Skip to content
34 changes: 23 additions & 11 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import { View, StyleSheet, Pressable, Text } from 'react-native';
import { StyleSheet, Pressable } from 'react-native';
import { TipKitInlineView, TipKitPopOverView } from 'react-native-tipkit';
import CloseIcon from './CloseIcon';
import Animated, { LinearTransition } from 'react-native-reanimated';
import { useCallback } from 'react';

const AnimatedPressable = Animated.createAnimatedComponent(Pressable);

export default function App() {
const onActionButtonPress = () => {
const onActionButtonPress = useCallback(() => {
console.log('Action button pressed');
};
}, []);

return (
<View style={styles.container}>
<Text style={styles.title}>TipKit Example</Text>
<Animated.View layout={LinearTransition} style={styles.container}>
<Animated.Text layout={LinearTransition} style={styles.title}>
TipKit Example
</Animated.Text>
<TipKitInlineView
visible={true}
tipContainer={styles.inline}
title="Set favorites"
description="Tap and hold a color to add it to your favorites"
Expand Down Expand Up @@ -53,14 +58,21 @@ export default function App() {
popoverButtonArrowDirection="bottom-end"
// Popover Button Props
popoverButton={
<Pressable style={styles.customPopoverButton} onPress={() => {}}>
<Text style={styles.customPopoverButtonText}>
<AnimatedPressable
layout={LinearTransition}
style={styles.customPopoverButton}
onPress={() => {}}
>
<Animated.Text
layout={LinearTransition}
style={styles.customPopoverButtonText}
>
Custom Popover button
</Text>
</Pressable>
</Animated.Text>
</AnimatedPressable>
}
/>
</View>
</Animated.View>
);
}

Expand Down
20 changes: 18 additions & 2 deletions src/TipKitInlineView/TipKitInlineView.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
import React from 'react';
import React, { useCallback } from 'react';
import BaseTipKit, { type BaseTipKitProps } from '../components/BaseTipKit';
import { StretchInY, StretchOutY } from 'react-native-reanimated';

interface TipKitInlineViewProps extends BaseTipKitProps {}

const TipKitInlineView: React.FC<TipKitInlineViewProps> = ({ ...rest }) => {
return <BaseTipKit popoverButtonArrowDirection={undefined} {...rest} />;
const [visible, setVisible] = React.useState(true);

const onDismiss = useCallback(() => {
setVisible(false);
}, []);

return (
<BaseTipKit
popoverButtonArrowDirection={undefined}
enteringAnimation={StretchInY}
exitingAnimation={StretchOutY}
visible={visible}
onDismiss={onDismiss}
{...rest}
/>
);
};

export default TipKitInlineView;
35 changes: 25 additions & 10 deletions src/TipKitPopOverView/TipKitPopOverView.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, {
Fragment,
useCallback,
useMemo,
useRef,
useState,
Expand All @@ -8,6 +9,11 @@ import React, {
} from 'react';
import BaseTipKit, { type BaseTipKitProps } from '../components/BaseTipKit';
import { Button, StyleSheet, View, type ButtonProps } from 'react-native';
import Animated, {
LinearTransition,
ZoomInEasyDown,
ZoomOutEasyDown,
} from 'react-native-reanimated';

export type TipKitPopOverArrowDirection =
| 'top-start'
Expand Down Expand Up @@ -42,11 +48,11 @@ const TipKitPopOverView: React.FC<TipKitPopOverViewProps> = ({
height: 0,
});

const measureButtonPosition = () => {
const measureButtonPosition = useCallback(() => {
buttonRef.current?.measure((_fx, _fy, width, height, px, py) => {
setButtonPosition({ x: px, y: py, width, height });
});
};
}, []);

const popoverStyle = useMemo(() => {
const { y, x, height } = buttonPosition;
Expand All @@ -58,19 +64,23 @@ const TipKitPopOverView: React.FC<TipKitPopOverViewProps> = ({
};
}, [buttonPosition, popoverButtonArrowDirection]);

const onDismiss = () => {
const onDismiss = useCallback(() => {
setVisible(false);
};
}, []);

const handlePopoverButtonPress = () => {
const handlePopoverButtonPress = useCallback(() => {
measureButtonPosition();
popoverButtonOnPress?.();
setVisible(true);
};
}, [popoverButtonOnPress, measureButtonPosition]);

return (
<Fragment>
<View ref={buttonRef} style={styles.buttonContainer}>
<Animated.View
ref={buttonRef}
layout={LinearTransition}
style={styles.buttonContainer}
>
{popoverButton ? (
React.cloneElement(popoverButton, {
onPress: () => {
Expand All @@ -86,16 +96,21 @@ const TipKitPopOverView: React.FC<TipKitPopOverViewProps> = ({
{...popoverButtonProps}
/>
)}
</View>
</Animated.View>
{visible && (
<View style={[styles.popoverContainer, popoverStyle]}>
<Animated.View
layout={LinearTransition}
style={[styles.popoverContainer, popoverStyle]}
>
<BaseTipKit
visible={true}
onDismiss={onDismiss}
popoverButtonArrowDirection={popoverButtonArrowDirection}
enteringAnimation={ZoomInEasyDown}
exitingAnimation={ZoomOutEasyDown}
{...rest}
/>
</View>
</Animated.View>
)}
</Fragment>
);
Expand Down
19 changes: 14 additions & 5 deletions src/components/BaseTipKit.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo, type FC } from 'react';
import React, { useCallback, useMemo, type FC } from 'react';
import {
Pressable,
StyleSheet,
Expand All @@ -10,6 +10,7 @@ import {
} from 'react-native';
import CloseIcon from './CloseIcon';
import type { TipKitPopOverArrowDirection } from '../TipKitPopOverView/TipKitPopOverView';
import Animated, { FadeIn, FadeOut } from 'react-native-reanimated';

export interface BaseTipKitProps {
// General Logic Props
Expand All @@ -33,6 +34,8 @@ export interface BaseTipKitProps {

// Styling Props
tipContainer?: ViewStyle;
enteringAnimation?: any;
exitingAnimation?: any;
}

const BaseTipKit: FC<BaseTipKitProps> = ({
Expand All @@ -48,10 +51,12 @@ const BaseTipKit: FC<BaseTipKitProps> = ({
actionButtonOnPress,
tipContainer,
popoverButtonArrowDirection,
enteringAnimation = FadeIn,
exitingAnimation = FadeOut,
}) => {
const onXPress = () => {
const onXPress = useCallback(() => {
onDismiss?.();
};
}, [onDismiss]);

const arrowStyle = useMemo(() => {
const isTop = popoverButtonArrowDirection?.includes('top');
Expand Down Expand Up @@ -84,7 +89,11 @@ const BaseTipKit: FC<BaseTipKitProps> = ({

return (
visible && (
<View>
<Animated.View
key={`tip-${title}`}
entering={enteringAnimation}
exiting={exitingAnimation}
>
{popoverButtonArrowDirection && (
<View style={[styles.arrow, { ...arrowStyle }]} />
)}
Expand All @@ -110,7 +119,7 @@ const BaseTipKit: FC<BaseTipKitProps> = ({
)}
</View>
</View>
</View>
</Animated.View>
)
);
};
Expand Down
Loading