fix(menu): refactor menu system to use pure config objects and fix submenu click events

This commit is contained in:
yuding
2025-12-09 18:34:43 +08:00
parent c112c87dad
commit 9ae1d9d809
38 changed files with 6756 additions and 2575 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

201
dist/index.d.ts vendored
View File

@@ -146,6 +146,7 @@ export declare class BimEngine extends EventEmitter {
buttonGroup: ButtonGroupManager | null;
dialog: DialogManager | null;
engine: EngineManager | null;
rightKey: RightKeyManager | null;
get localeManager(): LocaleManager;
get themeManager(): ThemeManager;
constructor(container: HTMLElement | string, options?: {
@@ -169,6 +170,111 @@ export declare class BimEngine extends EventEmitter {
destroy(): void;
}
/**
* 通用菜单列表组件
* 负责渲染一组菜单项,支持分组、排序、图标、快捷键提示和递归多级子菜单。
* 它不包含定位逻辑,仅负责内容渲染。
*/
export declare class BimMenu implements IBimComponent {
element: HTMLElement;
private options;
private unsubscribeLocale;
private unsubscribeTheme;
private activeSubMenu;
constructor(options: MenuOptions);
/**
* 初始化组件
* 渲染 DOM 结构并订阅语言变更
*/
init(): void;
/**
* 设置主题
* @param theme 全局主题配置
*/
setTheme(theme: ThemeConfig): void;
/**
* 响应语言变更
* 重新渲染整个菜单以更新文本
*/
setLocales(): void;
/**
* 销毁组件
* 清理事件监听、子菜单和 DOM 元素
*/
destroy(): void;
/**
* 获取组件根元素
* 实现 IRightKeyContent 接口,允许被 RightKey 容器挂载
*/
getElement(): HTMLElement;
/**
* 核心渲染逻辑
* 处理分组、排序和 DOM 生成
*/
private render;
/**
* 创建单个菜单项的 DOM 元素
*/
private createItemElement;
/**
* 打开子菜单
* @param item 当前菜单项
* @param parentLi 触发的 DOM 元素(用于定位)
*/
private openSubMenu;
/**
* 关闭当前激活的子菜单
*/
private closeSubMenu;
}
/**
* 右键浮层容器组件 (RightKey)
* 这是一个纯粹的定位容器,负责在屏幕指定位置显示内容。
* 它不关心具体内容是什么,只处理定位、边界检测和关闭逻辑。
*/
export declare class BimRightKey implements IBimComponent {
private element;
private content;
private isVisible;
private onCloseCallback?;
constructor(options?: RightKeyOptions);
init(): void;
setTheme(_theme: ThemeConfig): void;
setLocales(): void;
destroy(): void;
/**
* 设置关闭时的回调函数
* 通常用于通知 Manager 状态变更
*/
setOnClose(callback: () => void): void;
/**
* 挂载内容组件
* @param content 实现了 IRightKeyContent 接口的组件实例
*/
mount(content: IRightKeyContent): void;
/**
* 卸载当前内容
*/
unmountContent(): void;
/**
* 在指定位置显示容器
* 包含智能边界检测逻辑,防止溢出屏幕
* @param x 目标 X 坐标 (通常是鼠标点击位置)
* @param y 目标 Y 坐标
*/
show(x: number, y: number): void;
/**
* 隐藏容器
*/
hide(): void;
/**
* 处理全局点击事件
* 用于检测是否点击了容器外部
*/
private handleGlobalClick;
}
/** 按钮内部文字图标排列 */
declare type ButtonAlign = 'vertical' | 'horizontal';
@@ -249,11 +355,11 @@ export declare function createEngine(r) {
const e = r.version || "v1";
switch (e) {
case "v2":
return new Nc(r);
return new Bc(r);
case "v1":
return new I_(r);
return new N_(r);
:
return console.warn(`Version '${e}' not found. Falling back to v2.`), new Nc(r);
return console.warn(`Version '${e}' not found. Falling back to v2.`), new Bc(r);
}
}
@@ -483,6 +589,17 @@ declare interface IBimComponent {
destroy(): void;
}
declare interface IRightKeyContent {
/**
* 获取组件的根 DOM 元素
*/
getElement(): HTMLElement;
/**
* 销毁组件
*/
destroy(): void;
}
declare type Listener<T = any> = (payload: T) => void;
declare type LocaleChangeListener = (locale: LocaleType) => void;
@@ -519,6 +636,39 @@ declare class LocaleManager {
*/
declare type LocaleType = 'zh-CN' | 'en-US';
/**
* 菜单项配置接口 (用于简化的对象配置)
*/
export declare interface MenuItemConfig {
id: string;
label: string;
onClick?: () => void;
icon?: string;
group?: string;
order?: number;
children?: MenuItemConfig[];
disabled?: boolean;
visible?: boolean;
}
/**
* <20><><EFBFBD>单组件配置选项
*/
declare interface MenuOptions {
/**
* 菜单项列表
* 可以是扁平数组,组件会根据 group 字段自动分组
*/
items: MenuItemConfig[];
/**
* 分组显示顺序
* 包含组 ID 的字符串数组。
* 例如: ['view', 'edit', 'tools']
* 未在此数组中定义的组将按默认顺序排在最后。
*/
groupOrder?: string[];
}
/**
* 模型加载选项
* 用于配置模型的位置、旋转和缩放
@@ -538,6 +688,51 @@ export declare interface OptButton extends ButtonConfig {
children?: OptButton[];
}
/**
* 右键菜单管理器 (RightKeyManager)
* 负责协调右键交互流程:
* 1. 监听 Canvas/容器的 contextmenu 事件
* 2. 通过注册的处理器 (Handler) 获取需要显示的菜单项
* 3. 实例化 Menu 组件并装载到 RightKey 容器中显示
*/
declare class RightKeyManager extends BimComponent {
private container;
private rightKeyPanel;
private contextHandlers;
constructor(engine: BimEngine, container: HTMLElement);
private initEventListeners;
destroy(): void;
/**
* 注册上下文菜单处理器
* @param handler 处理函数,接收鼠标事件,返回菜单项数组
*/
registerHandler(handler: (e: MouseEvent) => MenuItemConfig[] | null): void;
/**
* 手动显示菜单
* 允许外部直接调用以显示特定的菜单,不一定依赖右键事件
* @param x 屏幕 X 坐标
* @param y 屏幕 Y 坐标
* @param items 菜单项列表
* @param groupOrder 可<><E58FAF>的分组顺序
*/
showMenu(x: number, y: number, items: MenuItemConfig[], groupOrder?: string[]): void;
/**
* 隐藏右键菜单
*/
hide(): void;
/**
* 处理右键点击事件
*/
private handleContextMenu;
}
declare interface RightKeyOptions {
/** 自定义 CSS 类名 */
className?: string;
/** 层级 (z-index) */
zIndex?: number;
}
declare type ThemeChangeListener = (theme: ThemeConfig) => void;
/**