Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/v1.0.2 #5

Merged
merged 4 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 26 additions & 112 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,39 @@
import { FlatList, SafeAreaView, StyleSheet, Text, View } from 'react-native';
import { SafeAreaView, StyleSheet, Text, View, TextInput } from 'react-native';
import Tooltip from 'react-native-good-tooltip';
import { useState } from 'react';

export default function App() {
const data = [
'In FlatList',
'zIndex must be specified using',
'CellRendererComponent.',
];
const [inputText, setInputText] = useState('초기 텍스트');

return (
<SafeAreaView style={styles.container}>
{/* Header*/}
<View
style={{

Check warning on line 12 in example/src/App.tsx

View workflow job for this annotation

GitHub Actions / lint

Inline style: { flexDirection: 'row', justifyContent: 'space-between', zIndex: 1 }
flexDirection: 'row',
justifyContent: 'space-between',
zIndex: 1,
}}
>
<Tooltip
isVisible={true}
text="This is a tooltip"
placement={'bottom'}
anchor={'left'}
requiredConfirmation
onPress={() => {}}
>
<View style={[styles.box, { backgroundColor: 'red' }]} />

Check warning on line 24 in example/src/App.tsx

View workflow job for this annotation

GitHub Actions / lint

Inline style: { backgroundColor: 'red' }
</Tooltip>

<Tooltip
isVisible={true}
text="This is a tooltip"
placement={'bottom'}
styles={{ color: 'black' }}

Check warning on line 30 in example/src/App.tsx

View workflow job for this annotation

GitHub Actions / lint

Inline style: { color: 'black' }
>
<View style={[styles.box, { backgroundColor: 'green' }]} />

Check warning on line 32 in example/src/App.tsx

View workflow job for this annotation

GitHub Actions / lint

Inline style: { backgroundColor: 'green' }
</Tooltip>

<Tooltip
isVisible={true}
text="This is a tooltip"
placement={'bottom'}
anchor={'right'}
requiredConfirmation
>
<Tooltip text="This is a tooltip" placement={'bottom'} anchor={'right'}>
<View style={[styles.box, { backgroundColor: 'blue' }]} />

Check warning on line 36 in example/src/App.tsx

View workflow job for this annotation

GitHub Actions / lint

Inline style: { backgroundColor: 'blue' }
</Tooltip>
</View>

Expand Down Expand Up @@ -77,103 +66,28 @@
</View>
</View>

{/* Body*/}
<FlatList
data={data}
// style={{ flexGrow: 1 }}
CellRendererComponent={({ index, style, ...props }) => {
return (
<View
style={[
style,
{
zIndex: data.length - index,
},
]}
{...props}
/>
);
}}
renderItem={({ item, index }) => (
<Tooltip
isVisible={true}
placement={'bottom'}
anchor={(() => {
if (index % 3 === 0) return 'right';
if (index % 2 === 0) return 'center';

return 'left';
})()}
text={'List Item Tooltip ' + index}
>
<View
style={{
paddingVertical: 15,
backgroundColor: 'blue',
opacity: 0.4,
justifyContent: 'center',
alignItems: 'flex-end',
paddingHorizontal: 16,
}}
>
<Text style={{ color: 'white' }}>{`${item}`}</Text>
</View>
</Tooltip>
)}
ListFooterComponent={() => (
<View
style={{
justifyContent: 'flex-end',
alignItems: 'center',
backgroundColor: '#8851bc',
height: 500,
}}
>
<Tooltip
placement={'top'}
anchor={'right'}
text={'Top RIght'}
isVisible={true}
requiredConfirmation
>
<View style={{ height: 50, backgroundColor: 'red', zIndex: 0 }}>
<Text>
There may be situations where you need to add the overflow:
'visible' style.
</Text>
</View>
</Tooltip>
<Tooltip placement={'bottom'} text={'Input Text'} visible={true}>
<TextInput
value={inputText}
placeholder={'Input text'}
onChangeText={setInputText}
style={{ padding: 16, backgroundColor: 'gray' }}
/>
</Tooltip>

<View style={{ zIndex: 0 }}>
<Tooltip
isVisible={true}
text="Left Tooltip"
placement={'left'}
anchor={'top'}
requiredConfirmation
>
<View style={[styles.box, { backgroundColor: 'red' }]} />
</Tooltip>
<Tooltip
isVisible={true}
text="Center Tooltip"
placement={'right'}
anchor={'center'}
>
<View style={[styles.box, { backgroundColor: 'green' }]} />
</Tooltip>
<Tooltip
isVisible={true}
text="Center Tooltip"
placement={'left'}
anchor={'bottom'}
>
<View style={[styles.box, { backgroundColor: 'blue' }]} />
</Tooltip>
</View>
</View>
)}
/>
{/*<FlatList*/}
{/* data={[1, 2, 3]}*/}
{/* renderItem={() => {*/}
{/* return (*/}
{/* <TextInput*/}
{/* value={inputText}*/}
{/* onChangeText={setInputText}*/}
{/* placeholder={'Input text'}*/}
{/* style={{ padding: 16, backgroundColor: 'gray' }}*/}
{/* />*/}
{/* );*/}
{/* }}*/}
{/*/>*/}
</SafeAreaView>
);
}
Expand Down
127 changes: 71 additions & 56 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import React, { useEffect, useState } from 'react';
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import {
Animated,
Dimensions,
Expand All @@ -25,6 +31,8 @@ const TOOLTIP_STYLE = {
};

interface ToolTipProps {
visible?: boolean;
rerenderKey?: any;
placement: 'top' | 'bottom' | 'left' | 'right';
anchor?: 'center' | 'left' | 'right' | 'top' | 'bottom';
offset?: {
Expand Down Expand Up @@ -53,17 +61,14 @@ interface ToolTipProps {
};
text: string | React.ReactElement;
children?: React.ReactElement;
isVisible: boolean;
onPress?: () => void;
onVisibleChange?: (isVisible: boolean) => void;
disableAutoHide?: boolean;
delayShowTime?: number;
autoHideTime?: number;
requiredConfirmation?: boolean;
}

const Tooltip = ({
isVisible,
visible,
anchor = 'center',
styles = {
tooltipStyle: TOOLTIP_STYLE,
Expand All @@ -77,58 +82,89 @@ const Tooltip = ({
offset,
arrowElement,
onVisibleChange,
disableAutoHide = false,
delayShowTime = 0,
autoHideTime = 5000,
requiredConfirmation = false,
}: ToolTipProps) => {
const [currentIsVisible, setCurrentIsVisible] = useState(false);
const showAnimationRef = useRef(false);
const hideAnimationRef = useRef(false);
const animatedValue = useMemo(() => new Animated.Value(0), []);

const [tooltipPosition, setTooltipPosition] = useState({
top: 0,
left: Platform.OS === 'android' && placement === 'right' ? -4 : 0,
});
const [tooltipSize, setTooltipSize] = useState({ width: 0, height: 0 });
const animatedValue = new Animated.Value(0);

const isVerticalPlacement = placement === 'top' || placement === 'bottom';
const tooltipColor = (() => {
if (styles?.color) return styles?.color;

return '#3Eb489';
})();

const arrowStyle = {
...createArrowShape(
styles?.arrowSize?.width || ARROW_SIZE.width,
styles?.arrowSize?.height || ARROW_SIZE.height
),
borderBottomColor: tooltipColor,
};
const transformsStyle = (() => {
const { x, y } = getAnchorPoint(placement, anchor);

useEffect(() => {
if (
autoHideTime > 0 &&
disableAutoHide === false &&
requiredConfirmation === false
) {
setTimeout(() => {
// 기본적으로 5초 뒤 사라짐 처리
setCurrentIsVisible(false);
}, autoHideTime);
}
}, [autoHideTime, disableAutoHide, requiredConfirmation]);
return withAnchorPoint(
{ transform: [{ scale: animatedValue }] },
{ x, y },
{ width: tooltipSize.width, height: tooltipSize.height }
);
})();

const runAnimation = useCallback(
(isShowAnimation: boolean) => {
if (isShowAnimation) {
if (showAnimationRef.current) return;

Animated.spring(animatedValue, {
toValue: 1,
speed: 6,
useNativeDriver: true,
}).start(() => {
onVisibleChange && onVisibleChange(true);
});
showAnimationRef.current = true;
} else {
if (hideAnimationRef.current) return;

Animated.timing(animatedValue, {
toValue: 0,
duration: 300,
useNativeDriver: true,
}).start(() => {
onVisibleChange && onVisibleChange(false);
});
hideAnimationRef.current = true;
}
},
[animatedValue, onVisibleChange]
);

// show animation
useEffect(() => {
if (onVisibleChange) {
onVisibleChange(isVisible);
if (visible !== undefined && !visible) {
return;
}
}, [isVisible, onVisibleChange]);

useEffect(() => {
setTimeout(() => {
setCurrentIsVisible(isVisible);
runAnimation(true);
}, delayShowTime);
}, [delayShowTime, isVisible]);
}, [delayShowTime, runAnimation, visible]);

// hide animation
useEffect(() => {
if (onPress) return;

setTimeout(() => {
runAnimation(false);
}, delayShowTime + autoHideTime);
}, [autoHideTime, delayShowTime, onPress, runAnimation]);

const handleVerticalTooltipLayout = (event: LayoutChangeEvent) => {
const { width, height } = event.nativeEvent.layout;
Expand Down Expand Up @@ -247,37 +283,16 @@ const Tooltip = ({
</View>
);

const transformsStyle = (() => {
const { x, y } = getAnchorPoint(placement, anchor);

if (currentIsVisible) {
Animated.spring(animatedValue, {
toValue: 1,
speed: 6,
useNativeDriver: true,
}).start();
} else {
animatedValue.setValue(1);
Animated.timing(animatedValue, {
toValue: 0,
duration: 300,
useNativeDriver: true,
}).start();
}

return withAnchorPoint(
{ transform: [{ scale: animatedValue }] },
{ x, y },
{ width: tooltipSize.width, height: tooltipSize.height }
);
})();

const renderTooltipContent = () => (
// View Overflow 영역에 있는 Tooltip을 선택하기 위해 TouchableOpacity 사용
<TouchableOpacity
activeOpacity={1}
onPress={() => {
setCurrentIsVisible((prevState) => !prevState);
if (!onPress) {
return;
}

runAnimation(false);
onPress && onPress();
}}
style={{
Expand All @@ -301,7 +316,7 @@ const Tooltip = ({
/>
)}

{requiredConfirmation && (
{onPress && (
<>
<View style={{ width: 8 }} />
<Image
Expand Down
Loading