# Menus - 菜单

## 说明

近手弹出菜单，通过 ref 调用 `showFrom(triggerRef)` 从触发元素附近弹出。支持三种交互项：`button`（点击执行）、`toggle`（开关态）、`select`（分组单选，同 `group` 内互斥）。菜单项可带左侧图标、选中态勾选图标和分割线。选项数据会按 `group` 自动归拢排序：同组 `select` 项聚在一起，组间与非 `select` 项保持原始相对顺序。点击任一项后菜单自动关闭。

通过 `forwardRef` 暴露 `MenusRef`，需配合触发元素的 ref 使用（如 `Drawer` 的 `rightIconRef`）。

## 属性

| 属性 | 说明 | 类型 | 默认值 | 必填 |
|------|------|------|--------|------|
| **data** | 菜单项列表 | `MenusItemData[]` | - | 是 |
| **colorType** | 选中态色系 | `ColorType` | `'green'` | 否 |
| **selectedIds** | 受控的 select 选中状态，key 为 group（无 group 用 `'_default'`），value 为选中项 id | `Record<string, string \| number>` | - | 否 |
| **onPress** | `actionType='button'` 点击回调 | `(item: MenusItemData) => void` | - | 否 |
| **onToggle** | `actionType='toggle'` 切换回调 | `(item: MenusItemData, selected: boolean) => void` | - | 否 |
| **onSelect** | `actionType='select'` 选择回调 | `(item: MenusItemData) => void` | - | 否 |
| **onShow** | 菜单弹出回调 | `() => void` | - | 否 |
| **onDismiss** | 菜单关闭回调 | `() => void` | - | 否 |
| **accessible** | 无障碍：是否启用 | `boolean` | `true` | 否 |

### MenusItemData

| 字段 | 说明 | 类型 | 默认值 | 必填 |
|------|------|------|--------|------|
| **id** | 唯一标识 | `string \| number` | - | 是 |
| **title** | 标题文字（最多 2 行） | `string` | - | 是 |
| **actionType** | 交互类型 | `'button' \| 'toggle' \| 'select'` | - | 是 |
| **leadingIcon** | 左侧图标，支持 SVG 组件或 Image。容器默认 24×24，支持 24-40，超过 40 自动约束到 40 | `React.ReactNode` | - | 否 |
| **leadingIconStyle** | 自定义图标容器样式，可覆盖 width/height（24-40 范围） | `StyleProp<ViewStyle>` | - | 否 |
| **disabled** | 是否禁用 | `boolean` | `false` | 否 |
| **selected** | toggle/select 的初始选中状态 | `boolean` | `false` | 否 |
| **group** | select 类型的互斥分组 key，同组只能选一个。不传归入默认组 | `string` | `'_default'` | 否 |
| **showSeparator** | 是否在该项下方显示分割线 | `boolean` | `false` | 否 |

### MenusRef

| 方法 | 说明 | 类型 |
|------|------|------|
| **showFrom** | 从触发元素附近弹出菜单 | `(triggerRef: any) => void` |

> `ColorType` 可选值：`'blue' \| 'green' \| 'wathet' \| 'purple' \| 'orange'`。

## 使用示例

```tsx
import { Menus } from 'miot/ui/hyperOSUI';
import type { MenusRef } from 'miot/ui/hyperOSUI';
import { useRef } from 'react';

const menusRef = useRef<MenusRef>(null);
const triggerRef = useRef(null);

<>
  <View ref={triggerRef} collapsable={false}>
    <IconButton onPress={() => menusRef.current?.showFrom(triggerRef.current)} />
  </View>

  <Menus
    ref={menusRef}
    data={[
      { id: 'edit', title: '编辑', actionType: 'button' },
      { id: 'mute', title: '静音', actionType: 'toggle', selected: true, showSeparator: true },
      { id: 'grid', title: '网格', actionType: 'select', group: 'layout', selected: true },
      { id: 'list', title: '列表', actionType: 'select', group: 'layout' },
    ]}
    onPress={(item) => console.log(item.id)}
    onToggle={(item, selected) => console.log(item.id, selected)}
    onSelect={(item) => console.log(item.id)}
  />
</>
```

## 注意事项

- 触发元素所在的 View 需设置 `collapsable={false}`，否则无法正确测量弹出锚点位置。
- `select` 项传入 `selectedIds` 即进入受控模式，内部不再维护选中状态；不传则按 `data` 中各项的 `selected` 初始化为非受控。
- 点击任意菜单项后菜单都会自动关闭。

## 修改记录

| 日期 | 版本 | 修改内容 | 修改原因 | 关联 |
|------|------|----------|----------|------|
| 2026-09-14 | v1.19.0 | 对齐菜单排版与几何尺寸 | — | ba3cb569 |
| 2026-09-14 | v1.19.0 | 同步组件视觉 Token | — | 5a99f324 |
| 2026-08-20 | v1.19.0 | 调整组件参数 | — | bc81b51f |
| 2026-07-20 | v1.18.17 | 118 版本组件更新 | — | feef8025 |
| 2026-06-08 | v1.18.12 | 调整选中指示器间距 | — | a1a7b0ee |
| 2026-06-04 | v1.18.12 | 优化菜单样式 | — | 12981332 |
| 2026-05-21 | v1.18.8 | 菜单项样式优化 | — | 873d087a |
| 2026-05-12 | v1.18.7 | 修复菜单相关问题 | — | 0c6e89f9 |
| 2026-04-25 | v1.18.6 | TS 类型定义规范化 | — | 1c59cbd5 |
| 2026-04-13 | v1.18.5-alpha.0 | 菜单类组件初版 | — | 7d954052 |
