Skip to content

Commit

Permalink
Merge pull request #3 from WayneKim92/release/v1.0.0
Browse files Browse the repository at this point in the history
release/v1.0.0
  • Loading branch information
WayneKim92 authored Aug 25, 2024
2 parents a976a6f + 6b0fabb commit 66af1d2
Show file tree
Hide file tree
Showing 7 changed files with 712 additions and 23 deletions.
53 changes: 48 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# react-native-good-tooltip
# React Native Good Tooltip

This tooltip was created with the best UX in mind.
Tooltips do not interrupt the user's flow. I'm not positive about the flow of using the app after touching the tooltip to close it.
So this component doesn't use Modal.

## Installation

Expand All @@ -10,15 +11,57 @@ npm install react-native-good-tooltip

## Usage

**⚠️Warning⚠️️**
This component will need to be used with styles (z-Index and Overflow).
You will immediately see the need for zIndex if you use "bottom" placement.
Please refer to the example project and video.

```tsx
import Tooltip from 'react-native-good-tooltip';

```js
import { multiply } from 'react-native-good-tooltip';

// ...

const result = await multiply(3, 7);
<Tooltip
isVisible={true}
text="This is a tooltip"
placement={'bottom'}
anchor={'left'}
requiredConfirmation
>
{/* your component */}
</Tooltip>
```

## Video
<table>
<tr>
<td>
<video src="https://github.com/user-attachments/assets/b7c69e2f-ef99-476b-bca7-bd9bed3c65bf" width="300" height="600" />
</td>
</tr>
</table>

## Props


## Props
| Prop | Type | Default | Description |
|------------------------|----------------------------------------------------------------------|----------------------------------------|-----------------------------------------------------------------------------------------------|
| `placement` | `'top' \| 'bottom' \| 'left' \| 'right'` | **required** | The position of the tooltip relative to the anchor. |
| `anchor` | `'center' \| 'left' \| 'right' \| 'top' \| 'bottom'` | `'center'` | The alignment of the tooltip relative to the anchor. |
| `text` | `string \| React.ReactElement` | **required** | The content of the tooltip. |
| `isVisible` | `boolean` | **required** | Whether the tooltip is visible. |
| `offset` | `{ position?: { x?: number, y?: number }, arrow?: { x?: number, y?: number } }` | `undefined` | The offset for the tooltip and arrow position. |
| `arrowElement` | `React.ReactElement` | `undefined` | Custom arrow element. |
| `styles` | `{color?: ColorValue,containerStyle?: ViewStyle,tooltipStyle?: ViewStyle,arrowSize?: { width?: number, height?: number },closeSize?: { width?: number, height?: number} }` | `undefined` | Custom styles for the tooltip. |
| `children` | `React.ReactElement` | `undefined` | The element to which the tooltip is anchored. |
| `onPress` | `() => void` | `undefined` | Function to call when the tooltip is pressed. |
| `onVisibleChange` | `(isVisible: boolean) => void` | `undefined` | Function to call when the visibility of the tooltip changes. |
| `disableAutoHide` | `boolean` | `false` | Whether to disable the auto-hide feature. |
| `delayShowTime` | `number` | `0` | The delay time before showing the tooltip. |
| `autoHideTime` | `number` | `5000` | The time after which the tooltip will automatically hide. |
| `requiredConfirmation` | `boolean` | `false` | Whether the tooltip requires confirmation to hide. |

## Contributing

Expand Down
Binary file added assets/close.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
196 changes: 180 additions & 16 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,194 @@
import { useState, useEffect } from 'react';
import { StyleSheet, View, Text } from 'react-native';
import { multiply } from 'react-native-good-tooltip';
import { FlatList, SafeAreaView, StyleSheet, Text, View } from 'react-native';
import Tooltip from 'react-native-good-tooltip';

export default function App() {
const [result, setResult] = useState<number | undefined>();

useEffect(() => {
multiply(3, 7).then(setResult);
}, []);
const data = [
'In FlatList',
'zIndex must be specified using',
'CellRendererComponent.',
];

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

Check warning on line 15 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
>
<View style={[styles.box, { backgroundColor: 'red' }]} />

Check warning on line 28 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 35 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 37 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
>
<View style={[styles.box, { backgroundColor: 'blue' }]} />

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

View workflow job for this annotation

GitHub Actions / lint

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

<View
style={{
backgroundColor: 'yellow',
opacity: 0.9,
paddingTop: 40,
flexDirection: 'row',
zIndex: 0,
}}
>
<View
style={[{ backgroundColor: 'red', flexShrink: 1 }, styles.message]}
>
<Text style={{ flexShrink: 1, flexGrow: 1 }}>
This Tooltip component does not use modal, so you must specify
z-Index. Especially if the placement is bottom, you need to be
especially careful.
</Text>
</View>
<View
style={[{ backgroundColor: 'blue', flexShrink: 1 }, styles.message]}
>
<Text style={{ flexShrink: 1, flexGrow: 1 }}>
This Tooltip component does not use modal, so you must specify
z-Index. Especially if the placement is bottom, you need to be
especially careful.
</Text>
</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>

<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>
)}
/>
</SafeAreaView>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
marginVertical: 8,
marginHorizontal: 16,
},
box: {
width: 60,
height: 60,
marginVertical: 20,
width: 50,
height: 50,
},
message: {
padding: 8,
},
});
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"scripts": {
"example": "yarn workspace react-native-good-tooltip-example",
"test": "jest",
"postinstall": "npx patch-package",
"typecheck": "tsc",
"lint": "eslint \"**/*.{js,ts,tsx}\"",
"clean": "del-cli lib",
Expand Down Expand Up @@ -181,5 +182,8 @@
"create-react-native-library": {
"type": "library",
"version": "0.41.0"
},
"dependencies": {
"react-native-anchor-point": "^1.0.6"
}
}
15 changes: 15 additions & 0 deletions patches/react-native-anchor-point+1.0.6.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
diff --git a/node_modules/react-native-anchor-point/index.ts b/node_modules/react-native-anchor-point/index.ts
index f789fa7..a1a97c6 100644
--- a/node_modules/react-native-anchor-point/index.ts
+++ b/node_modules/react-native-anchor-point/index.ts
@@ -33,8 +33,10 @@ export const withAnchorPoint = (transform: TransformsStyle, anchorPoint: Point,
shiftTranslateX.push({
translateX: size.width * (anchorPoint.x - defaultAnchorPoint.x),
});
+ // @ts-ignore
injectedTransform = [...shiftTranslateX, ...injectedTransform];
// shift after rotation
+ // @ts-ignore
injectedTransform.push({
translateX: size.width * (defaultAnchorPoint.x - anchorPoint.x),
});
69 changes: 69 additions & 0 deletions src/functions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
export const getAnchorPoint = (placement: string, anchor: string) => {
let x = 0;
let y = 0;

// vertical
if (placement === 'top' && anchor === 'left') {
x = 0;
y = 1;
}
if (placement === 'top' && anchor === 'right') {
x = 1;
y = 1;
}
if (placement === 'top' && anchor === 'center') {
x = 0.5;
y = 1;
}

if (placement === 'bottom' && anchor === 'left') {
x = 0;
y = 0;
}
if (placement === 'bottom' && anchor === 'center') {
x = 0.5;
y = 0;
}
if (placement === 'bottom' && anchor === 'right') {
x = 1;
y = 0;
}

// horizontal
if (placement === 'left' && anchor === 'top') {
x = 1;
y = 0;
}
if (placement === 'left' && anchor === 'center') {
x = 1;
y = 0.5;
}
if (placement === 'left' && anchor === 'bottom') {
x = 1;
y = 1;
}
if (placement === 'right' && anchor === 'top') {
x = 0;
y = 0;
}
if (placement === 'right' && anchor === 'center') {
x = 0;
y = 0.5;
}
if (placement === 'right' && anchor === 'bottom') {
x = 0;
y = 1;
}

return { x, y };
};

export const createArrowShape = (width: number, height: number) => {
return {
borderLeftWidth: width / 2,
borderRightWidth: width / 2,
borderBottomWidth: height,
borderLeftColor: 'transparent',
borderRightColor: 'transparent',
};
};
Loading

0 comments on commit 66af1d2

Please sign in to comment.