react-native-hold-menu-actions 0.1.17 → 0.1.19

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.
Files changed (35) hide show
  1. package/lib/commonjs/components/backdrop/Backdrop.js +0 -1
  2. package/lib/commonjs/components/backdrop/Backdrop.js.map +1 -1
  3. package/lib/commonjs/components/customView/CustomView.js +52 -54
  4. package/lib/commonjs/components/customView/CustomView.js.map +1 -1
  5. package/lib/commonjs/components/holdItem/HoldItem.js +11 -5
  6. package/lib/commonjs/components/holdItem/HoldItem.js.map +1 -1
  7. package/lib/commonjs/components/menu/Menu.js +2 -5
  8. package/lib/commonjs/components/menu/Menu.js.map +1 -1
  9. package/lib/commonjs/components/provider/Provider.js +0 -1
  10. package/lib/commonjs/components/provider/Provider.js.map +1 -1
  11. package/lib/commonjs/utils/calculations.js +1 -48
  12. package/lib/commonjs/utils/calculations.js.map +1 -1
  13. package/lib/module/components/backdrop/Backdrop.js +0 -1
  14. package/lib/module/components/backdrop/Backdrop.js.map +1 -1
  15. package/lib/module/components/customView/CustomView.js +54 -54
  16. package/lib/module/components/customView/CustomView.js.map +1 -1
  17. package/lib/module/components/holdItem/HoldItem.js +12 -6
  18. package/lib/module/components/holdItem/HoldItem.js.map +1 -1
  19. package/lib/module/components/menu/Menu.js +3 -5
  20. package/lib/module/components/menu/Menu.js.map +1 -1
  21. package/lib/module/components/provider/Provider.js +0 -1
  22. package/lib/module/components/provider/Provider.js.map +1 -1
  23. package/lib/module/utils/calculations.js +0 -44
  24. package/lib/module/utils/calculations.js.map +1 -1
  25. package/lib/typescript/components/customView/CustomView.d.ts +1 -1
  26. package/lib/typescript/components/menu/types.d.ts +0 -1
  27. package/lib/typescript/utils/calculations.d.ts +0 -1
  28. package/package.json +1 -1
  29. package/src/components/backdrop/Backdrop.tsx +0 -1
  30. package/src/components/customView/CustomView.tsx +69 -64
  31. package/src/components/holdItem/HoldItem.tsx +12 -16
  32. package/src/components/menu/Menu.tsx +2 -13
  33. package/src/components/menu/types.d.ts +0 -1
  34. package/src/components/provider/Provider.tsx +7 -10
  35. package/src/utils/calculations.ts +0 -53
@@ -32,50 +32,6 @@ export const menuAnimationAnchor = (anchorPoint, itemWidth, itemLength, itemsWit
32
32
  }
33
33
  };
34
34
  };
