@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.
- package/build/index.d.ts +5 -4
- package/build/index.d.ts.map +1 -1
- package/build/index.js +4 -3
- package/build/index.js.map +1 -1
- package/build/model/types.d.ts +4 -10
- package/build/model/types.d.ts.map +1 -1
- package/build/model/types.js.map +1 -1
- package/build/model/useOverlay.d.ts +1 -3
- package/build/model/useOverlay.d.ts.map +1 -1
- package/build/model/useOverlay.js +0 -8
- package/build/model/useOverlay.js.map +1 -1
- package/build/model/useOverlayProvider.d.ts.map +1 -1
- package/build/model/useOverlayProvider.js +11 -38
- package/build/model/useOverlayProvider.js.map +1 -1
- package/build/model/utils.d.ts.map +1 -1
- package/build/model/utils.js.map +1 -1
- package/build/overlay/BottomSheetOverlay/index.d.ts +2 -1
- package/build/overlay/BottomSheetOverlay/index.d.ts.map +1 -1
- package/build/overlay/BottomSheetOverlay/index.js +144 -91
- package/build/overlay/BottomSheetOverlay/index.js.map +1 -1
- package/build/overlay/ZSPortal/index.d.ts +11 -0
- package/build/overlay/ZSPortal/index.d.ts.map +1 -0
- package/build/overlay/ZSPortal/index.js +49 -0
- package/build/overlay/ZSPortal/index.js.map +1 -0
- package/build/overlay/index.d.ts +2 -1
- package/build/overlay/index.d.ts.map +1 -1
- package/build/overlay/index.js +2 -1
- package/build/overlay/index.js.map +1 -1
- package/build/ui/ZSAboveKeyboard/index.d.ts +9 -0
- package/build/ui/ZSAboveKeyboard/index.d.ts.map +1 -0
- package/build/ui/ZSAboveKeyboard/index.js +56 -0
- package/build/ui/ZSAboveKeyboard/index.js.map +1 -0
- package/build/ui/ZSContainer/index.d.ts +16 -14
- package/build/ui/ZSContainer/index.d.ts.map +1 -1
- package/build/ui/ZSContainer/index.js +78 -40
- package/build/ui/ZSContainer/index.js.map +1 -1
- package/build/ui/ZSPressable/index.d.ts +2 -1
- package/build/ui/ZSPressable/index.d.ts.map +1 -1
- package/build/ui/ZSPressable/index.js +40 -16
- package/build/ui/ZSPressable/index.js.map +1 -1
- package/build/ui/ZSTextField/index.d.ts.map +1 -1
- package/build/ui/ZSTextField/index.js +127 -41
- package/build/ui/ZSTextField/index.js.map +1 -1
- package/build/ui/atoms/AnimatedWrapper.d.ts.map +1 -1
- package/build/ui/atoms/AnimatedWrapper.js +58 -16
- package/build/ui/atoms/AnimatedWrapper.js.map +1 -1
- package/package.json +1 -1
- package/build/overlay/AboveKeyboard/index.d.ts +0 -4
- package/build/overlay/AboveKeyboard/index.d.ts.map +0 -1
- package/build/overlay/AboveKeyboard/index.js +0 -41
- package/build/overlay/AboveKeyboard/index.js.map +0 -1
- package/build/ui/ZSContainer/ui/VariantView.d.ts +0 -17
- package/build/ui/ZSContainer/ui/VariantView.d.ts.map +0 -1
- package/build/ui/ZSContainer/ui/VariantView.js +0 -13
- package/build/ui/ZSContainer/ui/VariantView.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useEffect, useState, useRef } from 'react';
|
|
1
|
+
import React, { useEffect, useState, useRef, useCallback, useMemo } from 'react';
|
|
2
2
|
import { StyleSheet, View, PanResponder, Keyboard, Platform } from 'react-native';
|
|
3
3
|
import { useBottomSheet } from '../../model/useOverlay';
|
|
4
4
|
import Animated, { useAnimatedStyle, useSharedValue, withSpring, withTiming } from 'react-native-reanimated';
|
|
@@ -6,53 +6,82 @@ import ModalBackground from '../ui/ModalBackground';
|
|
|
6
6
|
import { useTheme } from '../../model';
|
|
7
7
|
import { useSafeAreaInsets, initialWindowMetrics } from 'react-native-safe-area-context';
|
|
8
8
|
import { MAX_OVERLAY_WIDTH, Z_INDEX_VALUE } from '../../model/utils';
|
|
9
|
+
const IS_IOS = Platform.OS === 'ios';
|
|
10
|
+
const keyboardEvents = ({
|
|
11
|
+
showEvent: IS_IOS ? 'keyboardWillShow' : 'keyboardDidShow',
|
|
12
|
+
hideEvent: IS_IOS ? 'keyboardWillHide' : 'keyboardDidHide',
|
|
13
|
+
});
|
|
14
|
+
const ANIMATION_CONFIG = {
|
|
15
|
+
keyboard: {
|
|
16
|
+
show: { duration: IS_IOS ? 250 : 300 },
|
|
17
|
+
hide: { duration: IS_IOS ? 150 : 200 },
|
|
18
|
+
},
|
|
19
|
+
spring: {
|
|
20
|
+
damping: 50,
|
|
21
|
+
stiffness: 300,
|
|
22
|
+
mass: 0.7,
|
|
23
|
+
velocity: 100,
|
|
24
|
+
restDisplacementThreshold: 0.2,
|
|
25
|
+
},
|
|
26
|
+
close: { duration: 150 },
|
|
27
|
+
scale: { duration: 200 },
|
|
28
|
+
scaleRestore: {
|
|
29
|
+
damping: 15,
|
|
30
|
+
stiffness: 300,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
const GESTURE_CONSTANTS = {
|
|
34
|
+
scaleAmount: 0.985,
|
|
35
|
+
horizontalDamping: 18,
|
|
36
|
+
verticalUpDamping: 18,
|
|
37
|
+
verticalDownDamping: 1.5,
|
|
38
|
+
closeVelocityThreshold: 0.5,
|
|
39
|
+
closeDistanceRatio: 1 / 3,
|
|
40
|
+
hideDelay: 200,
|
|
41
|
+
};
|
|
9
42
|
function BottomSheetOverlay({ headerComponent, component, options = {}, }) {
|
|
10
43
|
const { isBackgroundTouchClose = true, marginHorizontal = 10, marginBottom = 10, padding = 14, } = options;
|
|
11
44
|
const { palette, dimensions: { width: windowWidth, height: windowHeight } } = useTheme();
|
|
12
45
|
const { bottomSheetVisible, setBottomSheetVisible, height } = useBottomSheet();
|
|
13
|
-
// 화면의 크기보다 높이가 높으면 화면의 크기로 제한
|
|
14
|
-
const maxHeight = Math.min((windowHeight - 30 - (initialWindowMetrics?.insets.bottom || 0) - (initialWindowMetrics?.insets.top || 0)), height);
|
|
15
|
-
const translateY = useSharedValue(maxHeight);
|
|
16
|
-
const translateX = useSharedValue(0);
|
|
17
|
-
const scale = useSharedValue(1);
|
|
18
46
|
const { bottom } = useSafeAreaInsets();
|
|
47
|
+
// 화면의 크기보다 높이가 높으면 화면의 크기로 제한
|
|
48
|
+
const maxHeight = useMemo(() => Math.min(windowHeight - 30 - (initialWindowMetrics?.insets.bottom || 0) - (initialWindowMetrics?.insets.top || 0), height), [windowHeight, height]);
|
|
49
|
+
const translateY = useRef(useSharedValue(0)).current;
|
|
50
|
+
const translateX = useRef(useSharedValue(0)).current;
|
|
51
|
+
const scale = useRef(useSharedValue(1)).current;
|
|
19
52
|
const startX = useRef(0);
|
|
20
53
|
const startY = useRef(0);
|
|
21
54
|
const [localVisible, setLocalVisible] = useState(false);
|
|
22
|
-
|
|
55
|
+
const handleKeyboardShow = useCallback((event) => {
|
|
56
|
+
const targetY = IS_IOS ? (-event.endCoordinates.height + bottom) : 0;
|
|
57
|
+
translateY.value = withTiming(targetY, ANIMATION_CONFIG.keyboard.show);
|
|
58
|
+
}, [translateY, bottom]);
|
|
59
|
+
const handleKeyboardHide = useCallback(() => {
|
|
60
|
+
translateY.value = withTiming(0, ANIMATION_CONFIG.keyboard.hide);
|
|
61
|
+
}, [translateY]);
|
|
62
|
+
// 소프트 키보드 핸들링
|
|
23
63
|
useEffect(() => {
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const keyboardShowSubscription = Keyboard.addListener(showEvent, (event) => {
|
|
27
|
-
translateY.value = withTiming(Platform.OS === 'ios' ? (-event.endCoordinates.height + bottom) : 0, { duration: 300 });
|
|
28
|
-
});
|
|
29
|
-
const keyboardHideSubscription = Keyboard.addListener(hideEvent, () => {
|
|
30
|
-
translateY.value = withTiming(0, { duration: 200 });
|
|
31
|
-
});
|
|
64
|
+
const keyboardShowSubscription = Keyboard.addListener(keyboardEvents.showEvent, handleKeyboardShow);
|
|
65
|
+
const keyboardHideSubscription = Keyboard.addListener(keyboardEvents.hideEvent, handleKeyboardHide);
|
|
32
66
|
return () => {
|
|
33
67
|
keyboardShowSubscription.remove();
|
|
34
68
|
keyboardHideSubscription.remove();
|
|
35
69
|
};
|
|
36
|
-
}, []);
|
|
70
|
+
}, [keyboardEvents.showEvent, keyboardEvents.hideEvent, handleKeyboardShow, handleKeyboardHide]);
|
|
71
|
+
// BottomSheet 표시/숨김 애니메이션 처리
|
|
37
72
|
useEffect(() => {
|
|
38
73
|
if (bottomSheetVisible) {
|
|
39
74
|
Keyboard.dismiss();
|
|
40
75
|
setLocalVisible(true);
|
|
41
|
-
translateY.value = withSpring(0,
|
|
42
|
-
damping: 50,
|
|
43
|
-
stiffness: 300,
|
|
44
|
-
mass: 0.7,
|
|
45
|
-
velocity: 100,
|
|
46
|
-
restDisplacementThreshold: 0.2,
|
|
47
|
-
});
|
|
76
|
+
translateY.value = withSpring(0, ANIMATION_CONFIG.spring);
|
|
48
77
|
}
|
|
49
78
|
else {
|
|
50
|
-
translateY.value = withTiming(maxHeight + 100,
|
|
79
|
+
translateY.value = withTiming(maxHeight + 100, ANIMATION_CONFIG.close);
|
|
51
80
|
setTimeout(() => {
|
|
52
81
|
setLocalVisible(false);
|
|
53
|
-
},
|
|
82
|
+
}, GESTURE_CONSTANTS.hideDelay);
|
|
54
83
|
}
|
|
55
|
-
}, [bottomSheetVisible]);
|
|
84
|
+
}, [bottomSheetVisible, translateY, maxHeight]);
|
|
56
85
|
const animatedStyles = useAnimatedStyle(() => {
|
|
57
86
|
return {
|
|
58
87
|
transform: [
|
|
@@ -61,75 +90,91 @@ function BottomSheetOverlay({ headerComponent, component, options = {}, }) {
|
|
|
61
90
|
{ scale: scale.value }
|
|
62
91
|
],
|
|
63
92
|
};
|
|
64
|
-
});
|
|
65
|
-
const
|
|
93
|
+
}, []);
|
|
94
|
+
const handlePanResponderGrant = useCallback(() => {
|
|
95
|
+
Keyboard.dismiss();
|
|
96
|
+
startX.current = translateX.value;
|
|
97
|
+
startY.current = translateY.value;
|
|
98
|
+
scale.value = withTiming(GESTURE_CONSTANTS.scaleAmount, ANIMATION_CONFIG.scale);
|
|
99
|
+
}, [translateX, translateY, scale]);
|
|
100
|
+
const handlePanResponderMove = useCallback((_, gestureState) => {
|
|
101
|
+
const newTranslateX = (startX.current + gestureState.dx) / GESTURE_CONSTANTS.horizontalDamping;
|
|
102
|
+
translateX.value = newTranslateX;
|
|
103
|
+
const newTranslateY = startY.current + gestureState.dy;
|
|
104
|
+
if (newTranslateY < 0) {
|
|
105
|
+
translateY.value = newTranslateY / GESTURE_CONSTANTS.verticalUpDamping;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
translateY.value = newTranslateY / GESTURE_CONSTANTS.verticalDownDamping;
|
|
109
|
+
}
|
|
110
|
+
}, [translateX, translateY]);
|
|
111
|
+
const handlePanResponderRelease = useCallback((_, gestureState) => {
|
|
112
|
+
translateX.value = withTiming(0, { duration: 100 });
|
|
113
|
+
// 빠른 플리킹 제스처를 했을 때, 혹은 화면의 1/3 이상 내렸을 때, 닫기
|
|
114
|
+
const shouldClose = gestureState.vy > GESTURE_CONSTANTS.closeVelocityThreshold ||
|
|
115
|
+
translateY.value > maxHeight * GESTURE_CONSTANTS.closeDistanceRatio;
|
|
116
|
+
if (shouldClose) {
|
|
117
|
+
translateY.value = withTiming(maxHeight + 100, ANIMATION_CONFIG.close);
|
|
118
|
+
setBottomSheetVisible(false);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
translateY.value = withTiming(0, ANIMATION_CONFIG.close);
|
|
122
|
+
}
|
|
123
|
+
// 사이즈 원래대로 복귀
|
|
124
|
+
scale.value = withSpring(1, ANIMATION_CONFIG.scaleRestore);
|
|
125
|
+
}, [translateX, translateY, scale, maxHeight, setBottomSheetVisible]);
|
|
126
|
+
const panResponder = useMemo(() => PanResponder.create({
|
|
66
127
|
onStartShouldSetPanResponder: () => true,
|
|
67
128
|
onMoveShouldSetPanResponder: () => true,
|
|
68
|
-
onPanResponderGrant:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
129
|
+
onPanResponderGrant: handlePanResponderGrant,
|
|
130
|
+
onPanResponderMove: handlePanResponderMove,
|
|
131
|
+
onPanResponderRelease: handlePanResponderRelease,
|
|
132
|
+
}), [handlePanResponderGrant, handlePanResponderMove, handlePanResponderRelease]);
|
|
133
|
+
// 배경 터치 핸들러
|
|
134
|
+
const handleBackgroundPress = useCallback(() => {
|
|
135
|
+
if (isBackgroundTouchClose)
|
|
136
|
+
setBottomSheetVisible(false);
|
|
137
|
+
}, [isBackgroundTouchClose, setBottomSheetVisible]);
|
|
138
|
+
const containerStyle = useMemo(() => [
|
|
139
|
+
styles.container,
|
|
140
|
+
{
|
|
141
|
+
width: windowWidth - marginHorizontal * 2,
|
|
142
|
+
height: maxHeight,
|
|
143
|
+
marginHorizontal,
|
|
144
|
+
bottom: marginBottom + bottom,
|
|
145
|
+
backgroundColor: palette.background.base,
|
|
73
146
|
},
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
damping: 15,
|
|
98
|
-
stiffness: 300
|
|
99
|
-
});
|
|
100
|
-
},
|
|
101
|
-
})).current;
|
|
102
|
-
return (!localVisible ? null :
|
|
103
|
-
<ModalBackground zIndex={Z_INDEX_VALUE.BOTTOM_SHEET1} key={localVisible ? 'visiblebs' : 'hiddenbs'} modalBgColor={palette.modalBgColor} onPress={() => {
|
|
104
|
-
if (isBackgroundTouchClose)
|
|
105
|
-
setBottomSheetVisible(false);
|
|
106
|
-
}}>
|
|
107
|
-
<Animated.View style={[
|
|
108
|
-
styles.container,
|
|
109
|
-
{
|
|
110
|
-
width: windowWidth - marginHorizontal * 2,
|
|
111
|
-
height: maxHeight,
|
|
112
|
-
marginHorizontal,
|
|
113
|
-
bottom: marginBottom + bottom,
|
|
114
|
-
backgroundColor: palette.background.base,
|
|
115
|
-
},
|
|
116
|
-
animatedStyles,
|
|
117
|
-
]}>
|
|
118
|
-
<View style={[
|
|
119
|
-
styles.pressableView,
|
|
120
|
-
{ paddingHorizontal: padding, paddingBottom: padding },
|
|
121
|
-
]}>
|
|
122
|
-
<View {...panResponder.panHandlers}>
|
|
123
|
-
<View style={[styles.gestureBarContainer, { paddingBottom: padding }]}>
|
|
124
|
-
<View style={[styles.gestureBar, { backgroundColor: palette.divider }]}/>
|
|
125
|
-
</View>
|
|
126
|
-
{headerComponent}
|
|
147
|
+
animatedStyles,
|
|
148
|
+
], [windowWidth, marginHorizontal, maxHeight, marginBottom, bottom, palette.background.base, animatedStyles]);
|
|
149
|
+
const pressableViewStyle = useMemo(() => [
|
|
150
|
+
styles.pressableView,
|
|
151
|
+
{ paddingHorizontal: padding, paddingBottom: padding },
|
|
152
|
+
], [padding]);
|
|
153
|
+
const gestureBarContainerStyle = useMemo(() => [
|
|
154
|
+
styles.gestureBarContainer,
|
|
155
|
+
{ paddingBottom: padding }
|
|
156
|
+
], [padding]);
|
|
157
|
+
const gestureBarStyle = useMemo(() => [
|
|
158
|
+
styles.gestureBar,
|
|
159
|
+
{ backgroundColor: palette.divider }
|
|
160
|
+
], [palette.divider]);
|
|
161
|
+
if (!localVisible) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
return (<ModalBackground zIndex={Z_INDEX_VALUE.BOTTOM_SHEET1} key={localVisible ? 'visiblebs' : 'hiddenbs'} modalBgColor={palette.modalBgColor} onPress={handleBackgroundPress}>
|
|
165
|
+
<Animated.View style={containerStyle}>
|
|
166
|
+
<View style={pressableViewStyle}>
|
|
167
|
+
<View {...panResponder.panHandlers}>
|
|
168
|
+
<View style={gestureBarContainerStyle}>
|
|
169
|
+
<View style={gestureBarStyle}/>
|
|
127
170
|
</View>
|
|
128
|
-
|
|
129
|
-
{component}
|
|
171
|
+
{headerComponent}
|
|
130
172
|
</View>
|
|
131
|
-
|
|
132
|
-
|
|
173
|
+
|
|
174
|
+
{component}
|
|
175
|
+
</View>
|
|
176
|
+
</Animated.View>
|
|
177
|
+
</ModalBackground>);
|
|
133
178
|
}
|
|
134
179
|
const styles = StyleSheet.create({
|
|
135
180
|
container: {
|
|
@@ -155,5 +200,13 @@ const styles = StyleSheet.create({
|
|
|
155
200
|
borderRadius: 2,
|
|
156
201
|
},
|
|
157
202
|
});
|
|
158
|
-
|
|
203
|
+
const arePropsEqual = (prevProps, nextProps) => {
|
|
204
|
+
return (prevProps.headerComponent === nextProps.headerComponent &&
|
|
205
|
+
prevProps.component === nextProps.component &&
|
|
206
|
+
prevProps.options?.isBackgroundTouchClose === nextProps.options?.isBackgroundTouchClose &&
|
|
207
|
+
prevProps.options?.marginHorizontal === nextProps.options?.marginHorizontal &&
|
|
208
|
+
prevProps.options?.marginBottom === nextProps.options?.marginBottom &&
|
|
209
|
+
prevProps.options?.padding === nextProps.options?.padding);
|
|
210
|
+
};
|
|
211
|
+
export default React.memo(BottomSheetOverlay, arePropsEqual);
|
|
159
212
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/overlay/BottomSheetOverlay/index.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect, useState, useRef } from 'react';\nimport { StyleSheet, View, PanResponder, Keyboard, Platform } from 'react-native';\nimport { useBottomSheet } from '../../model/useOverlay';\nimport Animated, { useAnimatedStyle, useSharedValue, withSpring, withTiming } from 'react-native-reanimated';\nimport ModalBackground from '../ui/ModalBackground';\nimport { useTheme } from '../../model';\nimport { useSafeAreaInsets, initialWindowMetrics } from 'react-native-safe-area-context';\nimport { ShowBottomSheetProps } from '../../model/types';\nimport { MAX_OVERLAY_WIDTH, Z_INDEX_VALUE } from '../../model/utils';\n\nfunction BottomSheetOverlay({\n headerComponent,\n component,\n options = {},\n}: ShowBottomSheetProps) {\n const {\n isBackgroundTouchClose = true,\n marginHorizontal = 10,\n marginBottom = 10,\n padding = 14,\n } = options;\n const { palette, dimensions: { width: windowWidth, height: windowHeight } } = useTheme();\n const { bottomSheetVisible, setBottomSheetVisible, height } = useBottomSheet();\n // 화면의 크기보다 높이가 높으면 화면의 크기로 제한\n const maxHeight = Math.min((windowHeight - 30 - (initialWindowMetrics?.insets.bottom || 0) - (initialWindowMetrics?.insets.top || 0)), height);\n const translateY = useSharedValue(maxHeight);\n const translateX = useSharedValue(0);\n const scale = useSharedValue(1);\n const { bottom } = useSafeAreaInsets();\n const startX = useRef(0);\n const startY = useRef(0);\n const [localVisible, setLocalVisible] = useState(false);\n\n // ** 소프트 키보드 핸들링\n useEffect(() => {\n const showEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';\n const hideEvent = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';\n\n const keyboardShowSubscription = Keyboard.addListener(showEvent, (event) => {\n translateY.value = withTiming(Platform.OS === 'ios' ? (-event.endCoordinates.height + bottom) : 0, { duration: 300 });\n });\n\n const keyboardHideSubscription = Keyboard.addListener(hideEvent, () => {\n translateY.value = withTiming(0, { duration: 200 });\n });\n\n return () => {\n keyboardShowSubscription.remove();\n keyboardHideSubscription.remove();\n };\n }, []);\n\n useEffect(() => {\n if (bottomSheetVisible) {\n Keyboard.dismiss();\n setLocalVisible(true);\n translateY.value = withSpring(0, {\n damping: 50,\n stiffness: 300,\n mass: 0.7,\n velocity: 100,\n restDisplacementThreshold: 0.2,\n });\n } else {\n translateY.value = withTiming(maxHeight + 100, { duration: 150 });\n setTimeout(() => {\n setLocalVisible(false);\n }, 200);\n }\n }, [bottomSheetVisible]);\n\n const animatedStyles = useAnimatedStyle(() => {\n return {\n transform: [\n { translateY: translateY.value },\n { translateX: translateX.value },\n { scale: scale.value }\n ],\n };\n });\n\n const panResponder = useRef(\n PanResponder.create({\n onStartShouldSetPanResponder: () => true,\n onMoveShouldSetPanResponder: () => true,\n onPanResponderGrant: () => {\n Keyboard.dismiss();\n startX.current = translateX.value;\n startY.current = translateY.value;\n scale.value = withTiming(0.985, { duration: 200 });\n\n },\n onPanResponderMove: (_, gestureState) => {\n const newTranslateX = (startX.current + gestureState.dx) / 18;\n translateX.value = newTranslateX;\n\n const newTranslateY = startY.current + gestureState.dy;\n if (newTranslateY < 0) {\n translateY.value = newTranslateY / 18;\n } else {\n translateY.value = newTranslateY / 1.5;\n }\n },\n onPanResponderRelease: (_, gestureState) => {\n translateX.value = withTiming(0, { duration: 100 });\n\n // 빠른 플리킹 제스처를 했을 때, 혹은 화면의 1/3 이상 내렸을 때, 닫기\n if (gestureState.vy > 0.5 || translateY.value > maxHeight / 3) {\n translateY.value = withTiming(maxHeight + 100, { duration: 150 });\n setBottomSheetVisible(false);\n } else {\n translateY.value = withTiming(0, { duration: 150 });\n }\n\n // 사이즈 원래대로 복귀\n scale.value = withSpring(1, {\n damping: 15,\n stiffness: 300\n });\n },\n })\n ).current;\n\n return (\n !localVisible ? null :\n <ModalBackground\n zIndex={Z_INDEX_VALUE.BOTTOM_SHEET1}\n key={localVisible ? 'visiblebs' : 'hiddenbs'}\n modalBgColor={palette.modalBgColor}\n onPress={() => {\n if (isBackgroundTouchClose) setBottomSheetVisible(false);\n }}\n >\n <Animated.View\n style={[\n styles.container,\n {\n width: windowWidth - marginHorizontal * 2,\n height: maxHeight,\n marginHorizontal,\n bottom: marginBottom + bottom,\n backgroundColor: palette.background.base,\n },\n animatedStyles,\n ]}\n >\n <View\n style={[\n styles.pressableView,\n { paddingHorizontal: padding, paddingBottom: padding },\n ]}\n >\n <View {...panResponder.panHandlers}>\n <View style={[styles.gestureBarContainer, { paddingBottom: padding }]}>\n <View style={[styles.gestureBar, { backgroundColor: palette.divider }]} />\n </View>\n {headerComponent}\n </View>\n\n {component}\n </View>\n </Animated.View>\n </ModalBackground>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n position: 'absolute',\n borderRadius: 26,\n overflow: 'hidden',\n zIndex: Z_INDEX_VALUE.BOTTOM_SHEET2,\n maxWidth: MAX_OVERLAY_WIDTH,\n },\n pressableView: {\n width: '100%',\n height: '100%',\n },\n gestureBarContainer: {\n width: '100%',\n paddingTop: 10,\n justifyContent: 'center',\n alignItems: 'center',\n },\n gestureBar: {\n width: 45,\n height: 3,\n borderRadius: 2,\n },\n});\n\nexport default BottomSheetOverlay;"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/overlay/BottomSheetOverlay/index.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect, useState, useRef, useCallback, useMemo } from 'react';\nimport { StyleSheet, View, PanResponder, Keyboard, Platform } from 'react-native';\nimport { useBottomSheet } from '../../model/useOverlay';\nimport Animated, { useAnimatedStyle, useSharedValue, withSpring, withTiming } from 'react-native-reanimated';\nimport ModalBackground from '../ui/ModalBackground';\nimport { useTheme } from '../../model';\nimport { useSafeAreaInsets, initialWindowMetrics } from 'react-native-safe-area-context';\nimport { ShowBottomSheetProps } from '../../model/types';\nimport { MAX_OVERLAY_WIDTH, Z_INDEX_VALUE } from '../../model/utils';\n\nconst IS_IOS = Platform.OS === 'ios';\n\nconst keyboardEvents = ({\n showEvent: IS_IOS ? 'keyboardWillShow' as const : 'keyboardDidShow' as const,\n hideEvent: IS_IOS ? 'keyboardWillHide' as const : 'keyboardDidHide' as const,\n});\n\nconst ANIMATION_CONFIG = {\n keyboard: {\n show: { duration: IS_IOS ? 250 : 300 },\n hide: { duration: IS_IOS ? 150 : 200 },\n },\n spring: {\n damping: 50,\n stiffness: 300,\n mass: 0.7,\n velocity: 100,\n restDisplacementThreshold: 0.2,\n },\n close: { duration: 150 },\n scale: { duration: 200 },\n scaleRestore: {\n damping: 15,\n stiffness: 300,\n },\n} as const;\n\nconst GESTURE_CONSTANTS = {\n scaleAmount: 0.985,\n horizontalDamping: 18,\n verticalUpDamping: 18,\n verticalDownDamping: 1.5,\n closeVelocityThreshold: 0.5,\n closeDistanceRatio: 1 / 3,\n hideDelay: 200,\n} as const;\n\nfunction BottomSheetOverlay({\n headerComponent,\n component,\n options = {},\n}: ShowBottomSheetProps) {\n const {\n isBackgroundTouchClose = true,\n marginHorizontal = 10,\n marginBottom = 10,\n padding = 14,\n } = options;\n const { palette, dimensions: { width: windowWidth, height: windowHeight } } = useTheme();\n const { bottomSheetVisible, setBottomSheetVisible, height } = useBottomSheet();\n const { bottom } = useSafeAreaInsets();\n \n // 화면의 크기보다 높이가 높으면 화면의 크기로 제한 \n const maxHeight = useMemo(() => \n Math.min(\n windowHeight - 30 - (initialWindowMetrics?.insets.bottom || 0) - (initialWindowMetrics?.insets.top || 0),\n height\n ),\n [windowHeight, height]\n );\n \n const translateY = useRef(useSharedValue(0)).current;\n const translateX = useRef(useSharedValue(0)).current;\n const scale = useRef(useSharedValue(1)).current;\n \n const startX = useRef(0);\n const startY = useRef(0);\n const [localVisible, setLocalVisible] = useState(false);\n\n const handleKeyboardShow = useCallback((event: any) => {\n const targetY = IS_IOS ? (-event.endCoordinates.height + bottom) : 0;\n translateY.value = withTiming(targetY, ANIMATION_CONFIG.keyboard.show);\n }, [translateY, bottom]);\n\n const handleKeyboardHide = useCallback(() => {\n translateY.value = withTiming(0, ANIMATION_CONFIG.keyboard.hide);\n }, [translateY]);\n\n // 소프트 키보드 핸들링\n useEffect(() => {\n const keyboardShowSubscription = Keyboard.addListener(keyboardEvents.showEvent, handleKeyboardShow);\n const keyboardHideSubscription = Keyboard.addListener(keyboardEvents.hideEvent, handleKeyboardHide);\n\n return () => {\n keyboardShowSubscription.remove();\n keyboardHideSubscription.remove();\n };\n }, [keyboardEvents.showEvent, keyboardEvents.hideEvent, handleKeyboardShow, handleKeyboardHide]);\n\n // BottomSheet 표시/숨김 애니메이션 처리\n useEffect(() => {\n if (bottomSheetVisible) {\n Keyboard.dismiss();\n setLocalVisible(true);\n translateY.value = withSpring(0, ANIMATION_CONFIG.spring);\n } else {\n translateY.value = withTiming(maxHeight + 100, ANIMATION_CONFIG.close);\n setTimeout(() => {\n setLocalVisible(false);\n }, GESTURE_CONSTANTS.hideDelay);\n }\n }, [bottomSheetVisible, translateY, maxHeight]);\n\n const animatedStyles = useAnimatedStyle(() => {\n return {\n transform: [\n { translateY: translateY.value },\n { translateX: translateX.value },\n { scale: scale.value }\n ],\n };\n }, []);\n\n const handlePanResponderGrant = useCallback(() => {\n Keyboard.dismiss();\n startX.current = translateX.value;\n startY.current = translateY.value;\n scale.value = withTiming(GESTURE_CONSTANTS.scaleAmount, ANIMATION_CONFIG.scale);\n }, [translateX, translateY, scale]);\n\n const handlePanResponderMove = useCallback((_, gestureState) => {\n const newTranslateX = (startX.current + gestureState.dx) / GESTURE_CONSTANTS.horizontalDamping;\n translateX.value = newTranslateX;\n\n const newTranslateY = startY.current + gestureState.dy;\n if (newTranslateY < 0) {\n translateY.value = newTranslateY / GESTURE_CONSTANTS.verticalUpDamping;\n } else {\n translateY.value = newTranslateY / GESTURE_CONSTANTS.verticalDownDamping;\n }\n }, [translateX, translateY]);\n\n const handlePanResponderRelease = useCallback((_, gestureState) => {\n translateX.value = withTiming(0, { duration: 100 });\n\n // 빠른 플리킹 제스처를 했을 때, 혹은 화면의 1/3 이상 내렸을 때, 닫기\n const shouldClose = gestureState.vy > GESTURE_CONSTANTS.closeVelocityThreshold || \n translateY.value > maxHeight * GESTURE_CONSTANTS.closeDistanceRatio;\n \n if (shouldClose) {\n translateY.value = withTiming(maxHeight + 100, ANIMATION_CONFIG.close);\n setBottomSheetVisible(false);\n } else {\n translateY.value = withTiming(0, ANIMATION_CONFIG.close);\n }\n\n // 사이즈 원래대로 복귀\n scale.value = withSpring(1, ANIMATION_CONFIG.scaleRestore);\n }, [translateX, translateY, scale, maxHeight, setBottomSheetVisible]);\n\n const panResponder = useMemo(\n () => PanResponder.create({\n onStartShouldSetPanResponder: () => true,\n onMoveShouldSetPanResponder: () => true,\n onPanResponderGrant: handlePanResponderGrant,\n onPanResponderMove: handlePanResponderMove,\n onPanResponderRelease: handlePanResponderRelease,\n }),\n [handlePanResponderGrant, handlePanResponderMove, handlePanResponderRelease]\n );\n\n // 배경 터치 핸들러\n const handleBackgroundPress = useCallback(() => {\n if (isBackgroundTouchClose) setBottomSheetVisible(false);\n }, [isBackgroundTouchClose, setBottomSheetVisible]);\n\n const containerStyle = useMemo(() => [\n styles.container,\n {\n width: windowWidth - marginHorizontal * 2,\n height: maxHeight,\n marginHorizontal,\n bottom: marginBottom + bottom,\n backgroundColor: palette.background.base,\n },\n animatedStyles,\n ], [windowWidth, marginHorizontal, maxHeight, marginBottom, bottom, palette.background.base, animatedStyles]);\n\n const pressableViewStyle = useMemo(() => [\n styles.pressableView,\n { paddingHorizontal: padding, paddingBottom: padding },\n ], [padding]);\n\n const gestureBarContainerStyle = useMemo(() => [\n styles.gestureBarContainer,\n { paddingBottom: padding }\n ], [padding]);\n\n const gestureBarStyle = useMemo(() => [\n styles.gestureBar,\n { backgroundColor: palette.divider }\n ], [palette.divider]);\n\n if (!localVisible) {\n return null;\n }\n\n return (\n <ModalBackground\n zIndex={Z_INDEX_VALUE.BOTTOM_SHEET1}\n key={localVisible ? 'visiblebs' : 'hiddenbs'}\n modalBgColor={palette.modalBgColor}\n onPress={handleBackgroundPress}\n >\n <Animated.View style={containerStyle}>\n <View style={pressableViewStyle}>\n <View {...panResponder.panHandlers}>\n <View style={gestureBarContainerStyle}>\n <View style={gestureBarStyle} />\n </View>\n {headerComponent}\n </View>\n\n {component}\n </View>\n </Animated.View>\n </ModalBackground>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n position: 'absolute',\n borderRadius: 26,\n overflow: 'hidden',\n zIndex: Z_INDEX_VALUE.BOTTOM_SHEET2,\n maxWidth: MAX_OVERLAY_WIDTH,\n },\n pressableView: {\n width: '100%',\n height: '100%',\n },\n gestureBarContainer: {\n width: '100%',\n paddingTop: 10,\n justifyContent: 'center',\n alignItems: 'center',\n },\n gestureBar: {\n width: 45,\n height: 3,\n borderRadius: 2,\n },\n});\n\nconst arePropsEqual = (\n prevProps: ShowBottomSheetProps, \n nextProps: ShowBottomSheetProps\n): boolean => {\n return (\n prevProps.headerComponent === nextProps.headerComponent &&\n prevProps.component === nextProps.component &&\n prevProps.options?.isBackgroundTouchClose === nextProps.options?.isBackgroundTouchClose &&\n prevProps.options?.marginHorizontal === nextProps.options?.marginHorizontal &&\n prevProps.options?.marginBottom === nextProps.options?.marginBottom &&\n prevProps.options?.padding === nextProps.options?.padding\n );\n};\n\nexport default React.memo(BottomSheetOverlay, arePropsEqual);"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
interface PortalProviderProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
}
|
|
5
|
+
export declare const PortalProvider: React.FC<PortalProviderProps>;
|
|
6
|
+
interface PortalProps {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
export declare const ZSPortal: React.FC<PortalProps>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/overlay/ZSPortal/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAoD,SAAS,EAAa,MAAM,OAAO,CAAC;AAUtG,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAqCxD,CAAC;AAIF,UAAU,WAAW;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAe1C,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React, { createContext, useContext, useState, useCallback, useEffect } from 'react';
|
|
2
|
+
import Animated, { FadeInDown, FadeOutDown } from 'react-native-reanimated';
|
|
3
|
+
const PortalContext = createContext(null);
|
|
4
|
+
export const PortalProvider = ({ children }) => {
|
|
5
|
+
const [portals, setPortals] = useState(new Map());
|
|
6
|
+
const registerPortal = useCallback((id, element) => {
|
|
7
|
+
setPortals(prev => {
|
|
8
|
+
// 동일한 요소가 이미 등록되어 있다면 업데이트하지 않음
|
|
9
|
+
if (prev.get(id) === element) {
|
|
10
|
+
return prev;
|
|
11
|
+
}
|
|
12
|
+
const newMap = new Map(prev);
|
|
13
|
+
newMap.set(id, element);
|
|
14
|
+
return newMap;
|
|
15
|
+
});
|
|
16
|
+
}, []);
|
|
17
|
+
const unregisterPortal = useCallback((id) => {
|
|
18
|
+
setPortals(prev => {
|
|
19
|
+
// 해당 ID가 존재하지 않으면 상태를 변경하지 않음
|
|
20
|
+
if (!prev.has(id)) {
|
|
21
|
+
return prev;
|
|
22
|
+
}
|
|
23
|
+
const newMap = new Map(prev);
|
|
24
|
+
newMap.delete(id);
|
|
25
|
+
return newMap;
|
|
26
|
+
});
|
|
27
|
+
}, []);
|
|
28
|
+
return (<PortalContext.Provider value={{ registerPortal, unregisterPortal }}>
|
|
29
|
+
{children}
|
|
30
|
+
{Array.from(portals.entries()).map(([id, element]) => (<Animated.View entering={FadeInDown} exiting={FadeOutDown} key={id} style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, pointerEvents: 'box-none' }}>
|
|
31
|
+
{element}
|
|
32
|
+
</Animated.View>))}
|
|
33
|
+
</PortalContext.Provider>);
|
|
34
|
+
};
|
|
35
|
+
export const ZSPortal = ({ children }) => {
|
|
36
|
+
const context = useContext(PortalContext);
|
|
37
|
+
const [portalId] = useState(() => `portal_${Date.now()}_${Math.random()}`);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (context) {
|
|
40
|
+
context.registerPortal(portalId, children);
|
|
41
|
+
return () => {
|
|
42
|
+
context.unregisterPortal(portalId);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return () => { };
|
|
46
|
+
}, [children]);
|
|
47
|
+
return null;
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/overlay/ZSPortal/index.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { createContext, useContext, useState, useCallback, ReactNode, useEffect } from 'react';\nimport Animated, { FadeInDown, FadeOutDown } from 'react-native-reanimated';\n\ninterface PortalContextType {\n registerPortal: (id: string, element: ReactNode) => void;\n unregisterPortal: (id: string) => void;\n}\n\nconst PortalContext = createContext<PortalContextType | null>(null);\n\ninterface PortalProviderProps {\n children: ReactNode;\n}\n\nexport const PortalProvider: React.FC<PortalProviderProps> = ({ children }) => {\n const [portals, setPortals] = useState<Map<string, ReactNode>>(new Map());\n\n const registerPortal = useCallback((id: string, element: ReactNode) => {\n setPortals(prev => {\n // 동일한 요소가 이미 등록되어 있다면 업데이트하지 않음\n if (prev.get(id) === element) {\n return prev;\n }\n const newMap = new Map(prev);\n newMap.set(id, element);\n return newMap;\n });\n }, []);\n\n const unregisterPortal = useCallback((id: string) => {\n setPortals(prev => {\n // 해당 ID가 존재하지 않으면 상태를 변경하지 않음\n if (!prev.has(id)) {\n return prev;\n }\n const newMap = new Map(prev);\n newMap.delete(id);\n return newMap;\n });\n }, []);\n\n return (\n <PortalContext.Provider value={{ registerPortal, unregisterPortal }}>\n {children}\n {Array.from(portals.entries()).map(([id, element]) => (\n <Animated.View entering={FadeInDown} exiting={FadeOutDown} key={id} style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, pointerEvents: 'box-none' }}>\n {element}\n </Animated.View>\n ))}\n </PortalContext.Provider>\n );\n};\n\n// ------------------------------------------------------------------------------------------------\n\ninterface PortalProps {\n children: ReactNode;\n}\n\nexport const ZSPortal: React.FC<PortalProps> = ({ children }) => {\n const context = useContext(PortalContext);\n const [portalId] = useState(() => `portal_${Date.now()}_${Math.random()}`);\n\n useEffect(() => {\n if (context) {\n context.registerPortal(portalId, children);\n return () => {\n context.unregisterPortal(portalId);\n };\n }\n return () => {};\n }, [children]);\n\n return null;\n};\n"]}
|
package/build/overlay/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import * as useOverlayProvider from '../model/useOverlayProvider';
|
|
|
5
5
|
import { useOverlay } from '../model/useOverlay';
|
|
6
6
|
import PopOverButton from './PopOver/PopOverButton';
|
|
7
7
|
import PopOverMenu from './PopOver/PopOverMenu';
|
|
8
|
+
import { ZSPortal } from './ZSPortal';
|
|
8
9
|
import * as types from '../model/types';
|
|
9
|
-
export { AlertOverlay, BottomSheetOverlay, SnackbarNotify, useOverlayProvider, useOverlay, PopOverButton, PopOverMenu, types, };
|
|
10
|
+
export { AlertOverlay, BottomSheetOverlay, SnackbarNotify, useOverlayProvider, useOverlay, PopOverButton, PopOverMenu, ZSPortal, types, };
|
|
10
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/overlay/index.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAC1C,OAAO,kBAAkB,MAAM,sBAAsB,CAAC;AACtD,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,kBAAkB,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,aAAa,MAAM,yBAAyB,CAAC;AACpD,OAAO,WAAW,MAAM,uBAAuB,CAAC;AAChD,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAC;AAExC,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,WAAW,EACX,KAAK,GACN,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/overlay/index.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAC1C,OAAO,kBAAkB,MAAM,sBAAsB,CAAC;AACtD,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,kBAAkB,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,aAAa,MAAM,yBAAyB,CAAC;AACpD,OAAO,WAAW,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAC;AAExC,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,WAAW,EACX,QAAQ,EACR,KAAK,GACN,CAAA"}
|
package/build/overlay/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import * as useOverlayProvider from '../model/useOverlayProvider';
|
|
|
5
5
|
import { useOverlay } from '../model/useOverlay';
|
|
6
6
|
import PopOverButton from './PopOver/PopOverButton';
|
|
7
7
|
import PopOverMenu from './PopOver/PopOverMenu';
|
|
8
|
+
import { ZSPortal } from './ZSPortal';
|
|
8
9
|
import * as types from '../model/types';
|
|
9
|
-
export { AlertOverlay, BottomSheetOverlay, SnackbarNotify, useOverlayProvider, useOverlay, PopOverButton, PopOverMenu, types, };
|
|
10
|
+
export { AlertOverlay, BottomSheetOverlay, SnackbarNotify, useOverlayProvider, useOverlay, PopOverButton, PopOverMenu, ZSPortal, types, };
|
|
10
11
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/overlay/index.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAC1C,OAAO,kBAAkB,MAAM,sBAAsB,CAAC;AACtD,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,kBAAkB,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,aAAa,MAAM,yBAAyB,CAAC;AACpD,OAAO,WAAW,MAAM,uBAAuB,CAAC;AAChD,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAC;AAExC,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,WAAW,EACX,KAAK,GACN,CAAA","sourcesContent":["import AlertOverlay from './AlertOverlay';\nimport BottomSheetOverlay from './BottomSheetOverlay';\nimport SnackbarNotify from './SnackbarNotify';\nimport * as useOverlayProvider from '../model/useOverlayProvider';\nimport { useOverlay } from '../model/useOverlay';\nimport PopOverButton from './PopOver/PopOverButton';\nimport PopOverMenu from './PopOver/PopOverMenu';\nimport * as types from '../model/types';\n\nexport {\n AlertOverlay,\n BottomSheetOverlay,\n SnackbarNotify,\n useOverlayProvider,\n useOverlay,\n PopOverButton,\n PopOverMenu,\n types,\n}"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/overlay/index.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAC1C,OAAO,kBAAkB,MAAM,sBAAsB,CAAC;AACtD,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,kBAAkB,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,aAAa,MAAM,yBAAyB,CAAC;AACpD,OAAO,WAAW,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAC;AAExC,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,WAAW,EACX,QAAQ,EACR,KAAK,GACN,CAAA","sourcesContent":["import AlertOverlay from './AlertOverlay';\nimport BottomSheetOverlay from './BottomSheetOverlay';\nimport SnackbarNotify from './SnackbarNotify';\nimport * as useOverlayProvider from '../model/useOverlayProvider';\nimport { useOverlay } from '../model/useOverlay';\nimport PopOverButton from './PopOver/PopOverButton';\nimport PopOverMenu from './PopOver/PopOverMenu';\nimport { ZSPortal } from './ZSPortal';\nimport * as types from '../model/types';\n\nexport {\n AlertOverlay,\n BottomSheetOverlay,\n SnackbarNotify,\n useOverlayProvider,\n useOverlay,\n PopOverButton,\n PopOverMenu,\n ZSPortal,\n types,\n}"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
children: React.ReactNode;
|
|
3
|
+
keyboardShowOffset?: number;
|
|
4
|
+
keyboardHideOffset?: number;
|
|
5
|
+
handleLayoutHeight?: (height: number) => void;
|
|
6
|
+
}
|
|
7
|
+
declare function ZSAboveKeyboard({ keyboardShowOffset, keyboardHideOffset, children, handleLayoutHeight, }: Props): import("react").JSX.Element;
|
|
8
|
+
export default ZSAboveKeyboard;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/ZSAboveKeyboard/index.tsx"],"names":[],"mappings":"AAUA,UAAU,KAAK;IACb,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C;AAED,iBAAS,eAAe,CAAC,EACvB,kBAAsB,EACtB,kBAAsB,EACtB,QAAQ,EACR,kBAAkB,GACnB,EAAE,KAAK,+BA2CP;AAED,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { Keyboard, Platform, StyleSheet, Dimensions, View } from 'react-native';
|
|
3
|
+
import { Z_INDEX_VALUE } from '../../model/utils';
|
|
4
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
5
|
+
import { ZSPortal } from '../../overlay';
|
|
6
|
+
const windowHeight = Dimensions.get('window').height;
|
|
7
|
+
const showEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';
|
|
8
|
+
const hideEvent = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';
|
|
9
|
+
function ZSAboveKeyboard({ keyboardShowOffset = 0, keyboardHideOffset = 0, children, handleLayoutHeight, }) {
|
|
10
|
+
const [topValue, setTopValue] = useState(0);
|
|
11
|
+
const [isKeyboardVisible, setIsKeyboardVisible] = useState(false);
|
|
12
|
+
const [componentHeight, setComponentHeight] = useState(0);
|
|
13
|
+
const { bottom } = useSafeAreaInsets();
|
|
14
|
+
// const statusBarHeight = StatusBar.currentHeight || 0;
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const keyboardShowSubscription = Keyboard.addListener(showEvent, (event) => {
|
|
17
|
+
// 키보드 바로 위에 위치하도록 계산
|
|
18
|
+
const topValue = windowHeight - event.endCoordinates.height - componentHeight - keyboardShowOffset - 0;
|
|
19
|
+
// 구형폰에서는 상태바 높이를 빼야함
|
|
20
|
+
// const topValue = windowHeight - event.endCoordinates.height - componentHeight - keyboardShowOffset - statusBarHeight;
|
|
21
|
+
setTopValue(topValue);
|
|
22
|
+
setIsKeyboardVisible(true);
|
|
23
|
+
});
|
|
24
|
+
const keyboardHideSubscription = Keyboard.addListener(hideEvent, () => {
|
|
25
|
+
setTopValue(0);
|
|
26
|
+
setIsKeyboardVisible(false);
|
|
27
|
+
});
|
|
28
|
+
return () => {
|
|
29
|
+
keyboardShowSubscription.remove();
|
|
30
|
+
keyboardHideSubscription.remove();
|
|
31
|
+
};
|
|
32
|
+
}, [componentHeight]);
|
|
33
|
+
const handleLayout = (event) => {
|
|
34
|
+
const { height } = event.nativeEvent.layout;
|
|
35
|
+
setComponentHeight(height);
|
|
36
|
+
handleLayoutHeight?.(height);
|
|
37
|
+
};
|
|
38
|
+
return (<ZSPortal>
|
|
39
|
+
<View style={[styles.container, isKeyboardVisible ? { top: topValue } : { bottom: keyboardHideOffset + bottom }]}>
|
|
40
|
+
<View onLayout={handleLayout}>
|
|
41
|
+
{children}
|
|
42
|
+
</View>
|
|
43
|
+
</View>
|
|
44
|
+
</ZSPortal>);
|
|
45
|
+
}
|
|
46
|
+
export default ZSAboveKeyboard;
|
|
47
|
+
const styles = StyleSheet.create({
|
|
48
|
+
container: {
|
|
49
|
+
position: 'absolute',
|
|
50
|
+
justifyContent: 'center',
|
|
51
|
+
alignItems: 'center',
|
|
52
|
+
zIndex: Z_INDEX_VALUE.ABOVE_KEYBOARD,
|
|
53
|
+
width: '100%',
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ui/ZSAboveKeyboard/index.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useState } from 'react';\nimport { Keyboard, Platform, StyleSheet, Dimensions, View, StatusBar, LayoutChangeEvent } from 'react-native';\nimport { Z_INDEX_VALUE } from '../../model/utils';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport { ZSPortal } from '../../overlay';\n\nconst windowHeight = Dimensions.get('window').height;\nconst showEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';\nconst hideEvent = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';\n\ninterface Props {\n children: React.ReactNode;\n keyboardShowOffset?: number;\n keyboardHideOffset?: number;\n handleLayoutHeight?: (height: number) => void;\n}\n\nfunction ZSAboveKeyboard({\n keyboardShowOffset = 0,\n keyboardHideOffset = 0,\n children,\n handleLayoutHeight,\n}: Props) {\n const [topValue, setTopValue] = useState(0);\n const [isKeyboardVisible, setIsKeyboardVisible] = useState(false);\n const [componentHeight, setComponentHeight] = useState(0);\n const { bottom } = useSafeAreaInsets();\n // const statusBarHeight = StatusBar.currentHeight || 0;\n\n useEffect(() => {\n const keyboardShowSubscription = Keyboard.addListener(showEvent, (event) => {\n // 키보드 바로 위에 위치하도록 계산\n const topValue = windowHeight - event.endCoordinates.height - componentHeight - keyboardShowOffset - 0;\n // 구형폰에서는 상태바 높이를 빼야함\n // const topValue = windowHeight - event.endCoordinates.height - componentHeight - keyboardShowOffset - statusBarHeight;\n setTopValue(topValue);\n setIsKeyboardVisible(true);\n });\n\n const keyboardHideSubscription = Keyboard.addListener(hideEvent, () => {\n setTopValue(0);\n setIsKeyboardVisible(false);\n });\n\n return () => {\n keyboardShowSubscription.remove();\n keyboardHideSubscription.remove();\n };\n }, [componentHeight]);\n\n const handleLayout = (event: LayoutChangeEvent) => {\n const { height } = event.nativeEvent.layout;\n setComponentHeight(height);\n handleLayoutHeight?.(height);\n };\n\n return (\n <ZSPortal>\n <View style={[styles.container, isKeyboardVisible ? { top: topValue } : { bottom: keyboardHideOffset + bottom }]}>\n <View onLayout={handleLayout}>\n {children}\n </View>\n </View>\n </ZSPortal>\n );\n}\n\nexport default ZSAboveKeyboard;\n\nconst styles = StyleSheet.create({\n container: {\n position: 'absolute',\n justifyContent: 'center',\n alignItems: 'center',\n zIndex: Z_INDEX_VALUE.ABOVE_KEYBOARD,\n width: '100%',\n },\n});\n"]}
|
|
@@ -14,9 +14,21 @@ export type ZSContainerProps = ViewProps & {
|
|
|
14
14
|
translucent?: boolean;
|
|
15
15
|
onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
16
16
|
scrollEventThrottle?: number;
|
|
17
|
+
scrollToFocusedInput?: boolean;
|
|
17
18
|
};
|
|
18
19
|
export type ZSContainerRef = ScrollView;
|
|
19
|
-
declare const
|
|
20
|
+
export declare const styles: {
|
|
21
|
+
flex1: {
|
|
22
|
+
flex: number;
|
|
23
|
+
width: "100%";
|
|
24
|
+
};
|
|
25
|
+
scrollContainerStyle: {
|
|
26
|
+
flexGrow: number;
|
|
27
|
+
alignItems: "center";
|
|
28
|
+
width: "100%";
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
declare const _default: React.MemoExoticComponent<React.ForwardRefExoticComponent<ViewProps & {
|
|
20
32
|
backgroundColor?: string;
|
|
21
33
|
statusBarColor?: string;
|
|
22
34
|
barStyle?: "light-content" | "dark-content";
|
|
@@ -30,17 +42,7 @@ declare const ZSContainer: React.ForwardRefExoticComponent<ViewProps & {
|
|
|
30
42
|
translucent?: boolean;
|
|
31
43
|
onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
32
44
|
scrollEventThrottle?: number;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
flex: number;
|
|
37
|
-
width: "100%";
|
|
38
|
-
};
|
|
39
|
-
scrollContainerStyle: {
|
|
40
|
-
flexGrow: number;
|
|
41
|
-
alignItems: "center";
|
|
42
|
-
width: "100%";
|
|
43
|
-
};
|
|
44
|
-
};
|
|
45
|
-
export default ZSContainer;
|
|
45
|
+
scrollToFocusedInput?: boolean;
|
|
46
|
+
} & React.RefAttributes<ScrollView>>>;
|
|
47
|
+
export default _default;
|
|
46
48
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/ZSContainer/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/ZSContainer/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAsF,MAAM,OAAO,CAAC;AAC7H,OAAO,EAAE,SAAS,EAAyB,UAAU,EAAE,oBAAoB,EAAE,iBAAiB,EAA4B,MAAM,cAAc,CAAC;AAW/I,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG;IACzC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,eAAe,GAAG,cAAc,CAAC;IAC5C,KAAK,CAAC,EAAE,KAAK,CAAC,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC,CAAC;IACnD,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,eAAe,CAAC,EAAE,SAAS,CAAC;IAC5B,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IACpE,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC;AAiJxC,eAAO,MAAM,MAAM;;;;;;;;;;CAGjB,CAAC;;sBApKiB,MAAM;qBACP,MAAM;eACZ,eAAe,GAAG,cAAc;YACnC,KAAK,CAAC,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;yBAC7B,OAAO;mBACb,SAAS;sBACN,SAAS;qBACV,SAAS;mCACK,OAAO;gCACV,MAAM;kBACpB,OAAO;eACV,CAAC,KAAK,EAAE,oBAAoB,CAAC,iBAAiB,CAAC,KAAK,IAAI;0BAC7C,MAAM;2BACL,OAAO;;AAkLhC,wBAAsD"}
|