callstack / callstack/react-native-paper
feat: modernize Menu to the latest Material Design specs
- Dominant language
- TypeScript
- Stars
- 14.5k
- Forks
- 2.2k
- Avg merge
- 5d 23h
- Merged PRs (30d)
- 12
Description
- Modernize the Menu component to the latest specs. Reuse the newly introduced theme tokens (typography, motion, shape etc).
See https://m3.material.io/components/menus for the full picture.
- Extract component specific tokens for easier maintenance.
- Get inspired from TextInput/TextField, Switch, Checkbox, FAB components which have gone through modernization.
# Current State
## Menu
**MD3 spec:** Menus
**Specs link:** https://m3.material.io/components/menus/specs
### Color tokens
- Container background: `theme.colors.elevation[level2]` which resolves to `surfaceContainerLow` ✅ (standard color scheme)
- `Menu.Item` label text: `onSurface` ✅
- `Menu.Item` leading/trailing icon: `onSurfaceVariant` ✅
- `Menu.Item` disabled opacity: `stateOpacity.disabled` (0.38) ✅
- [ ] No selected item state: spec defines `tertiaryContainer` bg / `onTertiaryContainer` text+icon for selected menu items
- [ ] No vibrant color scheme (M3 Expressive): `tertiaryContainer` container / `onTertiaryContainer` icons+labels / `tertiary` selected bg / `onTertiary` selected text+icon
### Spacing / sizing
- Container `paddingVertical: 8` ✅
- Item min/max width: 112dp / 280dp ✅
- Item `paddingHorizontal: 12` ✅
- Icon leading margin: 12dp after icon ✅
- Item height: 48dp (standard), 32dp (dense) – baseline menu values ✅
- [ ] `Menu.Item` label text uses `bodyLarge`; spec requires `labelLarge`
- [ ] `Menu.Item` has no supporting text slot (`bodySmall`); spec anatomy includes optional supporting text per item
- [ ] `Menu.Item` has no trailing supporting text slot (`labelLarge`); spec anatomy includes optional trailing text per item
### Shape
- [ ] Container: `borderRadius: theme.roundness` = 4dp; spec `corner.large` = `4 * roundness` = 16dp ❌
- [ ] First child item: spec `corner.medium` top corners; not implemented
- [ ] Last child item: spec `corner.medium` bottom corners; not implemented
- [ ] Selected item: spec `corner.medium`; not implemented
- No per-item shape rounding at all; all items are rectangles
### Behavior
- Open/close: scale + opacity animation ✅ (but uses `Easing.bezier(0.4, 0, 0.2, 1)` from old M3 motion guidelines; M3 Expressive uses spring-based motion)
- Dismisses on outside press ✅
- Keyboard-aware positioning ✅
- RTL support ✅
- Escape key dismissal on web ✅
- Back handler on Android ✅
- [ ] No item selection state / active item support
- [ ] No grouped layout (gaps between item groups); current workaround uses `Divider` which is not the spec-aligned grouping mechanism for vertical menus
- [ ] No submenu support
- [ ] No badge support on items
- [ ] M3 Expressive vertical menu shape morphing (active container shape animates as focus moves to submenu) not implemented
### Notes
- The current component implements the baseline menu variant only. The M3 Expressive vertical menu is a largely new feature surface (new shapes, selection states, vibrant color scheme, submenu motion, grouped layout) that requires significant additions.
- The `borderRadius: theme.roundness` bug is a significant visual regression vs spec – the container should be visibly rounded.
Contributor guide
Assessment
This issue has not been assessed yet.