35
- export const calculateDynamicTransformValue = (itemY, itemHeight, menuHeight, customViewHeight, anchorPosition, screenHeight, safeAreaTop, safeAreaBottom) => {
36
- 'worklet';
37
-
38
- const GAP = styleGuide.spacing;
39
- const isAnchorTop = anchorPosition.includes('top');
40
-
41
- if (isAnchorTop) {
42
- // Menu below item, custom view above item
43
- // Total space needed below item: itemHeight + gap + menuHeight + safeAreaBottom
44
- // Total space needed above item: customViewHeight + gap + safeAreaTop
45
- const bottomEdge = itemY + itemHeight + GAP + menuHeight + safeAreaBottom;
46
- const topEdge = itemY - GAP - customViewHeight - safeAreaTop;
47
- let tY = 0; // If bottom overflows screen
48
-
49
- if (bottomEdge > screenHeight) {
50
- tY = screenHeight - bottomEdge;
51
- } // After shifting, check if custom view goes above safe area
52
-
53
-
54
- if (topEdge + tY < 0) {
55
- tY = -topEdge;
56
- }
57
-
58
- return tY;
59
- } else {
60
- // Menu above item, custom view below item
61
- // Total space needed above item: menuHeight + gap + safeAreaTop
62
- // Total space needed below item: itemHeight + gap + customViewHeight + safeAreaBottom
63
- const topEdge = itemY - GAP - menuHeight - safeAreaTop;
64
- const bottomEdge = itemY + itemHeight + GAP + customViewHeight + safeAreaBottom;
65
- let tY = 0; // If top overflows screen (goes above safe area)
66
-
67
- if (topEdge < 0) {
68
- tY = -topEdge;
69
- } // After shifting, check if custom view goes below screen
70
-
71
-
72
- if (bottomEdge + tY > screenHeight) {
73
- tY = screenHeight - bottomEdge;
74
- }
75
-
76
- return tY;
77
- }
78
- };
79
35
  export const getTransformOrigin = (posX, itemWidth, windowWidth, bottom) => {
80
36
  'worklet';
81
37
 
@@ -1 +1 @@
1
- {"version":3,"sources":["calculations.ts"],"names":["styleGuide","MENU_WIDTH","MENU_TRANSFORM_ORIGIN_TOLERENCE","FONT_SCALE","MenuItemHeight","typography","callout","lineHeight","spacing","calculateMenuHeight","itemLength","separatorCount","menuAnimationAnchor","anchorPoint","itemWidth","itemsWithSeparatorLength","MenuHeight","splittetAnchorName","split","Center1","Center2","TyTop1","TyTop2","TxLeft1","TxLeft2","beginningTransformations","translateX","translateY","endingTransformations","calculateDynamicTransformValue","itemY","itemHeight","menuHeight","customViewHeight","anchorPosition","screenHeight","safeAreaTop","safeAreaBottom","GAP","isAnchorTop","includes","bottomEdge","topEdge","tY","getTransformOrigin","posX","windowWidth","bottom","distanceToLeft","Math","round","distanceToRight","position","majority","abs"],"mappings":"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","sourcesContent":["import styleGuide from '../styleGuide';\nimport {\n MENU_WIDTH,\n MENU_TRANSFORM_ORIGIN_TOLERENCE,\n FONT_SCALE,\n} from '../constants';\n\nexport const MenuItemHeight = () => {\n 'worklet';\n return (\n styleGuide.typography.callout.lineHeight * FONT_SCALE +\n styleGuide.spacing * 2.5\n );\n};\n\nexport const calculateMenuHeight = (\n itemLength: number,\n separatorCount: number\n) => {\n 'worklet';\n return (\n MenuItemHeight() * itemLength +\n (itemLength - 1) +\n separatorCount * styleGuide.spacing\n );\n};\n\nexport type TransformOriginAnchorPosition =\n | 'top-right'\n | 'top-left'\n | 'top-center'\n | 'bottom-right'\n | 'bottom-left'\n | 'bottom-center';\n\nexport const menuAnimationAnchor = (\n anchorPoint: TransformOriginAnchorPosition,\n itemWidth: number,\n itemLength: number,\n itemsWithSeparatorLength: number\n) => {\n 'worklet';\n const MenuHeight = calculateMenuHeight(itemLength, itemsWithSeparatorLength);\n const splittetAnchorName: string[] = anchorPoint.split('-');\n\n const Center1 = itemWidth;\n const Center2 = 0;\n\n const TyTop1 = -(MenuHeight / 2);\n const TyTop2 = MenuHeight / 2;\n\n const TxLeft1 = (MENU_WIDTH / 2) * -1;\n const TxLeft2 = (MENU_WIDTH / 2) * 1;\n\n return {\n beginningTransformations: {\n translateX:\n splittetAnchorName[1] === 'right'\n ? -TxLeft1\n : splittetAnchorName[1] === 'left'\n ? TxLeft1\n : Center1,\n translateY:\n splittetAnchorName[0] === 'top'\n ? TyTop1\n : splittetAnchorName[0] === 'bottom'\n ? TyTop1\n : Center2,\n },\n endingTransformations: {\n translateX:\n splittetAnchorName[1] === 'right'\n ? -TxLeft2\n : splittetAnchorName[1] === 'left'\n ? TxLeft2\n : Center2,\n translateY:\n splittetAnchorName[0] === 'top'\n ? TyTop2\n : splittetAnchorName[0] === 'bottom'\n ? -TyTop2\n : Center2,\n },\n };\n};\n\nexport const calculateDynamicTransformValue = (\n itemY: number,\n itemHeight: number,\n menuHeight: number,\n customViewHeight: number,\n anchorPosition: TransformOriginAnchorPosition,\n screenHeight: number,\n safeAreaTop: number,\n safeAreaBottom: number\n): number => {\n 'worklet';\n const GAP = styleGuide.spacing;\n const isAnchorTop = anchorPosition.includes('top');\n\n if (isAnchorTop) {\n // Menu below item, custom view above item\n // Total space needed below item: itemHeight + gap + menuHeight + safeAreaBottom\n // Total space needed above item: customViewHeight + gap + safeAreaTop\n const bottomEdge = itemY + itemHeight + GAP + menuHeight + safeAreaBottom;\n const topEdge = itemY - GAP - customViewHeight - safeAreaTop;\n\n let tY = 0;\n\n // If bottom overflows screen\n if (bottomEdge > screenHeight) {\n tY = screenHeight - bottomEdge;\n }\n // After shifting, check if custom view goes above safe area\n if (topEdge + tY < 0) {\n tY = -topEdge;\n }\n return tY;\n } else {\n // Menu above item, custom view below item\n // Total space needed above item: menuHeight + gap + safeAreaTop\n // Total space needed below item: itemHeight + gap + customViewHeight + safeAreaBottom\n const topEdge = itemY - GAP - menuHeight - safeAreaTop;\n const bottomEdge =\n itemY + itemHeight + GAP + customViewHeight + safeAreaBottom;\n\n let tY = 0;\n // If top overflows screen (goes above safe area)\n if (topEdge < 0) {\n tY = -topEdge;\n }\n // After shifting, check if custom view goes below screen\n if (bottomEdge + tY > screenHeight) {\n tY = screenHeight - bottomEdge;\n }\n return tY;\n }\n};\n\nexport const getTransformOrigin = (\n posX: number,\n itemWidth: number,\n windowWidth: number,\n bottom?: boolean\n): TransformOriginAnchorPosition => {\n 'worklet';\n const distanceToLeft = Math.round(posX + itemWidth / 2);\n const distanceToRight = Math.round(windowWidth - distanceToLeft);\n\n let position: TransformOriginAnchorPosition = bottom\n ? 'bottom-right'\n : 'top-right';\n\n const majority = Math.abs(distanceToLeft - distanceToRight);\n\n if (majority < MENU_TRANSFORM_ORIGIN_TOLERENCE) {\n position = bottom ? 'bottom-center' : 'top-center';\n } else if (distanceToLeft < distanceToRight) {\n position = bottom ? 'bottom-left' : 'top-left';\n }\n\n return position;\n};\n"]}
1
+ {"version":3,"sources":["calculations.ts"],"names":["styleGuide","MENU_WIDTH","MENU_TRANSFORM_ORIGIN_TOLERENCE","FONT_SCALE","MenuItemHeight","typography","callout","lineHeight","spacing","calculateMenuHeight","itemLength","separatorCount","menuAnimationAnchor","anchorPoint","itemWidth","itemsWithSeparatorLength","MenuHeight","splittetAnchorName","split","Center1","Center2","TyTop1","TyTop2","TxLeft1","TxLeft2","beginningTransformations","translateX","translateY","endingTransformations","getTransformOrigin","posX","windowWidth","bottom","distanceToLeft","Math","round","distanceToRight","position","majority","abs"],"mappings":"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","sourcesContent":["import styleGuide from '../styleGuide';\nimport {\n MENU_WIDTH,\n MENU_TRANSFORM_ORIGIN_TOLERENCE,\n FONT_SCALE,\n} from '../constants';\n\nexport const MenuItemHeight = () => {\n 'worklet';\n return (\n styleGuide.typography.callout.lineHeight * FONT_SCALE +\n styleGuide.spacing * 2.5\n );\n};\n\nexport const calculateMenuHeight = (\n itemLength: number,\n separatorCount: number\n) => {\n 'worklet';\n return (\n MenuItemHeight() * itemLength +\n (itemLength - 1) +\n separatorCount * styleGuide.spacing\n );\n};\n\nexport type TransformOriginAnchorPosition =\n | 'top-right'\n | 'top-left'\n | 'top-center'\n | 'bottom-right'\n | 'bottom-left'\n | 'bottom-center';\n\nexport const menuAnimationAnchor = (\n anchorPoint: TransformOriginAnchorPosition,\n itemWidth: number,\n itemLength: number,\n itemsWithSeparatorLength: number\n) => {\n 'worklet';\n const MenuHeight = calculateMenuHeight(itemLength, itemsWithSeparatorLength);\n const splittetAnchorName: string[] = anchorPoint.split('-');\n\n const Center1 = itemWidth;\n const Center2 = 0;\n\n const TyTop1 = -(MenuHeight / 2);\n const TyTop2 = MenuHeight / 2;\n\n const TxLeft1 = (MENU_WIDTH / 2) * -1;\n const TxLeft2 = (MENU_WIDTH / 2) * 1;\n\n return {\n beginningTransformations: {\n translateX:\n splittetAnchorName[1] === 'right'\n ? -TxLeft1\n : splittetAnchorName[1] === 'left'\n ? TxLeft1\n : Center1,\n translateY:\n splittetAnchorName[0] === 'top'\n ? TyTop1\n : splittetAnchorName[0] === 'bottom'\n ? TyTop1\n : Center2,\n },\n endingTransformations: {\n translateX:\n splittetAnchorName[1] === 'right'\n ? -TxLeft2\n : splittetAnchorName[1] === 'left'\n ? TxLeft2\n : Center2,\n translateY:\n splittetAnchorName[0] === 'top'\n ? TyTop2\n : splittetAnchorName[0] === 'bottom'\n ? -TyTop2\n : Center2,\n },\n };\n};\n\nexport const getTransformOrigin = (\n posX: number,\n itemWidth: number,\n windowWidth: number,\n bottom?: boolean\n): TransformOriginAnchorPosition => {\n 'worklet';\n const distanceToLeft = Math.round(posX + itemWidth / 2);\n const distanceToRight = Math.round(windowWidth - distanceToLeft);\n\n let position: TransformOriginAnchorPosition = bottom\n ? 'bottom-right'\n : 'top-right';\n\n const majority = Math.abs(distanceToLeft - distanceToRight);\n\n if (majority < MENU_TRANSFORM_ORIGIN_TOLERENCE) {\n position = bottom ? 'bottom-center' : 'top-center';\n } else if (distanceToLeft < distanceToRight) {\n position = bottom ? 'bottom-left' : 'top-left';\n }\n\n return position;\n};\n"]}
@@ -1,3 +1,3 @@
1
1
  import React from 'react';
2
- declare const CustomView: React.MemoExoticComponent<() => JSX.Element>;
2
+ declare const CustomView: React.MemoExoticComponent<() => JSX.Element | null>;
3
3
  export default CustomView;
@@ -28,7 +28,6 @@ export type MenuInternalProps = {
28
28
  anchorPosition: TransformOriginAnchorPosition;
29
29
  menuHeight: number;
30
30
  transformValue: number;
31
- customViewHeight: number;
32
31
  actionParams: {
33
32
  [name: string]: (string | number)[];
34
33
  };
@@ -11,5 +11,4 @@ export declare const menuAnimationAnchor: (anchorPoint: TransformOriginAnchorPos
11
11
  translateY: number;
12
12
  };
13
13
  };
14
- export declare const calculateDynamicTransformValue: (itemY: number, itemHeight: number, menuHeight: number, customViewHeight: number, anchorPosition: TransformOriginAnchorPosition, screenHeight: number, safeAreaTop: number, safeAreaBottom: number) => number;
15
14
  export declare const getTransformOrigin: (posX: number, itemWidth: number, windowWidth: number, bottom?: boolean | undefined) => TransformOriginAnchorPosition;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-hold-menu-actions",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "description": "A performant, easy to use hold to open context menu for React Native powered by Reanimated.",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -117,7 +117,6 @@ const BackdropComponent = () => {
117
117
  <AnimatedBlurView
118
118
  // @ts-ignore
119
119
  tint="default"
120
- blurType={'dark'}
121
120
  animatedProps={animatedContainerProps}
122
121
  style={[styles.container, animatedContainerStyle]}
123
122
  >
@@ -5,7 +5,7 @@ import Animated, {
5
5
  runOnJS,
6
6
  useAnimatedReaction,
7
7
  useAnimatedStyle,
8
- useSharedValue,
8
+ withDelay,
9
9
  withSpring,
10
10
  withTiming,
11
11
  } from 'react-native-reanimated';
@@ -17,45 +17,35 @@ import {
17
17
  SPRING_CONFIGURATION,
18
18
  SPRING_CONFIGURATION_MENU,
19
19
  WINDOW_WIDTH,
20
- WINDOW_HEIGHT,
21
20
  } from '../../constants';
22
21
  import { RenderCustomView } from '../menu/types';
23
- import { calculateDynamicTransformValue } from '../../utils/calculations';
24
-
25
- const SCREEN_PADDING = 16;
26
22
 
27
23
  const CustomViewComponent = () => {
28
- const { state, menuProps, customViewRef, safeAreaInsets } = useInternal();
24
+ const { state, menuProps, customViewRef } = useInternal();
29
25
 
30
26
  const [renderFn, setRenderFn] = useState<RenderCustomView | null>(null);
31
-
32
- const cvHeight = useSharedValue(0);
33
- const cvWidth = useSharedValue(0);
27
+ const [customViewHeight, setCustomViewHeight] = useState(0);
28
+ const [customViewWidth, setCustomViewWidth] = useState(0);
34
29
 
35
30
  const closeMenu = useCallback(() => {
36
31
  state.value = CONTEXT_MENU_STATE.END;
37
32
  }, [state]);
38
33
 
39
- const onLayout = useCallback(
40
- (event: LayoutChangeEvent) => {
41
- const { height, width } = event.nativeEvent.layout;
42
- cvHeight.value = height;
43
- cvWidth.value = width;
44
- menuProps.value = { ...menuProps.value, customViewHeight: height };
45
- },
46
- [menuProps, cvHeight, cvWidth]
47
- );
34
+ const onLayout = useCallback((event: LayoutChangeEvent) => {
35
+ const { height, width } = event.nativeEvent.layout;
36
+ setCustomViewHeight(height);
37
+ setCustomViewWidth(width);
38
+ }, []);
48
39
 
49
40
  const clearRenderFn = useCallback(() => {
50
41
  setRenderFn(null);
51
- cvHeight.value = 0;
52
- cvWidth.value = 0;
53
- menuProps.value = { ...menuProps.value, customViewHeight: 0 };
54
- }, [menuProps, cvHeight, cvWidth]);
42
+ setCustomViewHeight(0);
43
+ setCustomViewWidth(0);
44
+ }, []);
55
45
 
