@@ -19,6 +19,8 @@ @implementation MenuView {
1919 UIColor *_textColor;
2020 UIColor *_checkedColor;
2121 UIColor *_uncheckedColor;
22+ BOOL _isChildViewButton;
23+ NSMutableSet <UIView *> *_disabledViews;
2224}
2325
2426+ (ComponentDescriptorProvider)componentDescriptorProvider
@@ -31,6 +33,8 @@ - (instancetype)initWithFrame:(CGRect)frame
3133 if (self = [super initWithFrame: frame]) {
3234 static const auto defaultProps = std::make_shared<const MenuViewProps>();
3335 _props = defaultProps;
36+ _disabledViews = [[NSMutableSet alloc ] init ];
37+ _isChildViewButton = NO ;
3438 }
3539
3640 return self;
@@ -42,10 +46,8 @@ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childCompone
4246 if (index == 0 ) {
4347 // Clean up old child view if exists
4448 if (_childView && _childView != childComponentView) {
45- // Remove from our manual tracking without calling removeFromSuperview
46- // since React will handle the view hierarchy cleanup
47- _childView = nil ;
48- _menuButton = nil ;
49+ [self cleanupMenuButton ];
50+ [self restoreUserInteractionForDisabledViews ];
4951 }
5052
5153 _childView = (UIView *)childComponentView;
@@ -64,8 +66,9 @@ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childCompo
6466{
6567 // Clean up our references before React unmounts
6668 if (index == 0 && _childView == childComponentView) {
69+ [self cleanupMenuButton ];
70+ [self restoreUserInteractionForDisabledViews ];
6771 _childView = nil ;
68- _menuButton = nil ;
6972 }
7073
7174 // Let React handle the unmounting
@@ -78,9 +81,11 @@ - (void)setupChildViewAsMenuTrigger:(UIView *)childView
7881 if ([childView isKindOfClass: [UIButton class ]]) {
7982 _menuButton = (UIButton *)childView;
8083 _menuButton.showsMenuAsPrimaryAction = YES ;
84+ _isChildViewButton = YES ;
8185 [self updateMenuItems: _menuItems selectedIdentifier: nil ];
8286 } else {
8387 // For non-button children, create an invisible button overlay to show the menu
88+ _isChildViewButton = NO ;
8489 [self disableUserInteractionRecursively: childView];
8590
8691 // Create an invisible button that covers the entire view
@@ -105,12 +110,46 @@ - (void)setupChildViewAsMenuTrigger:(UIView *)childView
105110
106111- (void )disableUserInteractionRecursively : (UIView *)view
107112{
108- view.userInteractionEnabled = NO ;
113+ if (view.userInteractionEnabled ) {
114+ [_disabledViews addObject: view];
115+ view.userInteractionEnabled = NO ;
116+ }
109117 for (UIView *subview in view.subviews ) {
110118 [self disableUserInteractionRecursively: subview];
111119 }
112120}
113121
122+ - (void )restoreUserInteractionForDisabledViews
123+ {
124+ for (UIView *view in _disabledViews) {
125+ // Only restore if the view is still in the view hierarchy
126+ if (view.superview != nil ) {
127+ view.userInteractionEnabled = YES ;
128+ }
129+ }
130+ [_disabledViews removeAllObjects ];
131+ }
132+
133+ - (void )cleanupMenuButton
134+ {
135+ if (_menuButton) {
136+ // If it's not a child view button (i.e., it's our overlay button), remove it
137+ if (!_isChildViewButton && _menuButton.superview == self) {
138+ [_menuButton removeFromSuperview ];
139+ }
140+ // Clear the menu to prevent any lingering references
141+ _menuButton.menu = nil ;
142+ _menuButton = nil ;
143+ }
144+ _isChildViewButton = NO ;
145+ }
146+
147+ - (void )dealloc
148+ {
149+ [self cleanupMenuButton ];
150+ [self restoreUserInteractionForDisabledViews ];
151+ }
152+
114153- (void )updateProps : (Props::Shared const &)props oldProps : (Props::Shared const &)oldProps
115154{
116155 const auto &oldViewProps = *std::static_pointer_cast<MenuViewProps const >(_props);
0 commit comments