# Menu 组件详细文档

> 本文档详细描述 Menu 组件的实现细节，包括 API、UI 结构、逻辑流程等，供 AI 根据文档重现组件。

---

## 1. 组件概述

### 1.1 基本信息
- **组件名称**: `BimMenu`
- **文件路径**: `src/components/menu/index.ts`
- **类型定义**: `src/components/menu/item.ts` (配置), `src/components/menu/types.ts` (选项)
- **样式文件**: `src/components/menu/index.css`
- **实现接口**: `IBimComponent`, `IRightKeyContent`
- **用途**: 渲染一组菜单项，支持分组、排序、图标、快捷键提示和无限级递归子菜单。
- **特点**: 纯数据驱动（基于 `MenuItemConfig`），内置国际化支持。

### 1.2 在 SDK 中的位置
- Menu 组件主要由 `RightKeyManager` 使用，作为右键菜单的内容载体。
- 也可以单独实例化并挂载到任何容器中。
- `RightKeyManager` 位于 `src/managers/right-key-manager.ts`。

---

## 2. 组件类 API 文档

### 2.1 构造函数

```typescript
constructor(options: MenuOptions)
```

**参数**:
- `options`: `MenuOptions` - 菜单配置选项

**MenuOptions 定义**:
```typescript
interface MenuOptions {
    items: MenuItemConfig[]; // 菜单项配置列表
    groupOrder?: string[];   // 分组显示顺序
}
```

**行为**:
- 创建根元素 `<ul>`
- 保存配置选项

### 2.2 公共方法

#### `init(): void`
初始化组件（实现 `IBimComponent` 接口）

**功能**:
- 调用 `render()` 渲染 DOM 结构
- 订阅语言变更：`localeManager.subscribe()`
- 订阅主题变更：`themeManager.subscribe()`（虽然目前主要通过 CSS 变量，但保留订阅以备扩展）

#### `setTheme(theme: ThemeConfig): void`
设置主题（实现 `IBimComponent` 接口）

**参数**:
- `theme`: `ThemeConfig`

**功能**:
- 将主题颜色映射到 CSS 变量
- `--bim-ui_bg_color` ← `theme.panelBackground`
- `--bim-ui_text_primary` ← `theme.textPrimary`
- `--bim-ui_border_color` ← `theme.border`
- `--bim-ui_bg_hover` ← `theme.componentHover`

#### `setLocales(): void`
设置语言（实现 `IBimComponent` 接口）

**功能**:
- 清空当前 DOM
- 重新调用 `render()`，使 `t()` 函数获取最新的翻译文本

#### `destroy(): void`
销毁组件（实现 `IBimComponent`, `IRightKeyContent` 接口）

**功能**:
- 取消语言和主题订阅
- 关闭并销毁所有打开的子菜��
- 从 DOM 中移除自身元素

#### `getElement(): HTMLElement`
获取组件根元素（实现 `IRightKeyContent` 接口）

**返回**: `HTMLElement` (根 `<ul>` 元素)

**功能**:
- 允许父容器（如 `BimRightKey`）获取并挂载此菜单

---

## 3. 分化组件说明

**BimMenu 没有子类或分化组件**。它通过递归自身来实现多级菜单。

---

## 4. Manager API 文档

参见 [RightKey 组件文档](./right-key.md) 中的 `RightKeyManager`。`BimMenu` 本身是一个纯 UI 组件，通常不直接通过 Manager 管理，而是被 `RightKeyManager` 动态创建和销毁。

---

## 5. UI 详细描述

### 5.1 DOM 结构

```html
<ul class="bim-menu">
    <!-- 分组 1 -->
    <li class="bim-menu-item [disabled]">
        <div class="bim-menu-item-icon">[SVG图标]</div>
        <div class="bim-menu-item-label">菜单文本</div>
        <!-- 如果有子菜单 -->
        <div class="bim-menu-item-arrow">
            <svg>...</svg> <!-- 右箭头 -->
        </div>
    </li>
    
    <!-- 分组分割线 -->
    <li class="bim-menu-divider"></li>
    
    <!-- 分组 2 -->
    <li class="bim-menu-item">...</li>
</ul>
```

### 5.2 CSS 类名和样式

#### `.bim-menu` (根容器)
- `display: flex`, `flex-direction: column`
- `background`: `var(--bim-ui_bg_color)`
- `border-radius: 4px`
- `padding: 4px 0`, `margin: 0`, `list-style: none` (关键：移除列表默认样式)
- `min-width: 160px`
- `box-shadow`: `0 4px 12px rgba(0,0,0,0.2)`
- `user-select: none`

#### `.bim-menu-item` (菜单项)
- `display: flex`, `align-items: center`
- `padding: 6px 12px`
- `cursor: pointer`
- `position: relative`
- `color`: `var(--bim-ui_text_primary)`

#### `.bim-menu-item:hover`
- `background-color`: `var(--bim-ui_bg_hover)`

#### `.bim-menu-item.disabled`
- `opacity: 0.5`
- `cursor: not-allowed`
- `pointer-events: none`

#### `.bim-menu-divider` (分割线)
- `height: 1px`
- `background-color`: `var(--bim-ui_border_color)`
- `margin: 4px 0`

---

## 6. 逻辑流程详细描述

### 6.1 渲染流程 (`render`)

