initial commit
This commit is contained in:
170
.agents/skills/vercel-react-native-skills/rules/ui-menus.md
Normal file
170
.agents/skills/vercel-react-native-skills/rules/ui-menus.md
Normal file
@@ -0,0 +1,170 @@
|
||||
---
|
||||
title: Use Native Menus for Dropdowns and Context Menus
|
||||
impact: HIGH
|
||||
impactDescription: native accessibility, platform-consistent UX
|
||||
tags: user-interface, menus, context-menus, zeego, accessibility
|
||||
---
|
||||
|
||||
## Use Native Menus for Dropdowns and Context Menus
|
||||
|
||||
Use native platform menus instead of custom JS implementations. Native menus
|
||||
provide built-in accessibility, consistent platform UX, and better performance.
|
||||
Use [zeego](https://zeego.dev) for cross-platform native menus.
|
||||
|
||||
**Incorrect (custom JS menu):**
|
||||
|
||||
```tsx
|
||||
import { useState } from "react";
|
||||
import { View, Pressable, Text } from "react-native";
|
||||
|
||||
function MyMenu() {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Pressable onPress={() => setOpen(!open)}>
|
||||
<Text>Open Menu</Text>
|
||||
</Pressable>
|
||||
{open && (
|
||||
<View style={{ position: "absolute", top: 40 }}>
|
||||
<Pressable onPress={() => console.log("edit")}>
|
||||
<Text>Edit</Text>
|
||||
</Pressable>
|
||||
<Pressable onPress={() => console.log("delete")}>
|
||||
<Text>Delete</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**Correct (native menu with zeego):**
|
||||
|
||||
```tsx
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
|
||||
function MyMenu() {
|
||||
return (
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
<Pressable>
|
||||
<Text>Open Menu</Text>
|
||||
</Pressable>
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
<DropdownMenu.Content>
|
||||
<DropdownMenu.Item key="edit" onSelect={() => console.log("edit")}>
|
||||
<DropdownMenu.ItemTitle>Edit</DropdownMenu.ItemTitle>
|
||||
</DropdownMenu.Item>
|
||||
|
||||
<DropdownMenu.Item key="delete" destructive onSelect={() => console.log("delete")}>
|
||||
<DropdownMenu.ItemTitle>Delete</DropdownMenu.ItemTitle>
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**Context menu (long-press):**
|
||||
|
||||
```tsx
|
||||
import * as ContextMenu from "zeego/context-menu";
|
||||
|
||||
function MyContextMenu() {
|
||||
return (
|
||||
<ContextMenu.Root>
|
||||
<ContextMenu.Trigger>
|
||||
<View style={{ padding: 20 }}>
|
||||
<Text>Long press me</Text>
|
||||
</View>
|
||||
</ContextMenu.Trigger>
|
||||
|
||||
<ContextMenu.Content>
|
||||
<ContextMenu.Item key="copy" onSelect={() => console.log("copy")}>
|
||||
<ContextMenu.ItemTitle>Copy</ContextMenu.ItemTitle>
|
||||
</ContextMenu.Item>
|
||||
|
||||
<ContextMenu.Item key="paste" onSelect={() => console.log("paste")}>
|
||||
<ContextMenu.ItemTitle>Paste</ContextMenu.ItemTitle>
|
||||
</ContextMenu.Item>
|
||||
</ContextMenu.Content>
|
||||
</ContextMenu.Root>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**Checkbox items:**
|
||||
|
||||
```tsx
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
|
||||
function SettingsMenu() {
|
||||
const [notifications, setNotifications] = useState(true);
|
||||
|
||||
return (
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
<Pressable>
|
||||
<Text>Settings</Text>
|
||||
</Pressable>
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
<DropdownMenu.Content>
|
||||
<DropdownMenu.CheckboxItem
|
||||
key="notifications"
|
||||
value={notifications}
|
||||
onValueChange={() => setNotifications((prev) => !prev)}
|
||||
>
|
||||
<DropdownMenu.ItemIndicator />
|
||||
<DropdownMenu.ItemTitle>Notifications</DropdownMenu.ItemTitle>
|
||||
</DropdownMenu.CheckboxItem>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**Submenus:**
|
||||
|
||||
```tsx
|
||||
import * as DropdownMenu from "zeego/dropdown-menu";
|
||||
|
||||
function MenuWithSubmenu() {
|
||||
return (
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
<Pressable>
|
||||
<Text>Options</Text>
|
||||
</Pressable>
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
<DropdownMenu.Content>
|
||||
<DropdownMenu.Item key="home" onSelect={() => console.log("home")}>
|
||||
<DropdownMenu.ItemTitle>Home</DropdownMenu.ItemTitle>
|
||||
</DropdownMenu.Item>
|
||||
|
||||
<DropdownMenu.Sub>
|
||||
<DropdownMenu.SubTrigger key="more">
|
||||
<DropdownMenu.ItemTitle>More Options</DropdownMenu.ItemTitle>
|
||||
</DropdownMenu.SubTrigger>
|
||||
|
||||
<DropdownMenu.SubContent>
|
||||
<DropdownMenu.Item key="settings">
|
||||
<DropdownMenu.ItemTitle>Settings</DropdownMenu.ItemTitle>
|
||||
</DropdownMenu.Item>
|
||||
|
||||
<DropdownMenu.Item key="help">
|
||||
<DropdownMenu.ItemTitle>Help</DropdownMenu.ItemTitle>
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.SubContent>
|
||||
</DropdownMenu.Sub>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
Reference: [Zeego Documentation](https://zeego.dev/components/dropdown-menu)
|
||||
Reference in New Issue
Block a user