56
46
  const updateRenderFn = useCallback(
57
- (shouldShow: boolean) => {
58
- if (shouldShow && customViewRef.current) {
47
+ (hasCustomView: boolean) => {
48
+ if (hasCustomView && customViewRef.current) {
59
49
  setRenderFn(() => customViewRef.current);
60
50
  } else {
61
51
  setTimeout(clearRenderFn, HOLD_ITEM_TRANSFORM_DURATION);
@@ -79,71 +69,87 @@ const CustomViewComponent = () => {
79
69
  [state, menuProps]
80
70
  );
81
71
 
82
- const visibilityStyles = useAnimatedStyle(() => {
83
- const active =
84
- state.value === CONTEXT_MENU_STATE.ACTIVE &&
85
- menuProps.value.hasCustomView;
86
- return {
87
- opacity: withTiming(active ? 1 : 0, {
88
- duration: HOLD_ITEM_TRANSFORM_DURATION,
89
- }),
90
- transform: [
91
- {
92
- scale: active
93
- ? withSpring(1, SPRING_CONFIGURATION_MENU)
94
- : withTiming(0, { duration: HOLD_ITEM_TRANSFORM_DURATION }),
95
- },
96
- ],
97
- };
98
- });
99
-
100
72
  const wrapperStyles = useAnimatedStyle(() => {
101
73
  const anchorPositionVertical = menuProps.value.anchorPosition.split('-')[0];
102
74
  const isAbove = anchorPositionVertical === 'top';
103
75
 
76
+ // Fixed anchor point: top of the item
104
77
  const top = menuProps.value.itemY;
78
+
79
+ const SCREEN_PADDING = 16;
105
80
  const MAX_WIDTH = WINDOW_WIDTH - SCREEN_PADDING * 2;
106
81
 
82
+ // Start at item's left edge
107
83
  let left = menuProps.value.itemX;
108
- const w = cvWidth.value;
109
- if (w > 0 && left + w > WINDOW_WIDTH - SCREEN_PADDING) {
110
- left = Math.max(SCREEN_PADDING, WINDOW_WIDTH - w - SCREEN_PADDING);
84
+
85
+ // If the view overflows the right edge, shift left
86
+ if (
87
+ customViewWidth > 0 &&
88
+ left + customViewWidth > WINDOW_WIDTH - SCREEN_PADDING
89
+ ) {
90
+ left = Math.max(
91
+ SCREEN_PADDING,
92
+ WINDOW_WIDTH - customViewWidth - SCREEN_PADDING
93
+ );
111
94
  }
112
95
  if (left < SCREEN_PADDING) {
113
96
  left = SCREEN_PADDING;
114
97
  }
115
-
116
- const h = cvHeight.value;
117
- const tY = calculateDynamicTransformValue(
118
- menuProps.value.itemY,
119
- menuProps.value.itemHeight,
120
- menuProps.value.menuHeight,
121
- h,
122
- menuProps.value.anchorPosition,
123
- WINDOW_HEIGHT,
124
- safeAreaInsets?.top || 0,
125
- safeAreaInsets?.bottom || 0
98
+ const tY = menuProps.value.transformValue;
99
+
100
+ // Positional offset via translateY:
101
+ // above item: shift up by customViewHeight + gap
102
+ // below item: shift down by itemHeight + gap
103
+ const positionOffsetY = isAbove
104
+ ? -(customViewHeight + 8)
105
+ : menuProps.value.itemHeight + 8;
106
+
107
+ const scaleAnimation =
108
+ state.value === CONTEXT_MENU_STATE.ACTIVE
109
+ ? withDelay(150, withSpring(1, SPRING_CONFIGURATION_MENU))
110
+ : withTiming(0, { duration: HOLD_ITEM_TRANSFORM_DURATION });
111
+
112
+ const opacityAnimation = withDelay(
113
+ 150,
114
+ withTiming(state.value === CONTEXT_MENU_STATE.ACTIVE ? 1 : 0, {
115
+ duration: HOLD_ITEM_TRANSFORM_DURATION,
116
+ })
126
117
  );
127
118
 
128
- const positionOffsetY = isAbove ? -(h + 8) : menuProps.value.itemHeight + 8;
119
+ // Scale anchor: scale from the edge closest to the item
120
+ const scaleAnchorOffset = isAbove
121
+ ? customViewHeight / 2
122
+ : -(customViewHeight / 2);
129
123
 
130
124
  return {
131
125
  top,
132
126
  left,
133
127
  maxWidth: MAX_WIDTH,
128
+ opacity: opacityAnimation,
134
129
  transform: [
135
- { translateY: withSpring(tY, SPRING_CONFIGURATION) },
130
+ // 1. Transform value (screen boundary compensation)
131
+ {
132
+ translateY:
133
+ state.value === CONTEXT_MENU_STATE.ACTIVE
134
+ ? withSpring(tY, SPRING_CONFIGURATION)
135
+ : withTiming(0, { duration: HOLD_ITEM_TRANSFORM_DURATION }),
136
+ },
137
+ // 2. Position offset (animated when customViewHeight changes)
136
138
  { translateY: withSpring(positionOffsetY, SPRING_CONFIGURATION_MENU) },
139
+ // 3. Scale anchor: move to edge -> scale -> move back
140
+ { translateY: scaleAnchorOffset },
141
+ { scale: scaleAnimation },
142
+ { translateY: -scaleAnchorOffset },
137
143
  ],
138
144
  };
139
- });
145
+ }, [menuProps, customViewHeight, customViewWidth]);
146
+
147
+ if (!renderFn) return null;
140
148
 
141
149
  return (
142
150
  <Animated.View style={[styles.customViewWrapper, wrapperStyles]}>
143
- <Animated.View style={visibilityStyles}>
144
- <Animated.View onLayout={onLayout}>
145
- {renderFn?.({ closeMenu })}
146
- </Animated.View>
151
+ <Animated.View onLayout={onLayout}>
152
+ {renderFn({ closeMenu })}
147
153
  </Animated.View>
148
154
  </Animated.View>
149
155
  );
@@ -153,7 +159,6 @@ const styles = StyleSheet.create({
153
159
  customViewWrapper: {
154
160
  position: 'absolute',
155
161
  zIndex: 20,
156
- pointerEvents: 'box-none',
157
162
  },
158
163
  });
159
164
 
@@ -35,7 +35,6 @@ import {
35
35
  TransformOriginAnchorPosition,
36
36
  getTransformOrigin,
37
37
  calculateMenuHeight,
38
- calculateDynamicTransformValue,
39
38
  } from '../../utils/calculations';
40
39
  import {
41
40
  HOLD_ITEM_TRANSFORM_DURATION,
@@ -152,9 +151,18 @@ const HoldItemComponent = ({
152
151
  const calculateTransformValue = () => {
153
152
  'worklet';
154
153
 
155
- const height =
154
+ const screenH =
156
155
  deviceOrientation === 'portrait' ? WINDOW_HEIGHT : WINDOW_WIDTH;
157
156
 
157
+ const hasCustomView = !!renderCustomView;
158
+
159
+ // If custom view exists, center item on screen
160
+ if (hasCustomView && !disableMove) {
161
+ const itemCenterY = itemRectY.value + itemRectHeight.value / 2;
162
+ const screenCenterY = screenH / 2;
163
+ return screenCenterY - itemCenterY;
164
+ }
165
+
158
166
  const isAnchorPointTop = transformOrigin.value.includes('top');
159
167
 
160
168
  let tY = 0;
@@ -167,7 +175,7 @@ const HoldItemComponent = ({
167
175
  styleGuide.spacing +
168
176
  (safeAreaInsets?.bottom || 0);
169
177
 
170
- tY = topTransform > height ? height - topTransform : 0;
178
+ tY = topTransform > screenH ? screenH - topTransform : 0;
171
179
  } else {
172
180
  const bottomTransform =
173
181
  itemRectY.value - menuHeight - (safeAreaInsets?.top || 0);
@@ -196,7 +204,6 @@ const HoldItemComponent = ({
196
204
  menuHeight: menuHeight,
197
205
  items: items || [],
198
206
  transformValue: transformValue.value,
199
- customViewHeight: 0,
200
207
  actionParams: actionParams || {},
201
208
  hasCustomView: !!renderCustomView,
202
209
  };
@@ -334,18 +341,7 @@ const HoldItemComponent = ({
334
341
  const animateOpacity = () =>
335
342
  withDelay(HOLD_ITEM_TRANSFORM_DURATION, withTiming(0, { duration: 0 }));
336
343
 
337
- const screenH =
338
- deviceOrientation === 'portrait' ? WINDOW_HEIGHT : WINDOW_WIDTH;
339
- let tY = calculateDynamicTransformValue(
340
- itemRectY.value,
341
- itemRectHeight.value,
342
- menuHeight,
343
- menuProps.value.customViewHeight,
344
- transformOrigin.value,
345
- screenH,
346
- safeAreaInsets?.top || 0,
347
- safeAreaInsets?.bottom || 0
348
- );
344
+ let tY = calculateTransformValue();
349
345
  const transformAnimation = () =>
350
346
  disableMove
351
347
  ? 0
@@ -14,12 +14,10 @@ import {
14
14
  HOLD_ITEM_TRANSFORM_DURATION,
15
15
  CONTEXT_MENU_STATE,
16
16
  SPRING_CONFIGURATION,
17
- WINDOW_HEIGHT,
18
17
  } from '../../constants';
19
- import { calculateDynamicTransformValue } from '../../utils/calculations';
20
18
 
21
19
  const MenuComponent = () => {
22
- const { state, menuProps, safeAreaInsets } = useInternal();
20
+ const { state, menuProps } = useInternal();
23
21
 
24
22
  const wrapperStyles = useAnimatedStyle(() => {
25
23
  const anchorPositionVertical = menuProps.value.anchorPosition.split('-')[0];
@@ -30,16 +28,7 @@ const MenuComponent = () => {
30
28
  : menuProps.value.itemY - 8;
31
29
  const left = menuProps.value.itemX;
32
30
  const width = menuProps.value.itemWidth;
33
- const tY = calculateDynamicTransformValue(
34
- menuProps.value.itemY,
35
- menuProps.value.itemHeight,
36
- menuProps.value.menuHeight,
37
- menuProps.value.customViewHeight,
38
- menuProps.value.anchorPosition,
39
- WINDOW_HEIGHT,
40
- safeAreaInsets?.top || 0,
41
- safeAreaInsets?.bottom || 0
42
- );
31
+ const tY = menuProps.value.transformValue;
43
32
 
44
33
  return {
45
34
  top,
@@ -28,7 +28,6 @@ export type MenuInternalProps = {
28
28
  anchorPosition: TransformOriginAnchorPosition;
29
29
  menuHeight: number;
30
30
  transformValue: number;
31
- customViewHeight: number;
32
31
  actionParams: {
33
32
  [name: string]: (string | number)[];
34
33
  };
@@ -1,10 +1,6 @@
1
1
  import React, { memo, useEffect, useMemo, useRef } from 'react';
2
2
  import { PortalProvider } from '@gorhom/portal';
3
- import Animated, {
4
- useSharedValue,
5
- useAnimatedReaction,
6
- runOnJS,
7
- } from 'react-native-reanimated';
3
+ import Animated, { useSharedValue, useAnimatedReaction, runOnJS } from 'react-native-reanimated';
8
4
  import { GestureHandlerRootView } from 'react-native-gesture-handler';
9
5
 
10
6
  // Components
@@ -51,7 +47,6 @@ const ProviderComponent = ({
51
47
  anchorPosition: 'top-center',
52
48
  menuHeight: 0,
53
49
  transformValue: 0,
54
- customViewHeight: 0,
55
50
  actionParams: {},
56
51
  hasCustomView: false,
57
52
  });
@@ -67,12 +62,14 @@ const ProviderComponent = ({
67
62
  state => {
68
63
  switch (state) {
69
64
  case CONTEXT_MENU_STATE.ACTIVE: {
70
- if (onOpen) runOnJS(onOpen)();
71
- break;
65
+ if (onOpen)
66
+ runOnJS(onOpen)();
67
+ break
72
68
  }
73
69
  case CONTEXT_MENU_STATE.END: {
74
- if (onClose) runOnJS(onClose)();
75
- break;
70
+ if (onClose)
71
+ runOnJS(onClose)();
72
+ break
76
73
  }
77
74
  }
78
75
  },
@@ -84,59 +84,6 @@ export const menuAnimationAnchor = (
84
84
  };
85
85
  };
86
86
 
87
- export const calculateDynamicTransformValue = (
88
- itemY: number,
89
- itemHeight: number,
90
- menuHeight: number,
91
- customViewHeight: number,
92
- anchorPosition: TransformOriginAnchorPosition,
93
- screenHeight: number,
94
- safeAreaTop: number,
95
- safeAreaBottom: number
96
- ): number => {
97
- 'worklet';
98
- const GAP = styleGuide.spacing;
99
- const isAnchorTop = anchorPosition.includes('top');
100
-
101
- if (isAnchorTop) {
102
- // Menu below item, custom view above item
103
- // Total space needed below item: itemHeight + gap + menuHeight + safeAreaBottom
104
- // Total space needed above item: customViewHeight + gap + safeAreaTop
105
- const bottomEdge = itemY + itemHeight + GAP + menuHeight + safeAreaBottom;
106
- const topEdge = itemY - GAP - customViewHeight - safeAreaTop;
107
-
108
- let tY = 0;
109
-
110
- // If bottom overflows screen
111
- if (bottomEdge > screenHeight) {
112
- tY = screenHeight - bottomEdge;
113
- }
114
- // After shifting, check if custom view goes above safe area
115
- if (topEdge + tY < 0) {
116
- tY = -topEdge;
117
- }
118
- return tY;
119
- } else {
120
- // Menu above item, custom view below item
121
- // Total space needed above item: menuHeight + gap + safeAreaTop
122
- // Total space needed below item: itemHeight + gap + customViewHeight + safeAreaBottom
123
- const topEdge = itemY - GAP - menuHeight - safeAreaTop;
124
- const bottomEdge =
125
- itemY + itemHeight + GAP + customViewHeight + safeAreaBottom;
126
-
127
- let tY = 0;
128
- // If top overflows screen (goes above safe area)
129
- if (topEdge < 0) {
130
- tY = -topEdge;
131
- }
132
- // After shifting, check if custom view goes below screen
133
- if (bottomEdge + tY > screenHeight) {
134
- tY = screenHeight - bottomEdge;
135
- }
136
- return tY;
137
- }
138
- };
139
-
140
87
  export const getTransformOrigin = (
141
88
  posX: number,
142
89
  itemWidth: number,