--- name: popover-zero-wrapper-refactor overview: 为 Popover 组件增加显式 unwrapped 开关的"零包裹"模式(事件注入到用户触发器 vnode),并将 Tooltip/Dropdown/Select/DatePicker/RangePicker 及 AppSidebar、AppTabs、结构树等全部调用方迁移到零包裹,删除所有 .popover-trigger 相关补丁样式与 stretch-trigger 业务用法,全程保持现有行为不回归。 todos: - id: core-popover-unwrapped content: 改造 popover.vue:加 unwrapped prop、cloneVNode 注入事件与锚点指令、双分支模板 status: completed - id: migrate-derived content: 迁移 Tooltip/Dropdown/menu/Select/DatePicker/RangePicker 开启 unwrapped,删除各 index.scss 的 .popover-trigger 补丁 status: completed dependencies: - core-popover-unwrapped - id: migrate-usages content: 迁移外部使用点:AppSidebar/AppTabs 删 :deep 规则、结构树去 stretch-trigger、help-icon 开 unwrapped,用 [subagent:code-explorer] 核对全量清单 status: completed dependencies: - migrate-derived - id: demo-tests content: demo/popover.vue 补 fallback/组件触发器/事件合并三用例,新增 popover vitest 单测 status: completed dependencies: - core-popover-unwrapped - id: verify-all content: 跑 pnpm lint、fmt:check、build、test 全量验证,并人工回归四类触发场景 status: completed dependencies: - migrate-derived - migrate-usages - demo-tests --- ## 用户需求 为 fms-vue 的 Popover 组件实现"零包裹"(antdv 式事件注入)模式,并全量迁移派生组件与外部调用点,同时保证不引入性能开销。 > 执行策略:**直接迁移(非渐进)**。项目处于初期阶段,迁移成本低,不做"迁移一个验证一个",派生组件与外部使用点一次性全部开启 `unwrapped`,最后统一跑验证。`unwrapped` prop 保留默认 `false` 作为 API 兜底,但本次全量调用点均显式开启。 ## 核心功能 - Popover 新增显式 `unwrapped` prop(默认 `false`,保持现有行为):触发器插槽为单根元素/组件 vnode 时,通过 `cloneVNode` 把 6 个内部事件 handler(click/contextmenu/mouseenter/mouseleave/focusin/focusout)合并进用户 vnode,并用注入指令获取根 DOM 作为定位锚点;多根 fragment / 文本节点自动回退到现有 `span.popover-trigger` 包裹层。 - 派生组件全量迁移:Tooltip、Dropdown(含子菜单)、Select、DatePicker、RangePicker 内部显式开启 `unwrapped`,删除各自样式里的 `.popover-trigger` 布局补丁。 - 外部使用点迁移:AppSidebar / AppTabs 删除 `:deep(.popover-trigger)` 规则,结构树移除 `stretch-trigger`,FormEditPanel / TableEditPanel 的帮助图标 Popover 一并开启 `unwrapped`。 - demo 补充零包裹/fallback/事件合并用例;新增 Popover 组件单测(vitest + @vue/test-utils + jsdom)。 - 性能约束:归一化走 computed 缓存、不新增任何 watcher/observer/全局监听、`unwrapped=false` 时零额外开销。 ## 边界 - fallback 路径保留 `stretch-trigger` 与 `.popover-trigger` 样式,不做破坏性删除。 - 事件合并采用 Vue `mergeProps` 原生语义:用户 handler 先执行、内部 handler 后执行,两者都触发,不覆盖。 - 零包裹模式下 `stretch-trigger` 无意义,静默忽略。 ## 技术栈 - 现有栈:Vue 3.5.41(`