diff --git a/package.json b/package.json
index 948b52b..8574255 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,8 @@
"release": "release-it",
"example": "yarn --cwd example",
"pods": "cd example && pod-install --quiet",
- "bootstrap": "yarn example && yarn && yarn pods"
+ "bootstrap": "yarn example && yarn && yarn pods",
+ "format": "prettier --write \"src/**/*.{js,jsx,json,md,ts,tsx}\""
},
"keywords": [
"react-native",
diff --git a/src/Backdrop/Backdrop.tsx b/src/Backdrop/Backdrop.tsx
index 43bc83c..7e1417f 100644
--- a/src/Backdrop/Backdrop.tsx
+++ b/src/Backdrop/Backdrop.tsx
@@ -6,7 +6,7 @@ import {
Pressable,
StyleSheet,
} from 'react-native';
-import { ANIMATION_DURATION } from '../constants';
+// import { ANIMATION_DURATION } from '../constants';
import type { BackdropProps } from './Backdrop.d';
// On iOS, Modal orientations need to be manually specified
@@ -34,7 +34,8 @@ export default function Backdrop({
if (visible) {
setDelayedVisible(true);
} else {
- setTimeout(() => setDelayedVisible(false), ANIMATION_DURATION);
+ setDelayedVisible(false);
+ // setTimeout(() => setDelayedVisible(false), ANIMATION_DURATION);
}
}, [visible]);
diff --git a/src/Caret.tsx b/src/Caret.tsx
index 23a328f..657007a 100644
--- a/src/Caret.tsx
+++ b/src/Caret.tsx
@@ -14,50 +14,76 @@ export type CaretProps = {
style?: ViewProps['style'];
};
-export default ({ align, backgroundColor, position, style }: CaretProps) => {
+export default function Caret({
+ align,
+ backgroundColor,
+ position,
+ style,
+}: CaretProps) {
return (
);
-};
+}
const styles = StyleSheet.create({
container: {
- width: CARET_SIDE_SIZE,
- height: CARET_SIDE_SIZE,
- backgroundColor: POPOVER_BACKGROUND_COLOR,
- transform: [{ rotate: '45deg' }],
- borderRadius: BORDER_RADIUS,
+ // borderColor: "transparent",
+ borderBottomColor: 'transparent',
+ borderLeftColor: 'transparent',
+ borderRightColor: 'transparent',
+ borderTopColor: 'transparent',
+ borderWidth: CARET_SIDE_SIZE,
+ height: CARET_SIDE_SIZE * 2,
+ width: CARET_SIDE_SIZE * 2,
},
- containerPositionTop: {
- marginTop: (CARET_SIDE_SIZE / 2 + BORDER_RADIUS / 2) * -1,
- marginBottom: CARET_SIDE_SIZE / 2 + BORDER_RADIUS / 2,
+ containerCenter: {
+ alignSelf: 'center',
},
+ containerLeft: {},
containerPositionBottom: {
+ bottom: CARET_SIDE_SIZE / 2,
marginBottom: (CARET_SIDE_SIZE / 2 + BORDER_RADIUS / 2) * -1,
marginTop: CARET_SIDE_SIZE / 2 + BORDER_RADIUS / 2,
},
containerPositionLeft: {
+ left: CARET_SIDE_SIZE / 2,
marginLeft: (CARET_SIDE_SIZE / 2 + BORDER_RADIUS / 2) * -1,
marginRight: CARET_SIDE_SIZE / 2 + BORDER_RADIUS / 2,
},
containerPositionRight: {
- marginRight: (CARET_SIDE_SIZE / 2 + BORDER_RADIUS / 2) * -1,
marginLeft: CARET_SIDE_SIZE / 2 + BORDER_RADIUS / 2,
+ marginRight: (CARET_SIDE_SIZE / 2 + BORDER_RADIUS / 2) * -1,
+ right: CARET_SIDE_SIZE / 2,
},
- containerCenter: {
- alignSelf: 'center',
+ containerPositionTop: {
+ marginBottom: CARET_SIDE_SIZE / 2 + BORDER_RADIUS / 2,
+ marginTop: (CARET_SIDE_SIZE / 2 + BORDER_RADIUS / 2) * -1,
+ top: CARET_SIDE_SIZE / 2,
},
containerRight: {
alignSelf: 'flex-end',
diff --git a/src/Popable.tsx b/src/Popable.tsx
index 75f214e..d2ed0ad 100644
--- a/src/Popable.tsx
+++ b/src/Popable.tsx
@@ -3,6 +3,7 @@ import React, {
useCallback,
useEffect,
useImperativeHandle,
+ useMemo,
useRef,
useState,
} from 'react';
@@ -26,6 +27,7 @@ export type PopableProps = {
backgroundColor?: PopoverProps['backgroundColor'];
caret?: PopoverProps['caret'];
caretPosition?: PopoverProps['caretPosition'];
+ caretStyle?: ViewProps['style'];
children: any;
content: PopoverProps['children'];
numberOfLines?: PopoverProps['numberOfLines'];
@@ -35,6 +37,10 @@ export type PopableProps = {
style?: PopoverProps['style'];
visible?: boolean;
wrapperStyle?: ViewProps['style'];
+ manualPopupPosition?: {
+ left: number;
+ top: number;
+ };
};
const DEFAULT_LAYOUT = {
@@ -53,6 +59,7 @@ const Popable = forwardRef(function Popable(
children,
caret,
caretPosition,
+ caretStyle,
content,
numberOfLines,
onAction,
@@ -61,6 +68,10 @@ const Popable = forwardRef(function Popable(
style,
visible,
wrapperStyle,
+ manualPopupPosition = {
+ left: 0,
+ top: 0,
+ },
},
ref
) {
@@ -75,12 +86,19 @@ const Popable = forwardRef(function Popable(
const [childrenLayout, setChildrenLayout] = useState(DEFAULT_LAYOUT);
const [computedPosition, setComputedPosition] = useState(position);
const isInteractive = typeof visible === 'undefined';
- const isPopoverVisible = isInteractive ? popoverVisible : visible;
+ const isPopoverVisible = useMemo(() => {
+ return isInteractive ? popoverVisible : visible;
+ }, [isInteractive, popoverVisible, visible]);
const childrenRef = useRef(null);
const popoverRef = useRef(null);
useImperativeHandle(ref, () => ({
- show: () => setPopoverVisible(true),
+ show: () => {
+ popoverRef.current?.measureInWindow((_x, _y, _width, _height) => {
+ setPopoverPagePosition({ left: _x, top: _y });
+ });
+ setPopoverVisible(true);
+ },
hide: () => setPopoverVisible(false),
}));
@@ -103,15 +121,15 @@ const Popable = forwardRef(function Popable(
) {
handlers.onPress = () => {
if (!visible) {
- popoverRef.current?.measure(
- (_x, _y, _width, _height, pageX, pageY) => {
- setPopoverPagePosition({ left: pageX, top: pageY });
- }
- );
+ popoverRef.current?.measureInWindow((_x, _y, _width, _height) => {
+ setPopoverPagePosition({ left: _x, top: _y });
+ });
}
onAction?.(!visible);
- setPopoverVisible(!visible);
+ if (!ref) {
+ setPopoverVisible(!visible);
+ }
};
} else {
handlers.onLongPress = () => {
@@ -197,6 +215,7 @@ const Popable = forwardRef(function Popable(
backgroundColor,
caret,
caretPosition,
+ caretStyle,
children: content,
numberOfLines,
position: computedPosition,
@@ -228,8 +247,14 @@ const Popable = forwardRef(function Popable(
{
position: 'absolute',
transform: [
- { translateX: popoverPagePosition.left },
- { translateY: popoverPagePosition.top },
+ {
+ translateX:
+ popoverPagePosition.left + manualPopupPosition.left,
+ },
+ {
+ translateY:
+ popoverPagePosition.top + manualPopupPosition.top,
+ },
],
},
style,
@@ -242,7 +267,11 @@ const Popable = forwardRef(function Popable(
{
+ setTimeout(() => {
+ handlePopoverLayout();
+ }, 100);
+ }}
visible={Platform.OS === 'web' ? isPopoverVisible : false}
style={[
computedPosition === 'top' && styles.popoverTop,
@@ -265,7 +294,11 @@ const Popable = forwardRef(function Popable(
{
+ setTimeout(() => {
+ handleChildrenLayout();
+ }, 100);
+ }}
{...handlers}
>
{children}
@@ -279,12 +312,12 @@ const styles = StyleSheet.create({
position: 'relative',
zIndex: 1,
},
- popoverTop: {
- bottom: '100%',
- },
popoverBottom: {
top: '100%',
},
+ popoverTop: {
+ bottom: '100%',
+ },
});
export default Popable;
diff --git a/src/Popover.tsx b/src/Popover.tsx
index 6b5833f..9bac359 100644
--- a/src/Popover.tsx
+++ b/src/Popover.tsx
@@ -17,6 +17,7 @@ export type PopoverProps = {
backgroundColor?: string;
caret?: boolean;
caretPosition?: 'left' | 'center' | 'right';
+ caretStyle?: ViewProps['style'];
children: string | React.ReactElement;
forceInitialAnimation?: boolean;
numberOfLines?: number;
@@ -31,6 +32,7 @@ const Popover = React.forwardRef(function Popover(
backgroundColor,
caret: withCaret = true,
caretPosition = 'center',
+ caretStyle = {},
children,
forceInitialAnimation = false,
numberOfLines,
@@ -50,41 +52,38 @@ const Popover = React.forwardRef(function Popover(
)
).current;
- useEffect(
- () => {
- let animation: Animated.CompositeAnimation | undefined;
+ useEffect(() => {
+ let animation: Animated.CompositeAnimation | undefined;
- if (animated) {
- if (visible && (!prevVisible.current || forceInitialAnimation)) {
- animation = Animated[animationType](opacity, {
- toValue: 1,
- duration: ANIMATION_DURATION,
- useNativeDriver: true,
- });
- } else if (!visible && (prevVisible.current || forceInitialAnimation)) {
- animation = Animated[animationType](opacity, {
- toValue: 0,
- duration: ANIMATION_DURATION,
- useNativeDriver: true,
- });
- }
-
- animation?.start();
+ if (animated) {
+ if (visible && (!prevVisible.current || forceInitialAnimation)) {
+ animation = Animated[animationType](opacity, {
+ toValue: 1,
+ duration: ANIMATION_DURATION,
+ useNativeDriver: true,
+ });
+ } else if (!visible && (prevVisible.current || forceInitialAnimation)) {
+ animation = Animated[animationType](opacity, {
+ toValue: 0,
+ duration: ANIMATION_DURATION,
+ useNativeDriver: true,
+ });
}
- prevVisible.current = visible;
+ animation?.start();
+ }
- return () => animation?.stop();
- },
- [visible] // eslint-disable-line react-hooks/exhaustive-deps
- );
+ prevVisible.current = visible;
+
+ return () => animation?.stop();
+ }, [visible]);
const caret = (
);
@@ -144,22 +143,22 @@ const Popover = React.forwardRef(function Popover(
});
const styles = StyleSheet.create({
+ caret: {
+ zIndex: 0,
+ },
container: {
- width: POPOVER_WIDTH,
overflow: 'hidden',
+ width: POPOVER_WIDTH,
},
containerHorizontal: {
flexDirection: 'row',
},
content: {
- flex: 1,
- zIndex: 1,
backgroundColor: POPOVER_BACKGROUND_COLOR,
borderRadius: BORDER_RADIUS * 2,
+ flex: 1,
overflow: 'hidden',
- },
- contentTextOnly: {
- padding: POPOVER_PADDING,
+ zIndex: 1,
},
contentText: {
color: POPOVER_FONT_COLOR,
@@ -167,8 +166,8 @@ const styles = StyleSheet.create({
fontWeight: 'bold',
textAlign: 'center',
},
- caret: {
- zIndex: 0,
+ contentTextOnly: {
+ padding: POPOVER_PADDING,
},
});