1.  **数据分桶**: 遍历 `items`，根据 `item.group` (默认为 'default') 将菜单项放入不同的数组中。
2.  **确定顺序**:
    - 如果提供了 `groupOrder`，优先按其顺序排列组。
    - 未指定的组按遍历顺序追加。
3.  **渲染分组**:
    - 遍历排序后的组键。
    - 如果不是第一组，先插入一个 `.bim-menu-divider`。
    - 获取组内项，根据 `item.order` 升序排序。
    - 遍历组内项，如果 `item.visible !== false`，调用 `createItemElement` 创建 DOM。

### 6.2 交互流程

#### 点击事件
- **绑定**: 在 `.bim-menu-item` 上绑定 `click`。
- **逻辑**:
  - `e.stopPropagation()`: 阻止冒泡。
  - 检查 `!hasChildren`: 只有叶子节点才触发点击。
  - 调用 `item.onClick?.()`。
  - **注意**: 点击后，通常期望菜单关闭。这依赖于 `RightKeyManager` 或外部逻辑（通过 `onClick` 内部调用关闭，或者点击触发全局关闭）。

#### 子菜单展开 (`mouseenter`)
- **触发**: 鼠标移入带有子项的菜单项。
- **逻辑**:
  - 调用 `closeSubMenu()` 关闭当前可能已打开的其他子菜单。
  - 计算位置：通常位于父项右侧 (`rect.right`)，顶部对齐 (`rect.top`)。
  - 创建子菜单容器 `div` (fixed 定位, z-index 10001)。
  - **关键修复**: 在容器上绑定 `mousedown` 并 `stopPropagation`，防止触发 `BimRightKey` 的全局关闭逻辑。
  - 实例化新的 `BimMenu` (递归) 并 `init()`。
  - 将新菜单挂载到容器，容器挂载到 `document.body`。
  - 保存引用到 `this.activeSubMenu`。
  - **边界检测**: 如果右侧超出屏幕，改为向左展开。

#### 子菜单关闭
- **触发**: 鼠标移入**不带**子项的菜单项。
- **逻辑**: 调用 `closeSubMenu()`，销毁实例并移除 DOM。

---

## 7. 国际化支持

### 7.1 实现方式
- 使用 `src/services/locale.ts` 中的 `t()` 函数。
- 在 `createItemElement` 中，直接使用 `t(item.label)` 设置文本。
- 组件初始化时订阅语言变更，变更发生时清空并重绘 (`setLocales` -> `render`)。

---

## 8. 主题支持

### 8.1 变量映射
- 在 `setTheme` 中设置内联样式变量：
  - `--bim-ui_bg_color`: 面板背景
  - `--bim-ui_text_primary`: 主要文字
  - `--bim-ui_border_color`: 边框/分割线
  - `--bim-ui_bg_hover`: 悬停背景

---

## 9. 使用示例

### 9.1 数据结构示例

```typescript
const menuItems: MenuItemConfig[] = [
    {
        id: 'view',
        label: 'menu.view', // 翻译键
        group: 'view',
        children: [
            {
                id: 'home',
                label: 'menu.home',
                onClick: () => console.log('Go Home')
            }
        ]
    },
    {
        id: 'delete',
        label: 'menu.delete',
        group: 'edit',
        icon: '<svg>...</svg>',
        onClick: () => console.log('Delete')
    }
];
```

### 9.2 手动创建（通常不直接使用，而是通过 RightKeyManager）

```typescript
const menu = new BimMenu({ items: menuItems });
menu.init();
document.body.appendChild(menu.getElement());
```

---

## 10. 实现细节（供 AI 重现）

### 10.1 递归设计
组件自身不包含递归渲染 DOM 的逻辑，而是通过“交互触发”来递归实例化。即：子菜单**不是**一开始就渲染在 DOM 树中的，而是当用户鼠标悬停时，动态创建一个新的 `BimMenu` 实例并挂载到 `body` 上。这种设计避免了深层嵌套 DOM 带来的样式问题（如 `overflow: hidden` 截断子菜单）。

### 10.2 事件冲突处理
由于子菜单挂载在 `body` 上，点击子菜单在 DOM 树看来是“点击了主菜单外部”。这会触发 `BimRightKey` 的“点击外部关闭”逻辑。
**解决方案**: 子菜单容器监听 `mousedown` 并 `stopPropagation()`，欺骗 `BimRightKey` 认为点击没有发生（或者发生在内部）。

---

## 11. 类型定义

### 11.1 MenuItemConfig

```typescript
interface MenuItemConfig {
    id: string;
    label: string;
    onClick?: () => void;
    icon?: string;       // SVG 字符串
    group?: string;      // 分组标识
    order?: number;      // 排序权重
    children?: MenuItemConfig[];
    disabled?: boolean;
    visible?: boolean;
}
```

### 11.2 MenuOptions

```typescript
interface MenuOptions {
    items: MenuItemConfig[];
    groupOrder?: string[];
}
```

---

## 12. 文件清单

- `src/components/menu/index.ts`: 组件核心逻辑
- `src/components/menu/index.css`: 组件样式
- `src/components/menu/item.ts`: 仅包含类型定义 (`MenuItemConfig`)
- `src/components/menu/types.ts`: 组件选项接口

---

## 13. 更新记录

| 日期       | 修改内容                                  | 修改人       |
| ---------- | ----------------------------------------- | ------------ |
| 2024-XX-XX | 重构为纯配置对象驱动，移除 BimMenuItem 类 | AI Assistant |