Skip to content

Conversation

@SebastianThiebaud
Copy link

@SebastianThiebaud SebastianThiebaud commented Dec 18, 2025

Overview

Problem

When imageColor is undefined in a MenuAction, processColor(undefined) returns a transparent color (0,0,0,0). This transparent color is then applied as a tint to menu icons using withTintColor(), making the icons completely invisible.

Solution

Check if the color's alpha component is greater than 0 before applying the tint. This prevents transparent colors from being applied, allowing icons to display with their default appearance when imageColor is not provided.

Changes Made

File: ios/Shared/RCTMenuItem.swift

Before:

if let imageColor = details["imageColor"] {
    self.image = self.image?.withTintColor(RCTConvert.uiColor(imageColor), renderingMode: .alwaysOriginal)
}

After:

if let imageColor = details["imageColor"] {
    let uiColor = RCTConvert.uiColor(imageColor)
    // Only apply tint if color is valid and not transparent (alpha > 0)
    // processColor(undefined) returns transparent color (0,0,0,0) which makes icons invisible
    if let color = uiColor {
        var red: CGFloat = 0
        var green: CGFloat = 0
        var blue: CGFloat = 0
        var alpha: CGFloat = 0
        if color.getRed(&red, green: &green, blue: &blue, alpha: &alpha) && alpha > 0 {
            self.image = self.image?.withTintColor(color, renderingMode: .alwaysOriginal)
        }
    }
}

Test Plan

Prerequisites

  1. Create a React Native app or use an existing one
  2. Install @react-native-menu/menu package
  3. Build and run on iOS device or simulator (iOS 13+)

Test Case 1: Menu Icons Without imageColor (Primary Test)

This is the main bug fix - icons should be visible when imageColor is undefined

Test Code:

import { MenuView } from '@react-native-menu/menu';

function TestMenu() {
  return (
    <MenuView
      actions={[
        {
          id: 'action1',
          title: 'Action with icon (no imageColor)',
          image: 'heart', // SF Symbol name
          // imageColor is undefined - this is the bug case
        },
        {
          id: 'action2',
          title: 'Another action',
          image: 'star',
          // imageColor is undefined
        },
      ]}
      onPressAction={(e) => console.log(e.nativeEvent.event)}>
      <Pressable>
        <Text>Open Menu</Text>
      </Pressable>
    </MenuView>
  );
}

Expected Results:

  • ✅ Icons are visible in the menu (heart and star icons appear)
  • ✅ Icons display with their default system color
  • ✅ Icons are not transparent or invisible
  • ✅ Menu items are fully functional

Before Fix:

  • ❌ Icons would be invisible/transparent
  • ❌ Only empty space would appear where icons should be

Test Case 2: Menu Icons With Valid imageColor

Ensure the fix doesn't break existing functionality

Test Code:

import { MenuView } from '@react-native-menu/menu';
import { processColor } from 'react-native';

function TestMenuWithColor() {
  return (
    <MenuView
      actions={[
        {
          id: 'action1',
          title: 'Action with red icon',
          image: 'heart',
          imageColor: processColor('red'), // Valid color
        },
        {
          id: 'action2',
          title: 'Action with blue icon',
          image: 'star',
          imageColor: processColor('#007AFF'), // Valid color
        },
      ]}
      onPressAction={(e) => console.log(e.nativeEvent.event)}>
      <Pressable>
        <Text>Open Menu</Text>
      </Pressable>
    </MenuView>
  );
}

Expected Results:

  • ✅ Icons are visible and tinted with the specified colors
  • ✅ First icon appears in red
  • ✅ Second icon appears in blue
  • ✅ Tinting works correctly (no regression)

Test Case 3: Menu Icons With Transparent Color

Edge case: explicitly passing transparent color

Test Code:

import { MenuView } from '@react-native-menu/menu';
import { processColor } from 'react-native';

function TestMenuWithTransparent() {
  return (
    <MenuView
      actions={[
        {
          id: 'action1',
          title: 'Action with transparent color',
          image: 'heart',
          imageColor: processColor('rgba(0,0,0,0)'), // Explicitly transparent
        },
      ]}
      onPressAction={(e) => console.log(e.nativeEvent.event)}>
      <Pressable>
        <Text>Open Menu</Text>
      </Pressable>
    </MenuView>
  );
}

Expected Results:

  • ✅ Icon is visible with default system color (tint is not applied)
  • ✅ Icon does not become invisible
  • ✅ Menu item functions normally

Test Case 4: Menu Without Icons

Regression test: ensure menus without icons still work

Test Code:

import { MenuView } from '@react-native-menu/menu';

function TestMenuNoIcons() {
  return (
    <MenuView
      actions={[
        {
          id: 'action1',
          title: 'Action without icon',
        },
        {
          id: 'action2',
          title: 'Another action',
        },
      ]}
      onPressAction={(e) => console.log(e.nativeEvent.event)}>
      <Pressable>
        <Text>Open Menu</Text>
      </Pressable>
    </MenuView>
  );
}

Expected Results:

  • ✅ Menu displays correctly without icons
  • ✅ No crashes or errors
  • ✅ Menu items are functional

Test Case 5: Menu With Subactions

Regression test: ensure subactions work correctly

Test Code:

import { MenuView } from '@react-native-menu/menu';

function TestMenuWithSubactions() {
  return (
    <MenuView
      actions={[
        {
          id: 'parent',
          title: 'Parent Action',
          image: 'folder', // No imageColor
          subactions: [
            {
              id: 'child1',
              title: 'Child 1',
              image: 'doc', // No imageColor
            },
            {
              id: 'child2',
              title: 'Child 2',
              image: 'doc.text', // No imageColor
            },
          ],
        },
      ]}
      onPressAction={(e) => console.log(e.nativeEvent.event)}>
      <Pressable>
        <Text>Open Menu</Text>
      </Pressable>
    </MenuView>
  );
}

Expected Results:

  • ✅ Parent icon is visible
  • ✅ Child icons are visible in submenu
  • ✅ Submenu opens and closes correctly
  • ✅ All actions are functional

Test Case 6: Mixed Menu (Some with imageColor, Some without)

Test Code:

import { MenuView } from '@react-native-menu/menu';
import { processColor } from 'react-native';

function TestMixedMenu() {
  return (
    <MenuView
      actions={[
        {
          id: 'action1',
          title: 'Default icon (no color)',
          image: 'heart',
          // No imageColor
        },
        {
          id: 'action2',
          title: 'Colored icon',
          image: 'star',
          imageColor: processColor('red'),
        },
        {
          id: 'action3',
          title: 'Another default icon',
          image: 'trash',
          // No imageColor
        },
      ]}
      onPressAction={(e) => console.log(e.nativeEvent.event)}>
      <Pressable>
        <Text>Open Menu</Text>
      </Pressable>
    </MenuView>
  );
}

Expected Results:

  • ✅ First icon (heart) is visible with default color
  • ✅ Second icon (star) is visible and tinted red
  • ✅ Third icon (trash) is visible with default color
  • ✅ All icons display correctly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant