diff --git a/README.md b/README.md
index 334d2d3d..aff8878e 100644
--- a/README.md
+++ b/README.md
@@ -291,6 +291,40 @@ It will contain id of the given action.
|-------------------------|----------|
| ({nativeEvent}) => void | No |
+### Events
+
+#### `onCloseMenu`
+
+Callback function that will be called when the menu is dismissed. This event fires at the start of the dismissal, before any animations complete.
+
+| Type | Required |
+|------------|----------|
+| () => void | No |
+
+#### `onOpenMenu`
+
+Callback function that will be called when the menu is opened. This event fires right before the menu is displayed.
+
+| Type | Required |
+|------------|----------|
+| () => void | No |
+
+Example usage:
+```jsx
+ {
+ console.log('Menu was opened');
+ }}
+ onCloseMenu={() => {
+ console.log('Menu was closed');
+ }}
+ // ... other props
+>
+
+ Open Menu
+
+
+```
## Testing with Jest
In some cases, you might want to mock the package to test your components. You can do this by using the `jest.mock` function.
diff --git a/android/src/main/java/com/reactnativemenu/MenuOnCloseEvent.kt b/android/src/main/java/com/reactnativemenu/MenuOnCloseEvent.kt
new file mode 100644
index 00000000..7a585cbb
--- /dev/null
+++ b/android/src/main/java/com/reactnativemenu/MenuOnCloseEvent.kt
@@ -0,0 +1,13 @@
+package com.reactnativemenu
+
+import com.facebook.react.bridge.Arguments
+import com.facebook.react.bridge.WritableMap
+import com.facebook.react.uimanager.events.Event
+
+class MenuOnCloseEvent(surfaceId: Int, viewId: Int, private val targetId: Int) : Event(surfaceId, viewId) {
+ override fun getEventName() = "onCloseMenu"
+
+ override fun getEventData(): WritableMap? {
+ return Arguments.createMap()
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/java/com/reactnativemenu/MenuOnOpenEvent.kt b/android/src/main/java/com/reactnativemenu/MenuOnOpenEvent.kt
new file mode 100644
index 00000000..89a63019
--- /dev/null
+++ b/android/src/main/java/com/reactnativemenu/MenuOnOpenEvent.kt
@@ -0,0 +1,13 @@
+package com.reactnativemenu
+
+import com.facebook.react.bridge.Arguments
+import com.facebook.react.bridge.WritableMap
+import com.facebook.react.uimanager.events.Event
+
+class MenuOnOpenEvent(surfaceId: Int, viewId: Int, private val targetId: Int) : Event(surfaceId, viewId) {
+ override fun getEventName() = "onOpenMenu"
+
+ override fun getEventData(): WritableMap? {
+ return Arguments.createMap()
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/java/com/reactnativemenu/MenuView.kt b/android/src/main/java/com/reactnativemenu/MenuView.kt
index 0b3dbe59..e0f93aab 100644
--- a/android/src/main/java/com/reactnativemenu/MenuView.kt
+++ b/android/src/main/java/com/reactnativemenu/MenuView.kt
@@ -261,8 +261,14 @@ class MenuView(private val mContext: ReactContext) : ReactViewGroup(mContext) {
}
mPopupMenu.setOnDismissListener {
mIsMenuDisplayed = false
+ val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(mContext, id)
+ val surfaceId: Int = UIManagerHelper.getSurfaceId(this)
+ dispatcher?.dispatchEvent(MenuOnCloseEvent(surfaceId, id, id))
}
mIsMenuDisplayed = true
+ val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(mContext, id)
+ val surfaceId: Int = UIManagerHelper.getSurfaceId(this)
+ dispatcher?.dispatchEvent(MenuOnOpenEvent(surfaceId, id, id))
mPopupMenu.show()
}
}
diff --git a/android/src/main/java/com/reactnativemenu/MenuViewManagerBase.kt b/android/src/main/java/com/reactnativemenu/MenuViewManagerBase.kt
index 2b2b0797..9089217e 100644
--- a/android/src/main/java/com/reactnativemenu/MenuViewManagerBase.kt
+++ b/android/src/main/java/com/reactnativemenu/MenuViewManagerBase.kt
@@ -17,7 +17,7 @@ import com.facebook.react.views.view.ReactDrawableHelper
import com.facebook.react.views.view.ReactViewGroup
import com.facebook.yoga.YogaConstants
-abstract class MenuViewManagerBase: ReactClippingViewManager() {
+abstract class MenuViewManagerBase : ReactClippingViewManager() {
override fun getName() = "MenuView"
@ReactProp(name = "actions")
@@ -37,8 +37,12 @@ abstract class MenuViewManagerBase: ReactClippingViewManager() {
override fun getExportedCustomDirectEventTypeConstants(): MutableMap {
return MapBuilder.of(
- "onPressAction",
- MapBuilder.of("registrationName", "onPressAction")
+ "onPressAction",
+ MapBuilder.of("registrationName", "onPressAction"),
+ "onCloseMenu",
+ MapBuilder.of("registrationName", "onCloseMenu"),
+ "onOpenMenu",
+ MapBuilder.of("registrationName", "onOpenMenu")
)
}
@@ -82,7 +86,19 @@ abstract class MenuViewManagerBase: ReactClippingViewManager() {
view.nextFocusUpId = viewId
}
- @ReactPropGroup(names = [ViewProps.BORDER_RADIUS, ViewProps.BORDER_TOP_LEFT_RADIUS, ViewProps.BORDER_TOP_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_RIGHT_RADIUS, ViewProps.BORDER_BOTTOM_LEFT_RADIUS, ViewProps.BORDER_TOP_START_RADIUS, ViewProps.BORDER_TOP_END_RADIUS, ViewProps.BORDER_BOTTOM_START_RADIUS, ViewProps.BORDER_BOTTOM_END_RADIUS])
+ @ReactPropGroup(
+ names =
+ [
+ ViewProps.BORDER_RADIUS,
+ ViewProps.BORDER_TOP_LEFT_RADIUS,
+ ViewProps.BORDER_TOP_RIGHT_RADIUS,
+ ViewProps.BORDER_BOTTOM_RIGHT_RADIUS,
+ ViewProps.BORDER_BOTTOM_LEFT_RADIUS,
+ ViewProps.BORDER_TOP_START_RADIUS,
+ ViewProps.BORDER_TOP_END_RADIUS,
+ ViewProps.BORDER_BOTTOM_START_RADIUS,
+ ViewProps.BORDER_BOTTOM_END_RADIUS]
+ )
fun setBorderRadius(view: ReactViewGroup, index: Int, borderRadius: Float) {
var borderRadius = borderRadius
if (!YogaConstants.isUndefined(borderRadius) && borderRadius < 0) {
@@ -109,33 +125,60 @@ abstract class MenuViewManagerBase: ReactClippingViewManager() {
// We should keep using setters as `Val cannot be reassigned`
view.setHitSlopRect(null)
} else {
- view.setHitSlopRect(Rect(
- if (hitSlop.hasKey("left")) PixelUtil.toPixelFromDIP(hitSlop.getDouble("left")).toInt() else 0,
- if (hitSlop.hasKey("top")) PixelUtil.toPixelFromDIP(hitSlop.getDouble("top")).toInt() else 0,
- if (hitSlop.hasKey("right")) PixelUtil.toPixelFromDIP(hitSlop.getDouble("right")).toInt() else 0,
- if (hitSlop.hasKey("bottom")) PixelUtil.toPixelFromDIP(hitSlop.getDouble("bottom")).toInt() else 0))
+ view.setHitSlopRect(
+ Rect(
+ if (hitSlop.hasKey("left"))
+ PixelUtil.toPixelFromDIP(hitSlop.getDouble("left")).toInt()
+ else 0,
+ if (hitSlop.hasKey("top"))
+ PixelUtil.toPixelFromDIP(hitSlop.getDouble("top")).toInt()
+ else 0,
+ if (hitSlop.hasKey("right"))
+ PixelUtil.toPixelFromDIP(hitSlop.getDouble("right")).toInt()
+ else 0,
+ if (hitSlop.hasKey("bottom"))
+ PixelUtil.toPixelFromDIP(hitSlop.getDouble("bottom")).toInt()
+ else 0
+ )
+ )
}
}
@ReactProp(name = "nativeBackgroundAndroid")
fun setNativeBackground(view: ReactViewGroup, @Nullable bg: ReadableMap?) {
view.setTranslucentBackgroundDrawable(
- if (bg == null) null else ReactDrawableHelper.createDrawableFromJSDescription(view.context, bg))
+ if (bg == null) null
+ else ReactDrawableHelper.createDrawableFromJSDescription(view.context, bg)
+ )
}
@TargetApi(Build.VERSION_CODES.M)
@ReactProp(name = "nativeForegroundAndroid")
fun setNativeForeground(view: ReactViewGroup, @Nullable fg: ReadableMap?) {
- view.foreground = if (fg == null) null else ReactDrawableHelper.createDrawableFromJSDescription(view.context, fg)
+ view.foreground =
+ if (fg == null) null
+ else ReactDrawableHelper.createDrawableFromJSDescription(view.context, fg)
}
@ReactProp(name = ViewProps.NEEDS_OFFSCREEN_ALPHA_COMPOSITING)
fun setNeedsOffscreenAlphaCompositing(
- view: ReactViewGroup, needsOffscreenAlphaCompositing: Boolean) {
+ view: ReactViewGroup,
+ needsOffscreenAlphaCompositing: Boolean
+ ) {
view.setNeedsOffscreenAlphaCompositing(needsOffscreenAlphaCompositing)
}
- @ReactPropGroup(names = [ViewProps.BORDER_WIDTH, ViewProps.BORDER_LEFT_WIDTH, ViewProps.BORDER_RIGHT_WIDTH, ViewProps.BORDER_TOP_WIDTH, ViewProps.BORDER_BOTTOM_WIDTH, ViewProps.BORDER_START_WIDTH, ViewProps.BORDER_END_WIDTH])
+ @ReactPropGroup(
+ names =
+ [
+ ViewProps.BORDER_WIDTH,
+ ViewProps.BORDER_LEFT_WIDTH,
+ ViewProps.BORDER_RIGHT_WIDTH,
+ ViewProps.BORDER_TOP_WIDTH,
+ ViewProps.BORDER_BOTTOM_WIDTH,
+ ViewProps.BORDER_START_WIDTH,
+ ViewProps.BORDER_END_WIDTH]
+ )
fun setBorderWidth(view: ReactViewGroup, index: Int, width: Float) {
var width = width
if (!YogaConstants.isUndefined(width) && width < 0) {
@@ -147,7 +190,18 @@ abstract class MenuViewManagerBase: ReactClippingViewManager() {
view.setBorderWidth(SPACING_TYPES[index], width)
}
- @ReactPropGroup(names = [ViewProps.BORDER_COLOR, ViewProps.BORDER_LEFT_COLOR, ViewProps.BORDER_RIGHT_COLOR, ViewProps.BORDER_TOP_COLOR, ViewProps.BORDER_BOTTOM_COLOR, ViewProps.BORDER_START_COLOR, ViewProps.BORDER_END_COLOR], customType = "Color")
+ @ReactPropGroup(
+ names =
+ [
+ ViewProps.BORDER_COLOR,
+ ViewProps.BORDER_LEFT_COLOR,
+ ViewProps.BORDER_RIGHT_COLOR,
+ ViewProps.BORDER_TOP_COLOR,
+ ViewProps.BORDER_BOTTOM_COLOR,
+ ViewProps.BORDER_START_COLOR,
+ ViewProps.BORDER_END_COLOR],
+ customType = "Color"
+ )
abstract fun setBorderColor(view: ReactViewGroup, index: Int, color: Int?)
@ReactProp(name = ViewProps.OVERFLOW)
@@ -181,14 +235,15 @@ abstract class MenuViewManagerBase: ReactClippingViewManager() {
companion object {
val COMMAND_SHOW = 1
- val SPACING_TYPES = arrayOf(
- Spacing.ALL,
- Spacing.LEFT,
- Spacing.RIGHT,
- Spacing.TOP,
- Spacing.BOTTOM,
- Spacing.START,
- Spacing.END
- )
+ val SPACING_TYPES =
+ arrayOf(
+ Spacing.ALL,
+ Spacing.LEFT,
+ Spacing.RIGHT,
+ Spacing.TOP,
+ Spacing.BOTTOM,
+ Spacing.START,
+ Spacing.END
+ )
}
}
diff --git a/ios/MenuViewManager.mm b/ios/MenuViewManager.mm
index 41a968e2..3d149b3e 100644
--- a/ios/MenuViewManager.mm
+++ b/ios/MenuViewManager.mm
@@ -57,6 +57,14 @@ - (UIView *)view
* onPressAction: callback to be called once user selects an action
*/
RCT_EXPORT_VIEW_PROPERTY(onPressAction, RCTDirectEventBlock);
+/**
+ * onCloseMenu: callback to be called when the menu is closed
+ */
+RCT_EXPORT_VIEW_PROPERTY(onCloseMenu, RCTDirectEventBlock);
+/**
+ * onOpenMenu: callback to be called when the menu is opened
+ */
+RCT_EXPORT_VIEW_PROPERTY(onOpenMenu, RCTDirectEventBlock);
/**
* shouldOpenOnLongPress: determines whether menu should be opened after long press or normal press
*/
diff --git a/ios/NewArch/FabricActionSheetView.swift b/ios/NewArch/FabricActionSheetView.swift
index 74d2f48f..484ff8a1 100644
--- a/ios/NewArch/FabricActionSheetView.swift
+++ b/ios/NewArch/FabricActionSheetView.swift
@@ -1,11 +1,23 @@
-
@objc(FabricActionSheetView)
public class FabricActionSheetView: ActionSheetView, FabricViewImplementationProtocol {
public var onPressAction: ((String) -> Void)?
-
+ public var onCloseMenu: (() -> Void)?
+ public var onOpenMenu: (() -> Void)?
+
@objc override func sendButtonAction(_ action: String) {
if let onPress = onPressAction {
onPress(action)
}
}
+
+ @objc override func sendMenuClose() {
+ if let onCloseMenu = onCloseMenu {
+ onCloseMenu()
+ }
+ }
+ @objc override func sendMenuOpen() {
+ if let onOpenMenu = onOpenMenu {
+ onOpenMenu()
+ }
+ }
}
diff --git a/ios/NewArch/FabricMenuViewImplementation.swift b/ios/NewArch/FabricMenuViewImplementation.swift
index 03df036d..33d27c5a 100644
--- a/ios/NewArch/FabricMenuViewImplementation.swift
+++ b/ios/NewArch/FabricMenuViewImplementation.swift
@@ -10,11 +10,25 @@ import UIKit
@objc(FabricMenuViewImplementation)
public class FabricMenuViewImplementation: MenuViewImplementation, FabricViewImplementationProtocol {
public var onPressAction: ((String) -> Void)?
-
+ public var onCloseMenu: (() -> Void)?
+ public var onOpenMenu: (() -> Void)?
+
@objc override func sendButtonAction(_ action: UIAction) {
if let onPress = onPressAction {
onPress(action.identifier.rawValue)
}
}
+ @objc override func sendMenuClose() {
+ if let onCloseMenu = onCloseMenu {
+ onCloseMenu()
+ }
+ }
+
+ @objc override func sendMenuOpen() {
+ if let onOpenMenu = onOpenMenu {
+ onOpenMenu()
+ }
+ }
+
}
diff --git a/ios/NewArch/FabricViewImplementationProtocol.swift b/ios/NewArch/FabricViewImplementationProtocol.swift
index 80353c6c..2cef2fb8 100644
--- a/ios/NewArch/FabricViewImplementationProtocol.swift
+++ b/ios/NewArch/FabricViewImplementationProtocol.swift
@@ -6,4 +6,6 @@ import Foundation
var shouldOpenOnLongPress: Bool { get set }
@objc optional var hitSlop: UIEdgeInsets { get set }
var onPressAction: ((String) -> Void)? { get set }
+ var onCloseMenu: (() -> Void)? { get set }
+ var onOpenMenu: (() -> Void)? { get set }
}
diff --git a/ios/NewArch/MenuView.mm b/ios/NewArch/MenuView.mm
index da06dfd8..6e815e49 100644
--- a/ios/NewArch/MenuView.mm
+++ b/ios/NewArch/MenuView.mm
@@ -41,6 +41,9 @@ - (instancetype)initWithFrame:(CGRect)frame
_view.onPressAction = ^(NSString *eventString) {
[self onPressAction:eventString];
};
+ _view.onCloseMenu = ^{
+ [self onCloseMenu];
+ };
self.contentView = _view;
}
@@ -68,6 +71,22 @@ - (void)onPressAction:(NSString * _Nonnull)eventString {
}
}
+- (void)onCloseMenu {
+ // If screen is already unmounted then there will be no event emitter
+ const auto eventEmitter = [self getEventEmitter];
+ if (eventEmitter != nullptr) {
+ eventEmitter->onCloseMenu({});
+ }
+}
+
+- (void)onOpenMenu {
+ // If screen is already unmounted then there will be no event emitter
+ const auto eventEmitter = [self getEventEmitter];
+ if (eventEmitter != nullptr) {
+ eventEmitter->onOpenMenu({});
+ }
+}
+
/**
Responsible for iterating through the C++ vector and convert each struct element to NSDictionary, then return it all in an NSArray
*/
diff --git a/ios/OldArch/LegacyActionSheetView.swift b/ios/OldArch/LegacyActionSheetView.swift
index a46ff502..3cd1a251 100644
--- a/ios/OldArch/LegacyActionSheetView.swift
+++ b/ios/OldArch/LegacyActionSheetView.swift
@@ -1,11 +1,26 @@
-
@objc(LegacyActionSheetView)
public class LegacyActionSheetView: ActionSheetView {
@objc var onPressAction: RCTDirectEventBlock?
-
+ @objc var onCloseMenu: RCTDirectEventBlock?
+ @objc var onOpenMenu: RCTDirectEventBlock?
+
+
+
@objc override func sendButtonAction(_ action: String) {
if let onPress = onPressAction {
onPress(["event":action])
}
}
+
+ @objc override func sendMenuClose() {
+ if let onCloseMenu = onCloseMenu {
+ onCloseMenu([:])
+ }
+ }
+
+ @objc override func sendMenuOpen() {
+ if let onOpenMenu = onOpenMenu {
+ onOpenMenu([:])
+ }
+ }
}
diff --git a/ios/OldArch/LegacyMenuViewImplementation.swift b/ios/OldArch/LegacyMenuViewImplementation.swift
index 6329cf2a..6a2a205f 100644
--- a/ios/OldArch/LegacyMenuViewImplementation.swift
+++ b/ios/OldArch/LegacyMenuViewImplementation.swift
@@ -3,6 +3,8 @@ import UIKit
@objc(LegacyMenuViewImplementation)
public class LegacyMenuViewImplementation: MenuViewImplementation {
@objc var onPressAction: RCTDirectEventBlock?
+ @objc var onCloseMenu: RCTDirectEventBlock?
+ @objc var onOpenMenu: RCTDirectEventBlock?
@objc override func sendButtonAction(_ action: UIAction) {
if let onPress = onPressAction {
@@ -10,4 +12,16 @@ public class LegacyMenuViewImplementation: MenuViewImplementation {
}
}
+ @objc override func sendMenuClose() {
+ if let onCloseMenu = onCloseMenu {
+ onCloseMenu([:])
+ }
+ }
+
+ @objc override func sendMenuOpen() {
+ if let onOpenMenu = onOpenMenu {
+ onOpenMenu([:])
+ }
+ }
+
}
diff --git a/ios/Shared/ActionSheetView.swift b/ios/Shared/ActionSheetView.swift
index c521b19d..352d8fa6 100644
--- a/ios/Shared/ActionSheetView.swift
+++ b/ios/Shared/ActionSheetView.swift
@@ -26,6 +26,7 @@ public class ActionSheetView: UIView {
actions.forEach({ alertAction in
if let action = RCTAlertAction(details: alertAction).createAction({
event in self.sendButtonAction(event)
+ self.sendMenuClose()
}) {
_actions.append(action)
}
@@ -49,6 +50,7 @@ public class ActionSheetView: UIView {
}
func launchActionSheet() {
+ self.sendMenuOpen()
let alert = UIAlertController(title: _title, message: nil, preferredStyle: .actionSheet)
@@ -68,7 +70,9 @@ public class ActionSheetView: UIView {
alert.addAction(action.copy() as! UIAlertAction)
})
- alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
+ alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in
+ self.sendMenuClose()
+ }))
if UIDevice.current.userInterfaceIdiom == .pad {
alert.modalPresentationStyle = .popover
@@ -109,6 +113,14 @@ public class ActionSheetView: UIView {
// NO-OP (should be overriden by parent)
}
+ @objc func sendMenuClose() {
+ // NO-OP (should be overriden by parent)
+ }
+
+ @objc func sendMenuOpen() {
+ // NO-OP (should be overriden by parent)
+ }
+
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
diff --git a/ios/Shared/MenuViewImplementation.swift b/ios/Shared/MenuViewImplementation.swift
index ccfc5810..5c4e0da4 100644
--- a/ios/Shared/MenuViewImplementation.swift
+++ b/ios/Shared/MenuViewImplementation.swift
@@ -53,13 +53,28 @@ public class MenuViewImplementation: UIButton {
@objc public var hitSlop: UIEdgeInsets = .zero
override init(frame: CGRect) {
- super.init(frame: frame)
- self.setup()
+ super.init(frame: frame)
+ let interaction = UIContextMenuInteraction(delegate: self)
+ self.addInteraction(interaction)
+ self.setup()
+ }
+
+ public override func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
+ sendMenuOpen()
+ return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { [weak self] _ in
+ guard let self = self else { return nil }
+ return self.menu
+ }
+ }
+
+ public override func contextMenuInteraction(_ interaction: UIContextMenuInteraction, willEndFor configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionAnimating?) {
+ sendMenuClose()
}
-
func setup () {
- let menu = UIMenu(title:_title, identifier: nil, children: self._actions)
+ let menu = UIMenu(title: _title,
+ identifier: nil,
+ children: self._actions)
if self._themeVariant != nil {
if self._themeVariant == "dark" {
@@ -76,15 +91,14 @@ public class MenuViewImplementation: UIButton {
}
public override func reactSetFrame(_ frame: CGRect) {
- super.reactSetFrame(frame);
- };
+ super.reactSetFrame(frame);
+ }
public override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
if hitSlop == .zero || !self.isEnabled || self.isHidden {
return super.point(inside: point, with: event)
}
- // Create a larger hit frame that extends beyond the view's bounds
let largerFrame = CGRect(
x: self.bounds.origin.x - hitSlop.left,
y: self.bounds.origin.y - hitSlop.top,
@@ -92,16 +106,22 @@ public class MenuViewImplementation: UIButton {
height: self.bounds.size.height + hitSlop.top + hitSlop.bottom
)
- // Check if the point is within the larger frame
return largerFrame.contains(point)
}
-
- required init?(coder aDecoder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
+ required init?(coder aDecoder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
@objc func sendButtonAction(_ action: UIAction) {
// NO-OP (should be overriden by parent)
}
+
+ @objc func sendMenuClose() {
+ // NO-OP (should be overriden by parent)
+ }
+
+ @objc func sendMenuOpen() {
+ // NO-OP (should be overriden by parent)
+ }
}
diff --git a/src/NativeModuleSpecs/UIMenuNativeComponent.ts b/src/NativeModuleSpecs/UIMenuNativeComponent.ts
index 34726504..e6509355 100644
--- a/src/NativeModuleSpecs/UIMenuNativeComponent.ts
+++ b/src/NativeModuleSpecs/UIMenuNativeComponent.ts
@@ -12,6 +12,7 @@ import codegenNativeComponent from "react-native/Libraries/Utilities/codegenNati
OR with extending types in an interface, so for now we'll just keep some duplicate
types here, to avoid issues while `pod install` takes place.
*/
+
type SubAction = {
id?: string;
title: string;
@@ -45,6 +46,8 @@ type MenuAction = {
};
export interface NativeProps extends ViewProps {
onPressAction?: DirectEventHandler<{ event: string }>;
+ onCloseMenu?: DirectEventHandler<{ event: string }>;
+ onOpenMenu?: DirectEventHandler<{ event: string }>;
actions: Array;
actionsHash: string; // just a workaround to make sure we don't have to manually compare MenuActions manually in C++ (since it's a struct and that's a pain)
title?: string;
@@ -55,7 +58,7 @@ export interface NativeProps extends ViewProps {
bottom: Int32;
left: Int32;
right: Int32;
- }
+ };
}
export default codegenNativeComponent(
diff --git a/src/index.tsx b/src/index.tsx
index 9ca58dda..a5362981 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -3,50 +3,50 @@ import { processColor } from "react-native";
import UIMenuView from "./UIMenuView";
import type {
- MenuComponentProps,
- MenuAction,
- ProcessedMenuAction,
- NativeActionEvent,
- MenuComponentRef,
+ MenuComponentProps,
+ MenuAction,
+ ProcessedMenuAction,
+ NativeActionEvent,
+ MenuComponentRef,
} from "./types";
import { objectHash } from "./utils";
function processAction(action: MenuAction): ProcessedMenuAction {
- return {
- ...action,
- imageColor: processColor(action.imageColor),
- titleColor: processColor(action.titleColor),
- subactions: action.subactions?.map((subAction) => processAction(subAction)),
- };
+ return {
+ ...action,
+ imageColor: processColor(action.imageColor),
+ titleColor: processColor(action.titleColor),
+ subactions: action.subactions?.map((subAction) => processAction(subAction)),
+ };
}
const defaultHitslop = { top: 0, left: 0, bottom: 0, right: 0 };
const MenuView = forwardRef(
- ({ actions, hitSlop = defaultHitslop, ...props }, ref) => {
- const processedActions = actions.map((action) =>
- processAction(action),
- );
- const hash = useMemo(() => {
- return objectHash(processedActions);
- }, [processedActions]);
+ ({ actions, hitSlop = defaultHitslop, ...props }, ref) => {
+ const processedActions = actions.map((action) =>
+ processAction(action),
+ );
+ const hash = useMemo(() => {
+ return objectHash(processedActions);
+ }, [processedActions]);
- return (
-
- );
- },
+ return (
+
+ );
+ },
);
export { MenuView };
export type {
- MenuComponentProps,
- MenuComponentRef,
- MenuAction,
- NativeActionEvent,
+ MenuComponentProps,
+ MenuComponentRef,
+ MenuAction,
+ NativeActionEvent,
};
diff --git a/src/types.ts b/src/types.ts
index 6f9dc310..9c323d9c 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -115,6 +115,14 @@ type MenuComponentPropsBase = {
* It will contain id of the given action.
*/
onPressAction?: ({ nativeEvent }: NativeActionEvent) => void;
+ /**
+ * Callback function that will be called when the menu closes.
+ */
+ onCloseMenu?: () => void;
+ /**
+ * Callback function that will be called when the menu opens.
+ */
+ onOpenMenu?: () => void;
/**
* Actions to be displayed in the menu.
*/
@@ -179,6 +187,8 @@ export type ProcessedMenuAction = Omit<
export type NativeMenuComponentProps = {
style?: StyleProp;
onPressAction?: ({ nativeEvent }: NativeActionEvent) => void;
+ onCloseMenu?: () => void;
+ onOpenMenu?: () => void;
actions: ProcessedMenuAction[];
actionsHash: string;
title?: string;