@greypan/web-ui 6.1.0 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/README.CN.md +209 -80
  2. package/README.md +189 -60
  3. package/dist/assets/menu-portal.js +1 -1
  4. package/dist/assets/menu-portal.js.map +1 -1
  5. package/dist/assets/overlay-motion.js +1 -1
  6. package/dist/assets/overlay-motion.js.map +1 -1
  7. package/dist/components/autocomplete/index.js +54 -53
  8. package/dist/components/autocomplete/index.js.map +1 -1
  9. package/dist/components/autocomplete/style.js +1 -1
  10. package/dist/components/autocomplete/style.js.map +1 -1
  11. package/dist/components/button/index.js +36 -32
  12. package/dist/components/button/index.js.map +1 -1
  13. package/dist/components/button/style.js +1 -1
  14. package/dist/components/button/style.js.map +1 -1
  15. package/dist/components/collapse/index.d.ts +29 -1
  16. package/dist/components/collapse/index.js +92 -30
  17. package/dist/components/collapse/index.js.map +1 -1
  18. package/dist/components/collapse/style.js +1 -1
  19. package/dist/components/collapse/style.js.map +1 -1
  20. package/dist/components/context-menu/index.d.ts +1 -0
  21. package/dist/components/context-menu/index.js +80 -76
  22. package/dist/components/context-menu/index.js.map +1 -1
  23. package/dist/components/dialog/index.js +6 -2
  24. package/dist/components/dialog/index.js.map +1 -1
  25. package/dist/components/dialog/style.js +1 -1
  26. package/dist/components/dialog/style.js.map +1 -1
  27. package/dist/components/drawer/index.js +24 -14
  28. package/dist/components/drawer/index.js.map +1 -1
  29. package/dist/components/drawer/style.js +1 -1
  30. package/dist/components/drawer/style.js.map +1 -1
  31. package/dist/components/dropdown/index.d.ts +1 -0
  32. package/dist/components/dropdown/index.js +65 -60
  33. package/dist/components/dropdown/index.js.map +1 -1
  34. package/dist/components/image-preview/index.d.ts +58 -0
  35. package/dist/components/image-preview/index.js +481 -0
  36. package/dist/components/image-preview/index.js.map +1 -0
  37. package/dist/components/image-preview/style.js +6 -0
  38. package/dist/components/image-preview/style.js.map +1 -0
  39. package/dist/components/index.d.ts +1 -0
  40. package/dist/components/index.js +20 -19
  41. package/dist/components/input/style.js +1 -1
  42. package/dist/components/input/style.js.map +1 -1
  43. package/dist/components/input-number/style.js +1 -1
  44. package/dist/components/input-number/style.js.map +1 -1
  45. package/dist/components/layout/index.d.ts +1 -1
  46. package/dist/components/layout/index.js +5 -3
  47. package/dist/components/layout/index.js.map +1 -1
  48. package/dist/components/layout/style.js +1 -1
  49. package/dist/components/layout/style.js.map +1 -1
  50. package/dist/components/popover/index.d.ts +1 -0
  51. package/dist/components/popover/index.js +53 -39
  52. package/dist/components/popover/index.js.map +1 -1
  53. package/dist/components/popover/style.js.map +1 -1
  54. package/dist/components/radio/index.js +18 -16
  55. package/dist/components/radio/index.js.map +1 -1
  56. package/dist/components/radio/style.js +1 -1
  57. package/dist/components/radio/style.js.map +1 -1
  58. package/dist/components/segmented/index.js +24 -22
  59. package/dist/components/segmented/index.js.map +1 -1
  60. package/dist/components/segmented/style.js +1 -1
  61. package/dist/components/segmented/style.js.map +1 -1
  62. package/dist/components/segmented-trigger/index.js +17 -15
  63. package/dist/components/segmented-trigger/index.js.map +1 -1
  64. package/dist/components/segmented-trigger/style.js +1 -1
  65. package/dist/components/segmented-trigger/style.js.map +1 -1
  66. package/dist/components/select/index.js +43 -38
  67. package/dist/components/select/index.js.map +1 -1
  68. package/dist/components/select/style.js +1 -1
  69. package/dist/components/select/style.js.map +1 -1
  70. package/dist/components/slider/index.js +32 -30
  71. package/dist/components/slider/index.js.map +1 -1
  72. package/dist/components/slider/style.js +1 -1
  73. package/dist/components/slider/style.js.map +1 -1
  74. package/dist/components/svg-draw-lines/index.js +1 -1
  75. package/dist/components/svg-draw-lines/index.js.map +1 -1
  76. package/dist/components/switch/index.js +25 -23
  77. package/dist/components/switch/index.js.map +1 -1
  78. package/dist/components/switch/style.js +1 -1
  79. package/dist/components/switch/style.js.map +1 -1
  80. package/dist/components/textarea/style.js +1 -1
  81. package/dist/components/textarea/style.js.map +1 -1
  82. package/dist/components/theme/index.js +1 -1
  83. package/dist/components/theme/index.js.map +1 -1
  84. package/dist/components/theme/style.js +1 -1
  85. package/dist/components/theme/style.js.map +1 -1
  86. package/dist/components/toast/manager.js +2 -2
  87. package/dist/components/toast/manager.js.map +1 -1
  88. package/dist/components/toast/style.js +1 -1
  89. package/dist/components/toast/style.js.map +1 -1
  90. package/dist/components/tooltip/index.d.ts +1 -0
  91. package/dist/components/tooltip/index.js +37 -33
  92. package/dist/components/tooltip/index.js.map +1 -1
  93. package/dist/components/tooltip/style.js.map +1 -1
  94. package/dist/icons/generated/radix-icons-reset.d.ts +6 -0
  95. package/dist/icons/generated/radix-icons-reset.js +10 -0
  96. package/dist/icons/generated/radix-icons-reset.js.map +1 -0
  97. package/dist/icons/index.d.ts +1 -0
  98. package/dist/icons/index.js +2 -1
  99. package/dist/shared/focus/pointer-focus.js +37 -0
  100. package/dist/shared/focus/pointer-focus.js.map +1 -0
  101. package/dist/shared/gesture/drag-gesture.js +53 -30
  102. package/dist/shared/gesture/drag-gesture.js.map +1 -1
  103. package/dist/shared/gesture/pinch-gesture.js +84 -0
  104. package/dist/shared/gesture/pinch-gesture.js.map +1 -0
  105. package/dist/shared/group-management/index.js.map +1 -1
  106. package/dist/shared/menu-portal/menu-portal.js.map +1 -1
  107. package/dist/shared/option-portal/combobox-shell.js +8 -6
  108. package/dist/shared/option-portal/combobox-shell.js.map +1 -1
  109. package/dist/shared/overlay/anchored-panel.js +33 -30
  110. package/dist/shared/overlay/anchored-panel.js.map +1 -1
  111. package/dist/shared/overlay/composition.js +57 -0
  112. package/dist/shared/overlay/composition.js.map +1 -0
  113. package/dist/shared/overlay/lifecycle.js +41 -0
  114. package/dist/shared/overlay/lifecycle.js.map +1 -0
  115. package/dist/shared/overlay/native-dialog-presence.js +15 -15
  116. package/dist/shared/overlay/native-dialog-presence.js.map +1 -1
  117. package/dist/shared/{theme → overlay}/overlay-root.js +1 -1
  118. package/dist/shared/overlay/overlay-root.js.map +1 -0
  119. package/dist/shared/overlay/overlay.js +43 -41
  120. package/dist/shared/overlay/overlay.js.map +1 -1
  121. package/dist/shared/overlay/portal.js +2 -2
  122. package/dist/shared/overlay/portal.js.map +1 -1
  123. package/dist/shared/overlay/positioning-generation.js +20 -0
  124. package/dist/shared/overlay/positioning-generation.js.map +1 -0
  125. package/dist/shared/{theme/theme-scope.js → overlay/theme-overlay-scope.js} +2 -2
  126. package/dist/shared/overlay/theme-overlay-scope.js.map +1 -0
  127. package/package.json +5 -5
  128. package/dist/shared/theme/overlay-root.js.map +0 -1
  129. package/dist/shared/theme/theme-scope.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/collapse/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n/*\n * :host 仅限 display/contain(ADR-0003)。\n * headless 内核(ADR-0039):不携带视觉样式,trigger 与内容的排版由消费者\n * 提供;这里只保留动画与三态关闭稳态必需的结构规则。\n */\n:host {\n display: block;\n}\n\n/*\n * grid 0fr↔1fr 高度动画(ADR-0038 选型):\n * 轨道行高在 0fr(收起)与 1fr(展开)间过渡,内容高度自适应、零 JS 测量;\n * inner 的 min-height/min-width 归零是轨道能收缩到 0 的必要条件,\n * overflow hidden 负责裁剪收起中的内容。\n */\n.wui-collapse-track {\n display: grid;\n grid-template-rows: 0fr;\n transition: grid-template-rows var(--wui-duration-collapse-enter, 200ms)\n var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n\n /*\n * 水平方向:块级 grid 默认撑满可用宽度,1fr 列会解析为剩余空间而非内容宽度;\n * width: max-content 让 1fr 列按内容 max-content 贡献解析(与行向 auto 高度同理),\n * 0fr 收缩依赖 inner 的 min-width: 0。\n */\n &.is-horizontal {\n grid-template-columns: 0fr;\n grid-template-rows: none;\n width: max-content;\n transition: grid-template-columns var(--wui-duration-collapse-enter, 200ms)\n var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n }\n}\n\n.wui-collapse-track[data-wui-presence='open'] {\n grid-template-rows: 1fr;\n\n &.is-horizontal {\n grid-template-columns: 1fr;\n grid-template-rows: none;\n }\n}\n\n.wui-collapse-track[data-wui-presence='closing'] {\n pointer-events: none;\n transition: grid-template-rows var(--wui-duration-collapse-exit, 160ms)\n var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n\n &.is-horizontal {\n transition: grid-template-columns var(--wui-duration-collapse-exit, 160ms)\n var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n }\n}\n\n.wui-collapse-inner {\n overflow: hidden;\n min-height: 0;\n}\n\n.is-horizontal .wui-collapse-inner {\n min-width: 0;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/collapse/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n/*\n * :host 仅限 display/contain(ADR-0003)。\n * headless 内核(ADR-0039):不携带视觉样式,trigger 与内容的排版由消费者\n * 提供;这里只保留动画与三态关闭稳态必需的结构规则。\n */\n:host {\n display: block;\n}\n\n/*\n * grid 0fr↔1fr 高度动画(ADR-0038 选型):\n * 轨道行高在 0fr(收起)与 1fr(展开)间过渡,内容高度自适应、零 JS 测量;\n * inner 的 min-height/min-width 归零是轨道能收缩到 0 的必要条件,\n * overflow hidden 负责裁剪收起中的内容。\n */\n.wui-collapse-track {\n display: grid;\n grid-template-rows: 0fr;\n transition: grid-template-rows var(--wui-duration-collapse-enter, 200ms)\n var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n\n /*\n * 水平方向:块级 grid 默认撑满可用宽度,1fr 列会解析为剩余空间而非内容宽度;\n * width: max-content 让 1fr 列按内容 max-content 贡献解析(与行向 auto 高度同理),\n * 0fr 收缩依赖 inner 的 min-width: 0。\n */\n &.is-horizontal {\n grid-template-columns: 0fr;\n grid-template-rows: none;\n width: max-content;\n transition: grid-template-columns var(--wui-duration-collapse-enter, 200ms)\n var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n }\n}\n\n.wui-collapse-track[data-wui-presence='open'] {\n grid-template-rows: 1fr;\n\n &.is-horizontal {\n grid-template-columns: 1fr;\n grid-template-rows: none;\n }\n}\n\n.wui-collapse-track[data-wui-presence='closing'] {\n pointer-events: none;\n transition: grid-template-rows var(--wui-duration-collapse-exit, 160ms)\n var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n\n &.is-horizontal {\n transition: grid-template-columns var(--wui-duration-collapse-exit, 160ms)\n var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n }\n}\n\n/*\n * peek 模式下轨道恒为 1fr(高度始终由内容驱动),裁剪长度交给 inner 的\n * max-height/max-width:这样 `peek` 与内容尺寸的较小值由 CSS 原生解析——内容不足\n * `peek` 时不残留空白,也不会被撑到 `peek`——而动画两端都是长度,可被浏览器插值\n * (fit-content 或 minmax 的关态与内容高度之间无法插值,实测会退化成跳变)。\n *\n * 注意不能限定 `:not([data-wui-presence])`:收起动画期间 presence='closing',\n * 轨道会掉回 0fr 先把内容压成 0 再弹回,动画被毁。\n */\n.wui-collapse-track[data-wui-peek] {\n grid-template-rows: 1fr;\n\n &.is-horizontal {\n grid-template-columns: 1fr;\n grid-template-rows: none;\n }\n}\n\n/*\n * peek 边缘渐隐的「活动长度」(替代直接读推导长度):\n * 关闭/收起态取推导值,展开态归 0(fallback)——渐变带因此跟随开合动画\n * 平滑出现/消失,而不是在某一帧突然出现(旧实现把 mask 限定在关闭稳态,收起动画\n * 结束才显示,表现为明显的延迟)。\n *\n * 插值依赖 `CSS.registerProperty` 把它注册成 `<length>`(见 index.ts):未注册的\n * 自定义属性是离散值、无法过渡,且不注册时「未定义」会让整条 mask-image 声明\n * 在打开态失效回退到 none,因此这里必须给 var() 显式 fallback。\n */\n.wui-collapse-inner {\n overflow: hidden;\n min-height: 0;\n\n /*\n * peek 展开/收起的过渡落在裁剪长度上;轨道静止在 1fr,只跟随 inner 的高度变化。\n * 活动长度与裁剪长度同步过渡,渐变带才能跟着开合一起淡入淡出。\n */\n transition:\n max-height var(--wui-duration-collapse-enter, 200ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n --wui-collapse-peek-edge-active var(--wui-duration-collapse-enter, 200ms)\n var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n}\n\n.is-horizontal .wui-collapse-inner {\n min-width: 0;\n\n /* 覆盖轴向,但保留活动长度的过渡——否则水平模式下渐变带不淡入淡出。 */\n transition-property: max-width, --wui-collapse-peek-edge-active;\n}\n\n.wui-collapse-track[data-wui-presence='closing'] .wui-collapse-inner {\n transition-duration: var(--wui-duration-collapse-exit, 160ms);\n}\n\n/*\n * peek 露出区域的边缘渐隐(mask-image):\n * 沿动画轴末端(默认底边、horizontal 时右边)做 alpha 渐变,让\"被裁掉的部分\"与\n * \"露出的部分\"之间柔和过渡,提示下方还有内容。设置 `peek` 即启用——渐隐长度由\n * `peek` 推导,不是独立入参。\n *\n * 长度推导:`peek * --wui-collapse-peek-edge-ratio`(默认 0.4),并夹在\n * `--wui-collapse-peek-edge-max`(默认 112px)以内,避免大 peek 算出过长的虚化带。\n * 纯 CSS 的 `calc(length * number)` —— 不需要 JS 解析单位,peek 用 rem/em 时\n * 渐隐长度自动跟着字号缩放。需要绝对长度时直接设 `--wui-collapse-peek-edge`\n * 覆盖(它优先于推导值),把比例设成 0 即可关掉渐隐。\n *\n * 渐变是四段「先陡后缓」而非线性:主体全黑延伸到渐变带起点后,前 30% 距离就\n * 掉到 0.6 alpha,65% 处 0.26,末端落到 edge-color(默认全透明)。线性渐变的\n * alpha 曲线前 40% 几乎贴着 1.0,人眼感知到的虚化远短于声明长度——实测同样\n * 50px 的带子,线性只让人觉得\"末尾一小截发虚\",先陡后缓从带子起点就明显发虚,\n * 感知长度接近翻倍。\n *\n * 渐变带的位置用百分比而非绝对长度:百分比相对 inner 的**当前渲染高度**,而该高度\n * 在动画期间随 max-height 逐帧变化——mask 字符串本身不需要插值,渲染结果会自动\n * 跟随裁剪边缘移动(实测:mask 字符串恒定,容器高度变化时渐变带跟着走)。\n * 渐变长度由活动长度变量控制,其过渡见上方说明。\n * 末端颜色由 `--wui-collapse-peek-edge-color` 覆盖(需带 alpha,mask 按 alpha 解析)。\n */\n.wui-collapse-track[data-wui-peek] .wui-collapse-inner {\n mask-image: linear-gradient(\n to bottom,\n black 0%,\n black calc(100% - var(--wui-collapse-peek-edge-active, 0px)),\n rgb(0 0 0 / 0.6) calc(100% - var(--wui-collapse-peek-edge-active, 0px) * 0.7),\n rgb(0 0 0 / 0.26) calc(100% - var(--wui-collapse-peek-edge-active, 0px) * 0.35),\n var(--wui-collapse-peek-edge-color, transparent) 100%\n );\n}\n\n.wui-collapse-track[data-wui-peek].is-horizontal .wui-collapse-inner {\n mask-image: linear-gradient(\n to right,\n black 0%,\n black calc(100% - var(--wui-collapse-peek-edge-active, 0px)),\n rgb(0 0 0 / 0.6) calc(100% - var(--wui-collapse-peek-edge-active, 0px) * 0.7),\n rgb(0 0 0 / 0.26) calc(100% - var(--wui-collapse-peek-edge-active, 0px) * 0.35),\n var(--wui-collapse-peek-edge-color, transparent) 100%\n );\n}\n\n/*\n * 裁剪长度只在关闭稳态由 CSS 声明;动画期间由内联长度覆盖,落稳态清除后回到这里。\n * 下面几条 peek 规则按选择器特异性升序排列(`no-descending-specificity`):\n * 不带 presence 限定的两条 mask 在最前,horizontal 的裁剪(多一个类)在最后。\n */\n.wui-collapse-track[data-wui-peek]:not([data-wui-presence]) .wui-collapse-inner {\n max-height: var(--wui-collapse-peek, 0);\n}\n\n/*\n * 非展开态(关闭稳态 + 收起动画进行中)让活动长度取推导值:\n * 收起动画一开始渐变带就开始淡入,与裁剪长度同步,而不是落稳态才出现。\n * 展开态(presence='open')不命中 → 活动长度回落到 0 → mask 整段不透明,\n * 完全展开的内容不再有底部淡出。\n *\n * 推导写成 `var(--wui-collapse-peek-edge, <推导式>)`:显式设了长度就听调用方的,\n * 没设才按比例算——逃生舱仍然是纯 CSS 变量,不占组件属性名额。\n */\n.wui-collapse-track[data-wui-peek]:not([data-wui-presence='open']) .wui-collapse-inner {\n --wui-collapse-peek-edge-active: var(\n --wui-collapse-peek-edge,\n clamp(\n 0px,\n calc(var(--wui-collapse-peek, 0px) * var(--wui-collapse-peek-edge-ratio, 0.4)),\n var(--wui-collapse-peek-edge-max, 112px)\n )\n );\n}\n\n.wui-collapse-track[data-wui-peek]:not([data-wui-presence]).is-horizontal .wui-collapse-inner {\n max-width: var(--wui-collapse-peek, 0);\n}\n"],"mappings":""}
@@ -21,6 +21,7 @@ export declare class WebUiContextMenu extends LitElement {
21
21
  private _restoreFocusTarget?;
22
22
  private _shouldOpenInstantly;
23
23
  private _refreshScheduled;
24
+ private readonly _menuPositionGeneration;
24
25
  private readonly _contentObserver;
25
26
  get isOpen(): boolean;
26
27
  connectedCallback(): void;
@@ -1,25 +1,29 @@
1
1
  import e from "../../_virtual/_@oxc-project_runtime@0.146.0/helpers/esm/decorate.js";
2
2
  import { dispatchOpenChangeEvent as t } from "../../shared/open-state/index.js";
3
- import { computePosition as n, shift as r } from "../../node_modules/.pnpm/@floating-ui_dom@1.8.0/node_modules/@floating-ui/dom/dist/floating-ui.dom.js";
4
- import { hideOverlayPresence as i, showOverlayPresence as a } from "../../shared/overlay/presence.js";
5
- import { defineScrollLockLease as o } from "../../shared/scroll-lock/scroll-lock.js";
6
- import { UserChangeController as s } from "../../shared/events/user-change.js";
3
+ import { overlayComposition as n } from "../../shared/overlay/composition.js";
4
+ import { computePosition as r, shift as i } from "../../node_modules/.pnpm/@floating-ui_dom@1.8.0/node_modules/@floating-ui/dom/dist/floating-ui.dom.js";
5
+ import { defineOverlayPositioningGeneration as a } from "../../shared/overlay/positioning-generation.js";
6
+ import { hideOverlayPresence as o, showOverlayPresence as s } from "../../shared/overlay/presence.js";
7
+ import { defineScrollLockLease as c } from "../../shared/scroll-lock/scroll-lock.js";
8
+ import { UserChangeController as l } from "../../shared/events/user-change.js";
7
9
  import "../dropdown-divider/index.js";
8
10
  import "../dropdown-header/index.js";
9
11
  import "../dropdown-item/index.js";
10
- import { captureFrameworkAnchors as c, focusMenuItem as l, getMenuChildren as u, getMenuItemFromEvent as d, hideNestedMenuChildren as f, moveMenuChildren as p, orderManagedMenuItems as m, reconcileManagedMenuItems as h, restoreFrameworkAnchors as g, returnManagedMenuItemsToSlot as _ } from "../../shared/menu-portal/menu-tree.js";
11
- import { createClosingSubmenuStack as v, createMenuHoverBinder as y, createMenuOutsideClickGuard as b, getEnabledMenuLevelItems as x, getFocusedMenuItemFromPanels as S, handleMenuKeyboard as C } from "../../shared/menu-behavior/index.js";
12
- import { createMenuPortalOverlay as w } from "../../shared/menu-portal/menu-portal.js";
13
- import T from "./style.js";
14
- import { LitElement as E, html as D, unsafeCSS as O } from "lit";
15
- import { customElement as k, property as A, state as j } from "lit/decorators.js";
12
+ import { captureFrameworkAnchors as u, focusMenuItem as d, getMenuChildren as f, getMenuItemFromEvent as p, hideNestedMenuChildren as m, moveMenuChildren as h, orderManagedMenuItems as g, reconcileManagedMenuItems as _, restoreFrameworkAnchors as v, returnManagedMenuItemsToSlot as y } from "../../shared/menu-portal/menu-tree.js";
13
+ import { createClosingSubmenuStack as b, createMenuHoverBinder as x, createMenuOutsideClickGuard as S, getEnabledMenuLevelItems as C, getFocusedMenuItemFromPanels as w, handleMenuKeyboard as T } from "../../shared/menu-behavior/index.js";
14
+ import { createMenuPortalOverlay as E } from "../../shared/menu-portal/menu-portal.js";
15
+ import D from "./style.js";
16
+ import { LitElement as O, html as k, unsafeCSS as A } from "lit";
17
+ import { customElement as j, property as M, state as N } from "lit/decorators.js";
16
18
  //#region src/components/context-menu/index.ts
17
- var M = "wui-context-menu-item", N = class extends E {
19
+ var P = "wui-context-menu-item", F = class extends O {
18
20
  constructor(...e) {
19
- super(...e), this.disabled = !1, this.noScrollLock = !1, this._isOpen = !1, this._x = 0, this._y = 0, this._activeSubmenus = [], this._activeSubmenuItems = [], this._submenuPositionEpochs = /* @__PURE__ */ new WeakMap(), this._outsideClickGuard = b(this, (e) => this._menu?.panel.contains(e) === !0 || this._activeSubmenus.some((t) => t.panel.contains(e))), this._closingSubmenus = v({
21
+ super(...e), this.disabled = !1, this.noScrollLock = !1, this._isOpen = !1, this._x = 0, this._y = 0, this._activeSubmenus = [], this._activeSubmenuItems = [], this._submenuPositionEpochs = /* @__PURE__ */ new WeakMap(), this._outsideClickGuard = S(this, (e) => [this._menu?.panel, ...this._activeSubmenus.map((e) => e.panel)].filter((e) => e instanceof HTMLElement).some((t) => n.contains(t, e))), this._closingSubmenus = b({
20
22
  getPanel: (e) => e.panel,
21
23
  restoreItems: (e, t) => this._restoreSubmenuItems(e, t),
22
- dispose: (e) => e.panel.remove()
24
+ dispose: (e) => {
25
+ n.unregisterPanel(e.panel), e.panel.remove();
26
+ }
23
27
  }), this._hoverDelegate = {
24
28
  getOpenDepth: () => this._activeSubmenus.length,
25
29
  getLevelItems: (e) => this._getLevelItems(e),
@@ -29,13 +33,13 @@ var M = "wui-context-menu-item", N = class extends E {
29
33
  closeFrom: (e) => {
30
34
  this._closeSubmenusFrom(e), this._hoverBinder.bind();
31
35
  }
32
- }, this._hoverBinder = y(this._hoverDelegate, "web-ui-dropdown-item"), this._keyboardDelegate = {
33
- getFocusedItem: (e) => S(e, [this._menu?.content, ...this._activeSubmenus.map((e) => e.content)], "web-ui-dropdown-item"),
36
+ }, this._hoverBinder = x(this._hoverDelegate, "web-ui-dropdown-item"), this._keyboardDelegate = {
37
+ getFocusedItem: (e) => w(e, [this._menu?.content, ...this._activeSubmenus.map((e) => e.content)], "web-ui-dropdown-item"),
34
38
  getLevelOf: (e) => {
35
39
  let t = this._getItemLevel(e);
36
40
  return t === -1 ? void 0 : t;
37
41
  },
38
- getEnabledItems: (e) => x(this._getLevelContainer(e)?.content),
42
+ getEnabledItems: (e) => C(this._getLevelContainer(e)?.content),
39
43
  isSubmenuItem: (e) => e.hasAttribute("submenu"),
40
44
  openSubmenuInstant: (e) => this._openSubmenu(e, !0),
41
45
  closeToParent: (e) => {
@@ -43,7 +47,7 @@ var M = "wui-context-menu-item", N = class extends E {
43
47
  return this._closeSubmenusFrom(e - 1), this._hoverBinder.bind(), t;
44
48
  },
45
49
  closeDeepestOrAll: () => this._closeLastSubmenuOrMenu()
46
- }, this._menuItemAnchors = /* @__PURE__ */ new Map(), this._scrollLock = o().make(), this._userOpenChange = new s(), this._shouldOpenInstantly = !0, this._refreshScheduled = !1, this._contentObserver = new MutationObserver(() => {
50
+ }, this._menuItemAnchors = /* @__PURE__ */ new Map(), this._scrollLock = c().make(), this._userOpenChange = new l(), this._shouldOpenInstantly = !0, this._refreshScheduled = !1, this._menuPositionGeneration = a().make(), this._contentObserver = new MutationObserver(() => {
47
51
  this._isOpen && this._scheduleRefresh();
48
52
  }), this._closeFromUser = () => {
49
53
  this._isOpen && (this._userOpenChange.mark(), this.close());
@@ -64,7 +68,7 @@ var M = "wui-context-menu-item", N = class extends E {
64
68
  }, this._onClickOutside = (e) => {
65
69
  !this._isOpen || this._outsideClickGuard.isArmed() || this._outsideClickGuard.isInside(e) || this._closeFromUser();
66
70
  }, this._onMenuClick = (e) => {
67
- let t = d(e);
71
+ let t = p(e);
68
72
  if (!(!t || t.hasAttribute("disabled"))) {
69
73
  if (t.hasAttribute("submenu")) {
70
74
  this._openSubmenu(t);
@@ -77,11 +81,11 @@ var M = "wui-context-menu-item", N = class extends E {
77
81
  }, this._onTouchMove = (e) => {
78
82
  this._preventBackgroundScroll(e);
79
83
  }, this._onDocumentKeydown = (e) => {
80
- this._isOpen && C(this._keyboardDelegate, e);
84
+ this._isOpen && T(this._keyboardDelegate, e);
81
85
  };
82
86
  }
83
87
  static {
84
- this.styles = O(T);
88
+ this.styles = A(D);
85
89
  }
86
90
  get isOpen() {
87
91
  return this._isOpen;
@@ -96,28 +100,28 @@ var M = "wui-context-menu-item", N = class extends E {
96
100
  }), document.addEventListener("keydown", this._onDocumentKeydown);
97
101
  }
98
102
  disconnectedCallback() {
99
- super.disconnectedCallback(), this.removeEventListener("contextmenu", this._onContextMenu), this.removeEventListener("keydown", this._onKeydown), this.removeEventListener("click", this._onMenuClick), document.removeEventListener("click", this._onClickOutside), document.removeEventListener("contextmenu", this._onContextMenuOutside), document.removeEventListener("wheel", this._onWheel, !0), document.removeEventListener("touchmove", this._onTouchMove, !0), document.removeEventListener("keydown", this._onDocumentKeydown), this._contentObserver.disconnect(), this._outsideClickGuard.dispose(), this._hoverBinder.dispose(), this._scrollLock.release(), this._returnItemsToSlot(), this._menu?.panel.remove(), this._menu = void 0, this._closeSubmenusFrom(0, !0), this._closingSubmenus.restoreAll(), this._isOpen = !1, this._restoreFocusTarget = void 0;
103
+ super.disconnectedCallback(), this.removeEventListener("contextmenu", this._onContextMenu), this.removeEventListener("keydown", this._onKeydown), this.removeEventListener("click", this._onMenuClick), document.removeEventListener("click", this._onClickOutside), document.removeEventListener("contextmenu", this._onContextMenuOutside), document.removeEventListener("wheel", this._onWheel, !0), document.removeEventListener("touchmove", this._onTouchMove, !0), document.removeEventListener("keydown", this._onDocumentKeydown), this._contentObserver.disconnect(), this._menuPositionGeneration.invalidate(), this._outsideClickGuard.dispose(), this._hoverBinder.dispose(), this._scrollLock.release(), this._menu && n.unregisterPanel(this._menu.panel), this._returnItemsToSlot(), this._menu?.panel.remove(), this._menu = void 0, this._closeSubmenusFrom(0, !0), this._closingSubmenus.restoreAll(), this._isOpen = !1, this._restoreFocusTarget = void 0;
100
104
  }
101
105
  updated(e) {
102
106
  if (!this.isConnected) {
103
107
  this._syncScrollLock(!1);
104
108
  return;
105
109
  }
106
- e.has("_isOpen") && (this._isOpen ? (this._syncScrollLock(), this._menu || (this._menu = w("context-menu", this), this._menu.panel.setAttribute("role", "menu"), this._menu.panel.setAttribute("aria-label", "上下文菜单"), this._menu.panel.addEventListener("click", this._onMenuClick)), this._contentObserver.observe(this._menu.content, {
110
+ e.has("_isOpen") && (this._isOpen ? (this._syncScrollLock(), this._menu || (this._menu = E("context-menu", this), this._menu.panel.setAttribute("role", "menu"), this._menu.panel.setAttribute("aria-label", "上下文菜单"), this._menu.panel.addEventListener("click", this._onMenuClick), n.registerPanel(this._menu.panel)), this._contentObserver.observe(this._menu.content, {
107
111
  childList: !0,
108
112
  subtree: !0
109
113
  }), requestAnimationFrame(() => {
110
- !this._isOpen || !this._menu || (this._refreshMenu(), a(this._menu.panel, { isInstant: this._shouldOpenInstantly }), this._shouldOpenInstantly = !0, this._focusFirstItem());
111
- })) : (this._syncScrollLock(!1), this._contentObserver.disconnect(), this._refreshScheduled = !1, this._closeMenuAfterPresence()), this._userOpenChange.consume() && this._dispatchChange(this._isOpen)), e.has("noScrollLock") && this._syncScrollLock();
114
+ !this._isOpen || !this._menu || (this._refreshMenu(), s(this._menu.panel, { isInstant: this._shouldOpenInstantly }), this._shouldOpenInstantly = !0, this._focusFirstItem());
115
+ })) : (this._syncScrollLock(!1), this._contentObserver.disconnect(), this._menuPositionGeneration.invalidate(), this._refreshScheduled = !1, this._closeMenuAfterPresence()), this._userOpenChange.consume() && this._dispatchChange(this._isOpen)), e.has("noScrollLock") && this._syncScrollLock();
112
116
  }
113
117
  openAt(e, t) {
114
118
  this._openAt(e, t, !0);
115
119
  }
116
120
  _openAt(e, t, n) {
117
- return !this.disabled && (this._x = e, this._y = t, this._shouldOpenInstantly = n, this._outsideClickGuard.arm(), this._isOpen ? (this._closeSubmenusFrom(0, !0), this._closingSubmenus.restoreAll(), this._scheduleRefresh(), !1) : (this._restoreFocusTarget ??= document.activeElement instanceof HTMLElement ? document.activeElement : void 0, this._isOpen = !0, !0));
121
+ return !this.disabled && (this._x = e, this._y = t, this._shouldOpenInstantly = n, this._outsideClickGuard.arm(), this._isOpen ? (this._closeSubmenusFrom(0, !0), this._closingSubmenus.restoreAll(), this._menuPositionGeneration.invalidate(), this._scheduleRefresh(), !1) : (this._restoreFocusTarget ??= document.activeElement instanceof HTMLElement ? document.activeElement : void 0, this._isOpen = !0, !0));
118
122
  }
119
123
  close() {
120
- this._isOpen &&= !1;
124
+ this._isOpen && (this._isOpen = !1, this._menuPositionGeneration.invalidate());
121
125
  }
122
126
  _scheduleRefresh() {
123
127
  this._refreshScheduled || !this._isOpen || (this._refreshScheduled = !0, requestAnimationFrame(() => {
@@ -129,24 +133,24 @@ var M = "wui-context-menu-item", N = class extends E {
129
133
  }
130
134
  _positionMenu() {
131
135
  let e = this._menu?.panel;
132
- if (e) {
133
- if (e.style.visibility = "hidden", e.style.display = "", !(e.parentElement instanceof HTMLDialogElement && e.parentElement.open)) {
134
- this._positionMenuInViewport(e);
135
- return;
136
- }
137
- n({ getBoundingClientRect: () => new DOMRect(this._x, this._y, 0, 0) }, e, {
138
- strategy: "fixed",
139
- placement: "bottom-start",
140
- middleware: [r({
141
- padding: 8,
142
- crossAxis: !0
143
- })]
144
- }).then(({ x: t, y: n, middlewareData: r }) => {
145
- if (!this._isOpen || this._menu?.panel !== e) return;
146
- let i = r.shift?.x ?? 0, a = r.shift?.y ?? 0;
147
- this._applyMenuPosition(e, t, n, i < 0 ? "right" : "left", a < 0 ? "bottom" : "top");
148
- });
136
+ if (!e) return;
137
+ if (e.style.visibility = "hidden", e.style.display = "", !(e.parentElement instanceof HTMLDialogElement && e.parentElement.open)) {
138
+ this._positionMenuInViewport(e);
139
+ return;
149
140
  }
141
+ let t = this._menuPositionGeneration.next();
142
+ r({ getBoundingClientRect: () => new DOMRect(this._x, this._y, 0, 0) }, e, {
143
+ strategy: "fixed",
144
+ placement: "bottom-start",
145
+ middleware: [i({
146
+ padding: 8,
147
+ crossAxis: !0
148
+ })]
149
+ }).then(({ x: n, y: r, middlewareData: i }) => {
150
+ if (!this._isOpen || this._menu?.panel !== e || !this._menuPositionGeneration.isCurrent(t)) return;
151
+ let a = i.shift?.x ?? 0, o = i.shift?.y ?? 0;
152
+ this._applyMenuPosition(e, n, r, a < 0 ? "right" : "left", o < 0 ? "bottom" : "top");
153
+ });
150
154
  }
151
155
  _positionMenuInViewport(e) {
152
156
  let { width: t, height: n } = e.getBoundingClientRect(), r = window.innerWidth, i = window.innerHeight, a = this._x, o = this._y;
@@ -159,50 +163,50 @@ var M = "wui-context-menu-item", N = class extends E {
159
163
  }
160
164
  _focusFirstItem() {
161
165
  let e = this._menu?.content.querySelectorAll("web-ui-dropdown-item:not([disabled])")?.[0];
162
- e && l(e);
166
+ e && d(e);
163
167
  }
164
168
  _setupMenuItems() {
165
169
  let e = this._menu;
166
170
  if (!e) return;
167
171
  let t = e.content;
168
- h(this, t, this._menuItemAnchors, M), this._hideMenuItems(), f(t, "context-menu-hidden");
169
- let n = c(t, M);
170
- m(this, t, this._menuItemAnchors, M), g(t, n);
172
+ _(this, t, this._menuItemAnchors, P), this._hideMenuItems(), m(t, "context-menu-hidden");
173
+ let n = u(t, P);
174
+ g(this, t, this._menuItemAnchors, P), v(t, n);
171
175
  }
172
176
  _returnItemsToSlot() {
173
177
  let e = this._menu;
174
- e && (this._closeSubmenusFrom(0, !0), this._closingSubmenus.restoreAll(), _(this, e.content, this._menuItemAnchors));
178
+ e && (this._closeSubmenusFrom(0, !0), this._closingSubmenus.restoreAll(), y(this, e.content, this._menuItemAnchors));
175
179
  }
176
180
  async _closeMenuAfterPresence() {
177
181
  let e = this._menu;
178
- e && !await i(e.panel) || this._isOpen || !this.isConnected || this._menu !== e || (this._returnItemsToSlot(), e?.panel.remove(), this._menu = void 0, this._restoreFocusTarget?.focus(), this._restoreFocusTarget = void 0);
182
+ e && !await o(e.panel) || this._isOpen || !this.isConnected || this._menu !== e || (e && n.unregisterPanel(e.panel), this._returnItemsToSlot(), e?.panel.remove(), this._menu = void 0, this._restoreFocusTarget?.focus(), this._restoreFocusTarget = void 0);
179
183
  }
180
184
  _hideMenuItems() {
181
- u(this).forEach((e) => e.setAttribute("slot", "context-menu-hidden")), f(this, "context-menu-hidden");
185
+ f(this).forEach((e) => e.setAttribute("slot", "context-menu-hidden")), m(this, "context-menu-hidden");
182
186
  }
183
187
  _openSubmenu(e, t = !1) {
184
188
  if (!this._isOpen || !e.hasAttribute("submenu") || e.hasAttribute("disabled")) return;
185
- let n = this._getItemLevel(e);
186
- if (n === -1 || this._activeSubmenuItems[n] === e) return;
187
- this._closeSubmenusFrom(n);
188
- let r = this._closingSubmenus.take(e);
189
- if (r) {
190
- this._activeSubmenus[n] = r, this._activeSubmenuItems[n] = e, e.setAttribute("active", ""), this._positionSubmenu(e, r), a(r.panel, { isInstant: t }), this._hoverBinder.bind();
189
+ let r = this._getItemLevel(e);
190
+ if (r === -1 || this._activeSubmenuItems[r] === e) return;
191
+ this._closeSubmenusFrom(r);
192
+ let i = this._closingSubmenus.take(e);
193
+ if (i) {
194
+ this._activeSubmenus[r] = i, this._activeSubmenuItems[r] = e, e.setAttribute("active", ""), this._positionSubmenu(e, i), s(i.panel, { isInstant: t }), this._hoverBinder.bind();
191
195
  return;
192
196
  }
193
- if (u(e).length === 0) return;
194
- let i = w("context-submenu", this);
195
- i.panel.dataset.level = String(n), i.panel.setAttribute("role", "menu"), i.panel.setAttribute("aria-label", "子菜单"), i.panel.style.visibility = "hidden", i.panel.addEventListener("click", this._onMenuClick), p(e, i.content), this._activeSubmenus[n] = i, this._activeSubmenuItems[n] = e, e.setAttribute("active", ""), this._positionSubmenu(e, i), a(i.panel, { isInstant: t }), this._hoverBinder.bind();
197
+ if (f(e).length === 0) return;
198
+ let a = E("context-submenu", this);
199
+ a.panel.dataset.level = String(r), a.panel.setAttribute("role", "menu"), a.panel.setAttribute("aria-label", "子菜单"), a.panel.style.visibility = "hidden", a.panel.addEventListener("click", this._onMenuClick), h(e, a.content), this._activeSubmenus[r] = a, this._activeSubmenuItems[r] = e, n.registerPanel(a.panel, r === 0 ? this._menu?.panel : this._activeSubmenus[r - 1]?.panel), e.setAttribute("active", ""), this._positionSubmenu(e, a), s(a.panel, { isInstant: t }), this._hoverBinder.bind();
196
200
  }
197
201
  _closeSubmenusFrom(e, t = !1) {
198
- for (let n = this._activeSubmenus.length - 1; n >= e; n--) {
199
- let e = this._activeSubmenus[n], r = this._activeSubmenuItems[n];
200
- r?.removeAttribute("active"), !r || t ? (this._restoreSubmenuItems(e, r), e.panel.remove()) : this._closingSubmenus.closeAsync(r, e);
202
+ for (let r = this._activeSubmenus.length - 1; r >= e; r--) {
203
+ let e = this._activeSubmenus[r], i = this._activeSubmenuItems[r];
204
+ i?.removeAttribute("active"), !i || t ? (e && n.unregisterPanel(e.panel), this._restoreSubmenuItems(e, i), e.panel.remove()) : this._closingSubmenus.closeAsync(i, e);
201
205
  }
202
206
  this._activeSubmenus.length = e, this._activeSubmenuItems.length = e;
203
207
  }
204
208
  _restoreSubmenuItems(e, t) {
205
- t && (p(e.content, t), f(t, "context-menu-hidden"));
209
+ t && (h(e.content, t), m(t, "context-menu-hidden"));
206
210
  }
207
211
  _getItemLevel(e) {
208
212
  if (this._menu?.panel.contains(e)) return 0;
@@ -211,11 +215,11 @@ var M = "wui-context-menu-item", N = class extends E {
211
215
  }
212
216
  _positionSubmenu(e, t) {
213
217
  if (t.panel.parentElement instanceof HTMLDialogElement && t.panel.parentElement.open) {
214
- let i = e.getBoundingClientRect().right + t.panel.getBoundingClientRect().width + 8 <= window.innerWidth, a = (this._submenuPositionEpochs.get(t.panel) ?? 0) + 1;
215
- this._submenuPositionEpochs.set(t.panel, a), n(e, t.panel, {
218
+ let n = e.getBoundingClientRect().right + t.panel.getBoundingClientRect().width + 8 <= window.innerWidth, a = (this._submenuPositionEpochs.get(t.panel) ?? 0) + 1;
219
+ this._submenuPositionEpochs.set(t.panel, a), r(e, t.panel, {
216
220
  strategy: "fixed",
217
- placement: i ? "right-start" : "left-start",
218
- middleware: [r({
221
+ placement: n ? "right-start" : "left-start",
222
+ middleware: [i({
219
223
  padding: 8,
220
224
  crossAxis: !0
221
225
  })]
@@ -226,7 +230,7 @@ var M = "wui-context-menu-item", N = class extends E {
226
230
  });
227
231
  return;
228
232
  }
229
- let i = e.getBoundingClientRect(), a = t.panel.getBoundingClientRect(), o = i.right + a.width + 8 <= window.innerWidth, s = o ? i.right : Math.max(8, i.left - a.width), c = Math.min(Math.max(8, i.top), window.innerHeight - a.height - 8);
233
+ let n = e.getBoundingClientRect(), a = t.panel.getBoundingClientRect(), o = n.right + a.width + 8 <= window.innerWidth, s = o ? n.right : Math.max(8, n.left - a.width), c = Math.min(Math.max(8, n.top), window.innerHeight - a.height - 8);
230
234
  t.panel.style.left = `${s}px`, t.panel.style.top = `${c}px`, t.panel.style.setProperty("--wui-internal-overlay-transform-origin", o ? "top left" : "top right"), t.panel.style.visibility = "";
231
235
  }
232
236
  _dispatchChange(e) {
@@ -237,12 +241,12 @@ var M = "wui-context-menu-item", N = class extends E {
237
241
  }
238
242
  _getLevelItems(e) {
239
243
  let t = this._getLevelContainer(e);
240
- return t ? u(t.content) : [];
244
+ return t ? f(t.content) : [];
241
245
  }
242
246
  _closeLastSubmenuOrMenu() {
243
247
  if (this._activeSubmenus.length > 0) {
244
248
  let e = this._activeSubmenus.length - 1, t = this._activeSubmenuItems[e];
245
- this._closeSubmenusFrom(e), l(t), this._hoverBinder.bind();
249
+ this._closeSubmenusFrom(e), d(t), this._hoverBinder.bind();
246
250
  } else this._closeFromUser();
247
251
  }
248
252
  _preventBackgroundScroll(e) {
@@ -252,10 +256,10 @@ var M = "wui-context-menu-item", N = class extends E {
252
256
  this._scrollLock.sync(e && !this.noScrollLock);
253
257
  }
254
258
  _isMenuPanelEvent(e) {
255
- return e.composedPath().some((e) => e instanceof HTMLElement && (e.classList.contains("context-menu") || e.classList.contains("context-submenu")));
259
+ return [this._menu?.panel, ...this._activeSubmenus.map((e) => e.panel)].filter((e) => e instanceof HTMLElement).some((t) => n.containsEvent(t, e));
256
260
  }
257
261
  render() {
258
- return D`
262
+ return k`
259
263
  <div class="context-menu-anchor">
260
264
  <slot @slotchange=${this._onSlotChange}></slot>
261
265
  </div>
@@ -265,15 +269,15 @@ var M = "wui-context-menu-item", N = class extends E {
265
269
  this._hideMenuItems(), this._isOpen && this._scheduleRefresh();
266
270
  }
267
271
  };
268
- e([A({
272
+ e([M({
269
273
  type: Boolean,
270
274
  reflect: !0
271
- })], N.prototype, "disabled", void 0), e([A({
275
+ })], F.prototype, "disabled", void 0), e([M({
272
276
  type: Boolean,
273
277
  reflect: !0,
274
278
  attribute: "no-scroll-lock"
275
- })], N.prototype, "noScrollLock", void 0), e([j()], N.prototype, "_isOpen", void 0), e([j()], N.prototype, "_x", void 0), e([j()], N.prototype, "_y", void 0), N = e([k("web-ui-context-menu")], N);
279
+ })], F.prototype, "noScrollLock", void 0), e([N()], F.prototype, "_isOpen", void 0), e([N()], F.prototype, "_x", void 0), e([N()], F.prototype, "_y", void 0), F = e([j("web-ui-context-menu")], F);
276
280
  //#endregion
277
- export { N as WebUiContextMenu };
281
+ export { F as WebUiContextMenu };
278
282
 
279
283
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/context-menu/index.ts"],"sourcesContent":["import { computePosition, shift } from '@floating-ui/dom'\nimport { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport '@/components/dropdown-divider'\nimport '@/components/dropdown-header'\nimport '@/components/dropdown-item'\nimport { UserChangeController } from '@/shared/events/user-change'\nimport {\n createClosingSubmenuStack,\n createMenuHoverBinder,\n createMenuOutsideClickGuard,\n getEnabledMenuLevelItems,\n getFocusedMenuItemFromPanels,\n handleMenuKeyboard,\n type MenuHoverDelegate,\n type MenuKeyboardDelegate\n} from '@/shared/menu-behavior'\nimport { createMenuPortalOverlay, type MenuPortalOverlay } from '@/shared/menu-portal/menu-portal'\nimport {\n captureFrameworkAnchors,\n focusMenuItem,\n getMenuChildren,\n getMenuItemFromEvent,\n hideNestedMenuChildren,\n moveMenuChildren,\n orderManagedMenuItems,\n reconcileManagedMenuItems,\n restoreFrameworkAnchors,\n returnManagedMenuItemsToSlot\n} from '@/shared/menu-portal/menu-tree'\nimport { dispatchOpenChangeEvent } from '@/shared/open-state'\nimport { hideOverlayPresence, showOverlayPresence } from '@/shared/overlay/presence'\nimport { defineScrollLockLease } from '@/shared/scroll-lock/scroll-lock'\n\nimport style from './style.css?inline'\n\nconst MARKER_TEXT = 'wui-context-menu-item'\n\n@customElement('web-ui-context-menu')\nexport class WebUiContextMenu extends LitElement {\n static override styles = unsafeCSS(style)\n\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true, attribute: 'no-scroll-lock' }) noScrollLock = false\n\n @state() private _isOpen = false\n @state() private _x = 0\n @state() private _y = 0\n\n private _activeSubmenus: MenuPortalOverlay[] = []\n private _activeSubmenuItems: HTMLElement[] = []\n // 子菜单 dialog 定位的唯一写者代数(按 panel 键控):同帧关闭→重开复用同一 panel\n // 时只允许最新一次定位写入;不同层级子菜单各有 panel,互不作废。\n private readonly _submenuPositionEpochs = new WeakMap<HTMLElement, number>()\n private _menu?: MenuPortalOverlay\n // 行为层(hover / outside-click / 键盘 / submenu 收尾)由 shared/menu-behavior 驱动\n private readonly _outsideClickGuard = createMenuOutsideClickGuard(\n this,\n node => this._menu?.panel.contains(node) === true || this._activeSubmenus.some(menu => menu.panel.contains(node))\n )\n private readonly _closingSubmenus = createClosingSubmenuStack<MenuPortalOverlay>({\n getPanel: container => container.panel,\n restoreItems: (container, parentItem) => this._restoreSubmenuItems(container, parentItem),\n dispose: container => container.panel.remove()\n })\n private readonly _hoverDelegate: MenuHoverDelegate = {\n getOpenDepth: () => this._activeSubmenus.length,\n getLevelItems: level => this._getLevelItems(level),\n getActiveItem: level => this._activeSubmenuItems[level],\n isSubmenuItem: item => item.hasAttribute('submenu'),\n openSubmenu: item => this._openSubmenu(item),\n closeFrom: level => {\n this._closeSubmenusFrom(level)\n this._hoverBinder.bind()\n }\n }\n private readonly _hoverBinder = createMenuHoverBinder(this._hoverDelegate, 'web-ui-dropdown-item')\n private readonly _keyboardDelegate: MenuKeyboardDelegate = {\n getFocusedItem: event =>\n getFocusedMenuItemFromPanels(\n event,\n [this._menu?.content, ...this._activeSubmenus.map(submenu => submenu.content)],\n 'web-ui-dropdown-item'\n ),\n getLevelOf: item => {\n const level = this._getItemLevel(item)\n return level === -1 ? undefined : level\n },\n getEnabledItems: level => getEnabledMenuLevelItems(this._getLevelContainer(level)?.content),\n isSubmenuItem: item => item.hasAttribute('submenu'),\n openSubmenuInstant: item => this._openSubmenu(item, true),\n closeToParent: level => {\n const parent = this._activeSubmenuItems[level - 1]\n this._closeSubmenusFrom(level - 1)\n this._hoverBinder.bind()\n return parent\n },\n closeDeepestOrAll: () => this._closeLastSubmenuOrMenu()\n }\n private readonly _menuItemAnchors = new Map<HTMLElement, Comment>()\n private readonly _scrollLock = defineScrollLockLease().make()\n private readonly _userOpenChange = new UserChangeController()\n private _restoreFocusTarget?: HTMLElement\n private _shouldOpenInstantly = true\n private _refreshScheduled = false\n // 菜单打开期间宿主可能不经重定位直接改写子内容(网络推送、定时器等),\n // 新节点缺隐藏 slot 会可见叠加到菜单上;观察 portal 内容并在下一帧重新同步。\n private readonly _contentObserver = new MutationObserver(() => {\n if (this._isOpen) this._scheduleRefresh()\n })\n\n get isOpen(): boolean {\n return this._isOpen\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._hideMenuItems()\n this.addEventListener('contextmenu', this._onContextMenu)\n this.addEventListener('keydown', this._onKeydown)\n this.addEventListener('click', this._onMenuClick)\n document.addEventListener('click', this._onClickOutside)\n document.addEventListener('contextmenu', this._onContextMenuOutside)\n document.addEventListener('wheel', this._onWheel, { capture: true, passive: false })\n document.addEventListener('touchmove', this._onTouchMove, { capture: true, passive: false })\n document.addEventListener('keydown', this._onDocumentKeydown)\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this.removeEventListener('contextmenu', this._onContextMenu)\n this.removeEventListener('keydown', this._onKeydown)\n this.removeEventListener('click', this._onMenuClick)\n document.removeEventListener('click', this._onClickOutside)\n document.removeEventListener('contextmenu', this._onContextMenuOutside)\n document.removeEventListener('wheel', this._onWheel, true)\n document.removeEventListener('touchmove', this._onTouchMove, true)\n document.removeEventListener('keydown', this._onDocumentKeydown)\n this._contentObserver.disconnect()\n this._outsideClickGuard.dispose()\n this._hoverBinder.dispose()\n this._scrollLock.release()\n this._returnItemsToSlot()\n this._menu?.panel.remove()\n this._menu = undefined\n this._closeSubmenusFrom(0, true)\n this._closingSubmenus.restoreAll()\n // 脱离文档即视为关闭:否则重连后 _isOpen 仍为 true 而 _menu 已清空,\n // 下次 openAt 会走已打开分支静默失败,菜单无法再打开。\n this._isOpen = false\n this._restoreFocusTarget = undefined\n }\n\n protected override updated(changed: Map<string, unknown>) {\n // Lit 的已排队更新可在卸载后执行,不能让已失效实例重新获取全局滚动锁。\n if (!this.isConnected) {\n this._syncScrollLock(false)\n return\n }\n\n if (changed.has('_isOpen')) {\n if (this._isOpen) {\n this._syncScrollLock()\n if (!this._menu) {\n this._menu = createMenuPortalOverlay('context-menu', this)\n this._menu.panel.setAttribute('role', 'menu')\n this._menu.panel.setAttribute('aria-label', '上下文菜单')\n this._menu.panel.addEventListener('click', this._onMenuClick)\n }\n // 父项始终留在 menu.content 内,观察它即可覆盖各级子菜单在打开期间的内容重建。\n this._contentObserver.observe(this._menu.content, { childList: true, subtree: true })\n requestAnimationFrame(() => {\n if (!this._isOpen || !this._menu) return\n this._refreshMenu()\n showOverlayPresence(this._menu.panel, { isInstant: this._shouldOpenInstantly })\n this._shouldOpenInstantly = true\n this._focusFirstItem()\n })\n } else {\n this._syncScrollLock(false)\n this._contentObserver.disconnect()\n this._refreshScheduled = false\n void this._closeMenuAfterPresence()\n }\n if (this._userOpenChange.consume()) this._dispatchChange(this._isOpen)\n }\n if (changed.has('noScrollLock')) this._syncScrollLock()\n }\n\n /**\n * 在指定视口坐标打开菜单。\n * @param x 水平坐标(px)。\n * @param y 垂直坐标(px)。\n * @returns 无返回值;命令式打开不派发 `open-change` 事件。\n */\n openAt(x: number, y: number) {\n this._openAt(x, y, true)\n }\n\n private _openAt(x: number, y: number, isInstant: boolean): boolean {\n if (this.disabled) return false\n this._x = x\n this._y = y\n this._shouldOpenInstantly = isInstant\n this._outsideClickGuard.arm()\n if (this._isOpen) {\n this._closeSubmenusFrom(0, true)\n this._closingSubmenus.restoreAll()\n this._scheduleRefresh()\n return false\n }\n this._restoreFocusTarget ??= document.activeElement instanceof HTMLElement ? document.activeElement : undefined\n this._isOpen = true\n return true\n }\n\n /**\n * 关闭菜单。\n * @returns 无返回值;命令式关闭不派发 `open-change` 事件。\n */\n close() {\n if (!this._isOpen) return\n this._isOpen = false\n }\n\n private readonly _closeFromUser = () => {\n if (!this._isOpen) return\n this._userOpenChange.mark()\n this.close()\n }\n\n // 同一帧内多次内容变化只刷新一次,避免观察者与刷新自身 append 形成循环。\n private _scheduleRefresh() {\n if (this._refreshScheduled || !this._isOpen) return\n this._refreshScheduled = true\n requestAnimationFrame(() => {\n this._refreshScheduled = false\n if (!this._isOpen || !this._menu) return\n this._refreshMenu()\n })\n }\n\n // 重新同步 portal 内容并重定位;fresh-open、重定位与观察者触发的刷新共用。\n private _refreshMenu() {\n if (!this._menu) return\n this._setupMenuItems()\n this._positionMenu()\n this._hoverBinder.bind()\n }\n\n private _positionMenu() {\n const panel = this._menu?.panel\n if (!panel) return\n\n panel.style.visibility = 'hidden'\n panel.style.display = ''\n\n // 普通 overlay root 不经过 transformed containing block,保留轻量的同步定位。\n // 只有 panel 已进入 open native dialog 时才需要 Floating UI 解析坐标。\n if (!(panel.parentElement instanceof HTMLDialogElement && panel.parentElement.open)) {\n this._positionMenuInViewport(panel)\n return\n }\n\n void computePosition({ getBoundingClientRect: () => new DOMRect(this._x, this._y, 0, 0) }, panel, {\n strategy: 'fixed',\n placement: 'bottom-start',\n // crossAxis 必须显式开启:bottom-start 的 sideAxis 为 y,默认只钳制 x,\n // 视口下缘打开时菜单底部会溢出且无法滚动进入视野。\n middleware: [shift({ padding: 8, crossAxis: true })]\n }).then(({ x, y, middlewareData }) => {\n if (!this._isOpen || this._menu?.panel !== panel) return\n // dialog 相对坐标不能与 viewport 的 _x/_y 比较推导 origin(原点非零时几乎恒判\n // right/bottom);shift 数据是该坐标系内的钳制位移增量,负值即被推向该轴起点侧。\n const shiftX = middlewareData.shift?.x ?? 0\n const shiftY = middlewareData.shift?.y ?? 0\n this._applyMenuPosition(panel, x, y, shiftX < 0 ? 'right' : 'left', shiftY < 0 ? 'bottom' : 'top')\n })\n }\n\n private _positionMenuInViewport(panel: HTMLElement) {\n const { width, height } = panel.getBoundingClientRect()\n const vw = window.innerWidth\n const vh = window.innerHeight\n\n let x = this._x\n let y = this._y\n\n if (x + width > vw) x = vw - width - 8\n if (y + height > vh) y = vh - height - 8\n if (x < 0) x = 8\n if (y < 0) y = 8\n\n this._applyMenuPosition(panel, x, y)\n }\n\n private _applyMenuPosition(\n panel: HTMLElement,\n x: number,\n y: number,\n horizontalOrigin?: 'left' | 'right',\n verticalOrigin?: 'top' | 'bottom'\n ) {\n panel.style.left = `${x}px`\n panel.style.top = `${y}px`\n // 非 dialog 路径保持 viewport 坐标比较;dialog 路径由调用方传入 shift 推导值。\n const horizontal = horizontalOrigin ?? (x < this._x ? 'right' : 'left')\n const vertical = verticalOrigin ?? (y < this._y ? 'bottom' : 'top')\n panel.style.setProperty('--wui-internal-overlay-transform-origin', `${vertical} ${horizontal}`)\n panel.style.visibility = ''\n }\n\n private _focusFirstItem() {\n const items = this._menu?.content.querySelectorAll<HTMLElement>('web-ui-dropdown-item:not([disabled])')\n const firstItem = items?.[0]\n if (firstItem) {\n focusMenuItem(firstItem)\n }\n }\n\n private _setupMenuItems() {\n const menu = this._menu\n if (!menu) return\n const content = menu.content\n\n reconcileManagedMenuItems(this, content, this._menuItemAnchors, MARKER_TEXT)\n this._hideMenuItems()\n // 宿主可能在菜单打开期间动态改写 slot 子内容(如切换上下文后重建嵌套子项),\n // 新节点没有隐藏 slot 会落入父项默认 slot 可见渲染并叠到一级菜单上;\n // 因此对已移入 content 的嵌套子项也要重新隐藏。\n hideNestedMenuChildren(content, 'context-menu-hidden')\n\n // 框架 v-if 注释锚点的复位独立于元素重排:无论元素序是否已变都要执行。\n // 若挂在「元素序已变才重排」之下,顺序恰好正确时会跳过复位,锚点漂移无法收敛,\n // 而 Vue 下次翻转正依赖锚点引导新分支项的插入点。\n const anchors = captureFrameworkAnchors(content, MARKER_TEXT)\n orderManagedMenuItems(this, content, this._menuItemAnchors, MARKER_TEXT)\n restoreFrameworkAnchors(content, anchors)\n }\n\n private _returnItemsToSlot() {\n const menu = this._menu\n if (!menu) return\n\n this._closeSubmenusFrom(0, true)\n this._closingSubmenus.restoreAll()\n\n returnManagedMenuItemsToSlot(this, menu.content, this._menuItemAnchors)\n }\n\n private async _closeMenuAfterPresence() {\n const menu = this._menu\n if (menu && !(await hideOverlayPresence(menu.panel))) return\n if (this._isOpen || !this.isConnected || this._menu !== menu) return\n\n this._returnItemsToSlot()\n menu?.panel.remove()\n this._menu = undefined\n this._restoreFocusTarget?.focus()\n this._restoreFocusTarget = undefined\n }\n\n private _hideMenuItems() {\n getMenuChildren(this).forEach(child => child.setAttribute('slot', 'context-menu-hidden'))\n hideNestedMenuChildren(this, 'context-menu-hidden')\n }\n\n private _openSubmenu(item: HTMLElement, isInstant = false) {\n if (!this._isOpen || !item.hasAttribute('submenu') || item.hasAttribute('disabled')) return\n\n const level = this._getItemLevel(item)\n if (level === -1 || this._activeSubmenuItems[level] === item) return\n\n this._closeSubmenusFrom(level)\n const closingSubmenu = this._closingSubmenus.take(item)\n if (closingSubmenu) {\n this._activeSubmenus[level] = closingSubmenu\n this._activeSubmenuItems[level] = item\n item.setAttribute('active', '')\n this._positionSubmenu(item, closingSubmenu)\n showOverlayPresence(closingSubmenu.panel, { isInstant })\n this._hoverBinder.bind()\n return\n }\n if (getMenuChildren(item).length === 0) return\n\n const submenu = createMenuPortalOverlay('context-submenu', this)\n submenu.panel.dataset.level = String(level)\n submenu.panel.setAttribute('role', 'menu')\n submenu.panel.setAttribute('aria-label', '子菜单')\n submenu.panel.style.visibility = 'hidden'\n submenu.panel.addEventListener('click', this._onMenuClick)\n moveMenuChildren(item, submenu.content)\n\n this._activeSubmenus[level] = submenu\n this._activeSubmenuItems[level] = item\n item.setAttribute('active', '')\n this._positionSubmenu(item, submenu)\n showOverlayPresence(submenu.panel, { isInstant })\n this._hoverBinder.bind()\n }\n\n private _closeSubmenusFrom(level: number, isInstant = false) {\n for (let index = this._activeSubmenus.length - 1; index >= level; index--) {\n const submenu = this._activeSubmenus[index]\n const item = this._activeSubmenuItems[index]\n item?.removeAttribute('active')\n if (!item || isInstant) {\n this._restoreSubmenuItems(submenu, item)\n submenu.panel.remove()\n } else {\n this._closingSubmenus.closeAsync(item, submenu)\n }\n }\n this._activeSubmenus.length = level\n this._activeSubmenuItems.length = level\n }\n\n private _restoreSubmenuItems(submenu: MenuPortalOverlay, item?: HTMLElement) {\n if (!item) return\n moveMenuChildren(submenu.content, item)\n // 子菜单打开期间宿主可能重建了嵌套子项,归还时补隐藏,避免可见叠加。\n hideNestedMenuChildren(item, 'context-menu-hidden')\n }\n\n private _getItemLevel(item: HTMLElement): number {\n const menu = this._menu\n if (menu?.panel.contains(item)) return 0\n const parentLevel = this._activeSubmenus.findIndex(submenu => submenu.panel.contains(item))\n return parentLevel === -1 ? -1 : parentLevel + 1\n }\n\n private _positionSubmenu(item: HTMLElement, submenu: MenuPortalOverlay) {\n // 与主菜单同因:panel 进入 open native dialog 后处于 transformed containing\n // block,viewport 坐标的 left/top 会相对 dialog padding box 解析而整体偏移,\n // 需改走 Floating UI 换算为 dialog 相对坐标;开合方向仍按视口坐标度量预判。\n if (submenu.panel.parentElement instanceof HTMLDialogElement && submenu.panel.parentElement.open) {\n const itemRect = item.getBoundingClientRect()\n const padding = 8\n const canOpenRight = itemRect.right + submenu.panel.getBoundingClientRect().width + padding <= window.innerWidth\n // 同帧关闭→重开会复用同一 panel 产生两个 in-flight 定位 promise,完成序不保证\n // 后者胜出;按 panel 键控的代数 token 只允许最新一次调用写入,迟到旧 promise 丢弃。\n const epoch = (this._submenuPositionEpochs.get(submenu.panel) ?? 0) + 1\n this._submenuPositionEpochs.set(submenu.panel, epoch)\n void computePosition(item, submenu.panel, {\n strategy: 'fixed',\n placement: canOpenRight ? 'right-start' : 'left-start',\n middleware: [shift({ padding, crossAxis: true })]\n }).then(({ x, y, middlewareData }) => {\n if (!this._activeSubmenus.includes(submenu) || epoch !== this._submenuPositionEpochs.get(submenu.panel)) return\n // 与主菜单 dialog 路径一致:origin 由 shift 增量推导,视口预判只决定 placement。\n const shiftX = middlewareData.shift?.x ?? 0\n const shiftY = middlewareData.shift?.y ?? 0\n const horizontalOrigin = shiftX < 0 ? 'right' : 'left'\n const verticalOrigin = shiftY < 0 ? 'bottom' : 'top'\n submenu.panel.style.left = `${x}px`\n submenu.panel.style.top = `${y}px`\n submenu.panel.style.setProperty(\n '--wui-internal-overlay-transform-origin',\n `${verticalOrigin} ${horizontalOrigin}`\n )\n submenu.panel.style.visibility = ''\n })\n return\n }\n\n const itemRect = item.getBoundingClientRect()\n const submenuRect = submenu.panel.getBoundingClientRect()\n const padding = 8\n const canOpenRight = itemRect.right + submenuRect.width + padding <= window.innerWidth\n const left = canOpenRight ? itemRect.right : Math.max(padding, itemRect.left - submenuRect.width)\n const top = Math.min(Math.max(padding, itemRect.top), window.innerHeight - submenuRect.height - padding)\n\n submenu.panel.style.left = `${left}px`\n submenu.panel.style.top = `${top}px`\n submenu.panel.style.setProperty('--wui-internal-overlay-transform-origin', canOpenRight ? 'top left' : 'top right')\n submenu.panel.style.visibility = ''\n }\n\n private _dispatchChange(open: boolean) {\n dispatchOpenChangeEvent(this, open)\n }\n\n private _onContextMenu = (e: MouseEvent) => {\n if (this.disabled) return\n e.preventDefault()\n this._restoreFocusTarget = e.target instanceof HTMLElement ? e.target : undefined\n if (this._openAt(e.clientX, e.clientY, false)) this._userOpenChange.mark()\n }\n\n private _onContextMenuOutside = (e: MouseEvent) => {\n if (this._isOpen && !this._outsideClickGuard.isInside(e)) {\n this._closeFromUser()\n }\n }\n\n private _onKeydown = (e: KeyboardEvent) => {\n if (this.disabled) return\n\n // 键盘 ContextMenu 键或 Shift+F10\n if (e.key === 'ContextMenu' || (e.shiftKey && e.key === 'F10')) {\n e.preventDefault()\n const focused = document.activeElement\n if (focused && focused !== document.body) {\n const rect = focused.getBoundingClientRect()\n if (this._openAt(rect.left, rect.bottom, true)) this._userOpenChange.mark()\n } else {\n if (this._openAt(window.innerWidth / 2, window.innerHeight / 2, true)) this._userOpenChange.mark()\n }\n return\n }\n }\n\n private _onClickOutside = (e: MouseEvent) => {\n if (!this._isOpen || this._outsideClickGuard.isArmed()) return\n if (this._outsideClickGuard.isInside(e)) return\n this._closeFromUser()\n }\n\n private _onMenuClick = (e: MouseEvent) => {\n const item = getMenuItemFromEvent(e)\n if (!item || item.hasAttribute('disabled')) return\n if (item.hasAttribute('submenu')) {\n this._openSubmenu(item)\n return\n }\n this._closeFromUser()\n }\n\n private _getLevelContainer(level: number) {\n return level === 0 ? this._menu : this._activeSubmenus[level - 1]\n }\n\n private _getLevelItems(level: number): HTMLElement[] {\n const container = this._getLevelContainer(level)\n if (!container) return []\n return getMenuChildren(container.content)\n }\n\n private _onWheel = (e: WheelEvent) => {\n this._preventBackgroundScroll(e)\n }\n\n private _onTouchMove = (e: TouchEvent) => {\n this._preventBackgroundScroll(e)\n }\n\n private _onDocumentKeydown = (e: KeyboardEvent) => {\n if (!this._isOpen) return\n // 鼠标右键打开的菜单焦点不在菜单内,e.target !== this 时也必须能 Escape 关闭;\n // 菜单为模态浮层,按 Escape 即关闭,无需限定焦点位置\n handleMenuKeyboard(this._keyboardDelegate, e)\n }\n\n private _closeLastSubmenuOrMenu() {\n if (this._activeSubmenus.length > 0) {\n const level = this._activeSubmenus.length - 1\n const parent = this._activeSubmenuItems[level]\n this._closeSubmenusFrom(level)\n focusMenuItem(parent)\n this._hoverBinder.bind()\n } else {\n this._closeFromUser()\n }\n }\n\n private _preventBackgroundScroll(e: Event) {\n if (!this._isOpen || this.noScrollLock || this._isMenuPanelEvent(e)) return\n e.preventDefault()\n }\n\n private _syncScrollLock(isOpen = this._isOpen) {\n this._scrollLock.sync(isOpen && !this.noScrollLock)\n }\n\n private _isMenuPanelEvent(e: Event): boolean {\n return e\n .composedPath()\n .some(\n node =>\n node instanceof HTMLElement &&\n (node.classList.contains('context-menu') || node.classList.contains('context-submenu'))\n )\n }\n\n override render() {\n return html`\n <div class=\"context-menu-anchor\">\n <slot @slotchange=${this._onSlotChange}></slot>\n </div>\n `\n }\n\n private _onSlotChange() {\n this._hideMenuItems()\n // 打开期间宿主重建顶层项时,新成员要移入 portal 才对用户可见;\n // 关闭状态下无需移动,等下次打开时由 _setupMenuItems 统一处理。\n if (this._isOpen) this._scheduleRefresh()\n }\n\n declare readonly $events: {\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-context-menu': WebUiContextMenu\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/context-menu/index.ts"],"sourcesContent":["import { computePosition, shift } from '@floating-ui/dom'\nimport { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport '@/components/dropdown-divider'\nimport '@/components/dropdown-header'\nimport '@/components/dropdown-item'\nimport { UserChangeController } from '@/shared/events/user-change'\nimport {\n createClosingSubmenuStack,\n createMenuHoverBinder,\n createMenuOutsideClickGuard,\n getEnabledMenuLevelItems,\n getFocusedMenuItemFromPanels,\n handleMenuKeyboard,\n type MenuHoverDelegate,\n type MenuKeyboardDelegate\n} from '@/shared/menu-behavior'\nimport { createMenuPortalOverlay, type MenuPortalOverlay } from '@/shared/menu-portal/menu-portal'\nimport {\n captureFrameworkAnchors,\n focusMenuItem,\n getMenuChildren,\n getMenuItemFromEvent,\n hideNestedMenuChildren,\n moveMenuChildren,\n orderManagedMenuItems,\n reconcileManagedMenuItems,\n restoreFrameworkAnchors,\n returnManagedMenuItemsToSlot\n} from '@/shared/menu-portal/menu-tree'\nimport { dispatchOpenChangeEvent } from '@/shared/open-state'\nimport { overlayComposition } from '@/shared/overlay/composition'\nimport { defineOverlayPositioningGeneration } from '@/shared/overlay/positioning-generation'\nimport { hideOverlayPresence, showOverlayPresence } from '@/shared/overlay/presence'\nimport { defineScrollLockLease } from '@/shared/scroll-lock/scroll-lock'\n\nimport style from './style.css?inline'\n\nconst MARKER_TEXT = 'wui-context-menu-item'\n\n@customElement('web-ui-context-menu')\nexport class WebUiContextMenu extends LitElement {\n static override styles = unsafeCSS(style)\n\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true, attribute: 'no-scroll-lock' }) noScrollLock = false\n\n @state() private _isOpen = false\n @state() private _x = 0\n @state() private _y = 0\n\n private _activeSubmenus: MenuPortalOverlay[] = []\n private _activeSubmenuItems: HTMLElement[] = []\n // 子菜单 dialog 定位的唯一写者代数(按 panel 键控):同帧关闭→重开复用同一 panel\n // 时只允许最新一次定位写入;不同层级子菜单各有 panel,互不作废。\n private readonly _submenuPositionEpochs = new WeakMap<HTMLElement, number>()\n private _menu?: MenuPortalOverlay\n // 行为层(hover / outside-click / 键盘 / submenu 收尾)由 shared/menu-behavior 驱动\n private readonly _outsideClickGuard = createMenuOutsideClickGuard(this, node => {\n const panels = [this._menu?.panel, ...this._activeSubmenus.map(menu => menu.panel)].filter(\n (panel): panel is HTMLElement => panel instanceof HTMLElement\n )\n return panels.some(panel => overlayComposition.contains(panel, node))\n })\n private readonly _closingSubmenus = createClosingSubmenuStack<MenuPortalOverlay>({\n getPanel: container => container.panel,\n restoreItems: (container, parentItem) => this._restoreSubmenuItems(container, parentItem),\n dispose: container => {\n overlayComposition.unregisterPanel(container.panel)\n container.panel.remove()\n }\n })\n private readonly _hoverDelegate: MenuHoverDelegate = {\n getOpenDepth: () => this._activeSubmenus.length,\n getLevelItems: level => this._getLevelItems(level),\n getActiveItem: level => this._activeSubmenuItems[level],\n isSubmenuItem: item => item.hasAttribute('submenu'),\n openSubmenu: item => this._openSubmenu(item),\n closeFrom: level => {\n this._closeSubmenusFrom(level)\n this._hoverBinder.bind()\n }\n }\n private readonly _hoverBinder = createMenuHoverBinder(this._hoverDelegate, 'web-ui-dropdown-item')\n private readonly _keyboardDelegate: MenuKeyboardDelegate = {\n getFocusedItem: event =>\n getFocusedMenuItemFromPanels(\n event,\n [this._menu?.content, ...this._activeSubmenus.map(submenu => submenu.content)],\n 'web-ui-dropdown-item'\n ),\n getLevelOf: item => {\n const level = this._getItemLevel(item)\n return level === -1 ? undefined : level\n },\n getEnabledItems: level => getEnabledMenuLevelItems(this._getLevelContainer(level)?.content),\n isSubmenuItem: item => item.hasAttribute('submenu'),\n openSubmenuInstant: item => this._openSubmenu(item, true),\n closeToParent: level => {\n const parent = this._activeSubmenuItems[level - 1]\n this._closeSubmenusFrom(level - 1)\n this._hoverBinder.bind()\n return parent\n },\n closeDeepestOrAll: () => this._closeLastSubmenuOrMenu()\n }\n private readonly _menuItemAnchors = new Map<HTMLElement, Comment>()\n private readonly _scrollLock = defineScrollLockLease().make()\n private readonly _userOpenChange = new UserChangeController()\n private _restoreFocusTarget?: HTMLElement\n private _shouldOpenInstantly = true\n private _refreshScheduled = false\n // 主菜单 dialog 路径与子菜单一样使用代数令牌;快速 openAt/refresh 或 close 后,\n // 迟到的 positioning promise 只能被丢弃,不能覆盖最新坐标。\n private readonly _menuPositionGeneration = defineOverlayPositioningGeneration().make()\n // 菜单打开期间宿主可能不经重定位直接改写子内容(网络推送、定时器等),\n // 新节点缺隐藏 slot 会可见叠加到菜单上;观察 portal 内容并在下一帧重新同步。\n private readonly _contentObserver = new MutationObserver(() => {\n if (this._isOpen) this._scheduleRefresh()\n })\n\n get isOpen(): boolean {\n return this._isOpen\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._hideMenuItems()\n this.addEventListener('contextmenu', this._onContextMenu)\n this.addEventListener('keydown', this._onKeydown)\n this.addEventListener('click', this._onMenuClick)\n document.addEventListener('click', this._onClickOutside)\n document.addEventListener('contextmenu', this._onContextMenuOutside)\n document.addEventListener('wheel', this._onWheel, { capture: true, passive: false })\n document.addEventListener('touchmove', this._onTouchMove, { capture: true, passive: false })\n document.addEventListener('keydown', this._onDocumentKeydown)\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this.removeEventListener('contextmenu', this._onContextMenu)\n this.removeEventListener('keydown', this._onKeydown)\n this.removeEventListener('click', this._onMenuClick)\n document.removeEventListener('click', this._onClickOutside)\n document.removeEventListener('contextmenu', this._onContextMenuOutside)\n document.removeEventListener('wheel', this._onWheel, true)\n document.removeEventListener('touchmove', this._onTouchMove, true)\n document.removeEventListener('keydown', this._onDocumentKeydown)\n this._contentObserver.disconnect()\n this._menuPositionGeneration.invalidate()\n this._outsideClickGuard.dispose()\n this._hoverBinder.dispose()\n this._scrollLock.release()\n if (this._menu) overlayComposition.unregisterPanel(this._menu.panel)\n this._returnItemsToSlot()\n this._menu?.panel.remove()\n this._menu = undefined\n this._closeSubmenusFrom(0, true)\n this._closingSubmenus.restoreAll()\n // 脱离文档即视为关闭:否则重连后 _isOpen 仍为 true 而 _menu 已清空,\n // 下次 openAt 会走已打开分支静默失败,菜单无法再打开。\n this._isOpen = false\n this._restoreFocusTarget = undefined\n }\n\n protected override updated(changed: Map<string, unknown>) {\n // Lit 的已排队更新可在卸载后执行,不能让已失效实例重新获取全局滚动锁。\n if (!this.isConnected) {\n this._syncScrollLock(false)\n return\n }\n\n if (changed.has('_isOpen')) {\n if (this._isOpen) {\n this._syncScrollLock()\n if (!this._menu) {\n this._menu = createMenuPortalOverlay('context-menu', this)\n this._menu.panel.setAttribute('role', 'menu')\n this._menu.panel.setAttribute('aria-label', '上下文菜单')\n this._menu.panel.addEventListener('click', this._onMenuClick)\n overlayComposition.registerPanel(this._menu.panel)\n }\n // 父项始终留在 menu.content 内,观察它即可覆盖各级子菜单在打开期间的内容重建。\n this._contentObserver.observe(this._menu.content, { childList: true, subtree: true })\n requestAnimationFrame(() => {\n if (!this._isOpen || !this._menu) return\n this._refreshMenu()\n showOverlayPresence(this._menu.panel, { isInstant: this._shouldOpenInstantly })\n this._shouldOpenInstantly = true\n this._focusFirstItem()\n })\n } else {\n this._syncScrollLock(false)\n this._contentObserver.disconnect()\n this._menuPositionGeneration.invalidate()\n this._refreshScheduled = false\n void this._closeMenuAfterPresence()\n }\n if (this._userOpenChange.consume()) this._dispatchChange(this._isOpen)\n }\n if (changed.has('noScrollLock')) this._syncScrollLock()\n }\n\n /**\n * 在指定视口坐标打开菜单。\n * @param x 水平坐标(px)。\n * @param y 垂直坐标(px)。\n * @returns 无返回值;命令式打开不派发 `open-change` 事件。\n */\n openAt(x: number, y: number) {\n this._openAt(x, y, true)\n }\n\n private _openAt(x: number, y: number, isInstant: boolean): boolean {\n if (this.disabled) return false\n this._x = x\n this._y = y\n this._shouldOpenInstantly = isInstant\n this._outsideClickGuard.arm()\n if (this._isOpen) {\n this._closeSubmenusFrom(0, true)\n this._closingSubmenus.restoreAll()\n // 先失效尚未完成的旧定位,再调度下一帧新代;避免新请求前的旧 promise 胜出。\n this._menuPositionGeneration.invalidate()\n this._scheduleRefresh()\n return false\n }\n this._restoreFocusTarget ??= document.activeElement instanceof HTMLElement ? document.activeElement : undefined\n this._isOpen = true\n return true\n }\n\n /**\n * 关闭菜单。\n * @returns 无返回值;命令式关闭不派发 `open-change` 事件。\n */\n close() {\n if (!this._isOpen) return\n this._isOpen = false\n this._menuPositionGeneration.invalidate()\n }\n\n private readonly _closeFromUser = () => {\n if (!this._isOpen) return\n this._userOpenChange.mark()\n this.close()\n }\n\n // 同一帧内多次内容变化只刷新一次,避免观察者与刷新自身 append 形成循环。\n private _scheduleRefresh() {\n if (this._refreshScheduled || !this._isOpen) return\n this._refreshScheduled = true\n requestAnimationFrame(() => {\n this._refreshScheduled = false\n if (!this._isOpen || !this._menu) return\n this._refreshMenu()\n })\n }\n\n // 重新同步 portal 内容并重定位;fresh-open、重定位与观察者触发的刷新共用。\n private _refreshMenu() {\n if (!this._menu) return\n this._setupMenuItems()\n this._positionMenu()\n this._hoverBinder.bind()\n }\n\n private _positionMenu() {\n const panel = this._menu?.panel\n if (!panel) return\n\n panel.style.visibility = 'hidden'\n panel.style.display = ''\n\n // 普通 overlay root 不经过 transformed containing block,保留轻量的同步定位。\n // 只有 panel 已进入 open native dialog 时才需要 Floating UI 解析坐标。\n if (!(panel.parentElement instanceof HTMLDialogElement && panel.parentElement.open)) {\n this._positionMenuInViewport(panel)\n return\n }\n\n const generation = this._menuPositionGeneration.next()\n void computePosition({ getBoundingClientRect: () => new DOMRect(this._x, this._y, 0, 0) }, panel, {\n strategy: 'fixed',\n placement: 'bottom-start',\n // crossAxis 必须显式开启:bottom-start 的 sideAxis 为 y,默认只钳制 x,\n // 视口下缘打开时菜单底部会溢出且无法滚动进入视野。\n middleware: [shift({ padding: 8, crossAxis: true })]\n }).then(({ x, y, middlewareData }) => {\n if (!this._isOpen || this._menu?.panel !== panel || !this._menuPositionGeneration.isCurrent(generation)) return\n // dialog 相对坐标不能与 viewport 的 _x/_y 比较推导 origin(原点非零时几乎恒判\n // right/bottom);shift 数据是该坐标系内的钳制位移增量,负值即被推向该轴起点侧。\n const shiftX = middlewareData.shift?.x ?? 0\n const shiftY = middlewareData.shift?.y ?? 0\n this._applyMenuPosition(panel, x, y, shiftX < 0 ? 'right' : 'left', shiftY < 0 ? 'bottom' : 'top')\n })\n }\n\n private _positionMenuInViewport(panel: HTMLElement) {\n const { width, height } = panel.getBoundingClientRect()\n const vw = window.innerWidth\n const vh = window.innerHeight\n\n let x = this._x\n let y = this._y\n\n if (x + width > vw) x = vw - width - 8\n if (y + height > vh) y = vh - height - 8\n if (x < 0) x = 8\n if (y < 0) y = 8\n\n this._applyMenuPosition(panel, x, y)\n }\n\n private _applyMenuPosition(\n panel: HTMLElement,\n x: number,\n y: number,\n horizontalOrigin?: 'left' | 'right',\n verticalOrigin?: 'top' | 'bottom'\n ) {\n panel.style.left = `${x}px`\n panel.style.top = `${y}px`\n // 非 dialog 路径保持 viewport 坐标比较;dialog 路径由调用方传入 shift 推导值。\n const horizontal = horizontalOrigin ?? (x < this._x ? 'right' : 'left')\n const vertical = verticalOrigin ?? (y < this._y ? 'bottom' : 'top')\n panel.style.setProperty('--wui-internal-overlay-transform-origin', `${vertical} ${horizontal}`)\n panel.style.visibility = ''\n }\n\n private _focusFirstItem() {\n const items = this._menu?.content.querySelectorAll<HTMLElement>('web-ui-dropdown-item:not([disabled])')\n const firstItem = items?.[0]\n if (firstItem) {\n focusMenuItem(firstItem)\n }\n }\n\n private _setupMenuItems() {\n const menu = this._menu\n if (!menu) return\n const content = menu.content\n\n reconcileManagedMenuItems(this, content, this._menuItemAnchors, MARKER_TEXT)\n this._hideMenuItems()\n // 宿主可能在菜单打开期间动态改写 slot 子内容(如切换上下文后重建嵌套子项),\n // 新节点没有隐藏 slot 会落入父项默认 slot 可见渲染并叠到一级菜单上;\n // 因此对已移入 content 的嵌套子项也要重新隐藏。\n hideNestedMenuChildren(content, 'context-menu-hidden')\n\n // 框架 v-if 注释锚点的复位独立于元素重排:无论元素序是否已变都要执行。\n // 若挂在「元素序已变才重排」之下,顺序恰好正确时会跳过复位,锚点漂移无法收敛,\n // 而 Vue 下次翻转正依赖锚点引导新分支项的插入点。\n const anchors = captureFrameworkAnchors(content, MARKER_TEXT)\n orderManagedMenuItems(this, content, this._menuItemAnchors, MARKER_TEXT)\n restoreFrameworkAnchors(content, anchors)\n }\n\n private _returnItemsToSlot() {\n const menu = this._menu\n if (!menu) return\n\n this._closeSubmenusFrom(0, true)\n this._closingSubmenus.restoreAll()\n\n returnManagedMenuItemsToSlot(this, menu.content, this._menuItemAnchors)\n }\n\n private async _closeMenuAfterPresence() {\n const menu = this._menu\n if (menu && !(await hideOverlayPresence(menu.panel))) return\n if (this._isOpen || !this.isConnected || this._menu !== menu) return\n\n if (menu) overlayComposition.unregisterPanel(menu.panel)\n this._returnItemsToSlot()\n menu?.panel.remove()\n this._menu = undefined\n this._restoreFocusTarget?.focus()\n this._restoreFocusTarget = undefined\n }\n\n private _hideMenuItems() {\n getMenuChildren(this).forEach(child => child.setAttribute('slot', 'context-menu-hidden'))\n hideNestedMenuChildren(this, 'context-menu-hidden')\n }\n\n private _openSubmenu(item: HTMLElement, isInstant = false) {\n if (!this._isOpen || !item.hasAttribute('submenu') || item.hasAttribute('disabled')) return\n\n const level = this._getItemLevel(item)\n if (level === -1 || this._activeSubmenuItems[level] === item) return\n\n this._closeSubmenusFrom(level)\n const closingSubmenu = this._closingSubmenus.take(item)\n if (closingSubmenu) {\n this._activeSubmenus[level] = closingSubmenu\n this._activeSubmenuItems[level] = item\n item.setAttribute('active', '')\n this._positionSubmenu(item, closingSubmenu)\n showOverlayPresence(closingSubmenu.panel, { isInstant })\n this._hoverBinder.bind()\n return\n }\n if (getMenuChildren(item).length === 0) return\n\n const submenu = createMenuPortalOverlay('context-submenu', this)\n submenu.panel.dataset.level = String(level)\n submenu.panel.setAttribute('role', 'menu')\n submenu.panel.setAttribute('aria-label', '子菜单')\n submenu.panel.style.visibility = 'hidden'\n submenu.panel.addEventListener('click', this._onMenuClick)\n moveMenuChildren(item, submenu.content)\n\n this._activeSubmenus[level] = submenu\n this._activeSubmenuItems[level] = item\n overlayComposition.registerPanel(\n submenu.panel,\n level === 0 ? this._menu?.panel : this._activeSubmenus[level - 1]?.panel\n )\n item.setAttribute('active', '')\n this._positionSubmenu(item, submenu)\n showOverlayPresence(submenu.panel, { isInstant })\n this._hoverBinder.bind()\n }\n\n private _closeSubmenusFrom(level: number, isInstant = false) {\n for (let index = this._activeSubmenus.length - 1; index >= level; index--) {\n const submenu = this._activeSubmenus[index]\n const item = this._activeSubmenuItems[index]\n item?.removeAttribute('active')\n if (!item || isInstant) {\n if (submenu) overlayComposition.unregisterPanel(submenu.panel)\n this._restoreSubmenuItems(submenu, item)\n submenu.panel.remove()\n } else {\n this._closingSubmenus.closeAsync(item, submenu)\n }\n }\n this._activeSubmenus.length = level\n this._activeSubmenuItems.length = level\n }\n\n private _restoreSubmenuItems(submenu: MenuPortalOverlay, item?: HTMLElement) {\n if (!item) return\n moveMenuChildren(submenu.content, item)\n // 子菜单打开期间宿主可能重建了嵌套子项,归还时补隐藏,避免可见叠加。\n hideNestedMenuChildren(item, 'context-menu-hidden')\n }\n\n private _getItemLevel(item: HTMLElement): number {\n const menu = this._menu\n if (menu?.panel.contains(item)) return 0\n const parentLevel = this._activeSubmenus.findIndex(submenu => submenu.panel.contains(item))\n return parentLevel === -1 ? -1 : parentLevel + 1\n }\n\n private _positionSubmenu(item: HTMLElement, submenu: MenuPortalOverlay) {\n // 与主菜单同因:panel 进入 open native dialog 后处于 transformed containing\n // block,viewport 坐标的 left/top 会相对 dialog padding box 解析而整体偏移,\n // 需改走 Floating UI 换算为 dialog 相对坐标;开合方向仍按视口坐标度量预判。\n if (submenu.panel.parentElement instanceof HTMLDialogElement && submenu.panel.parentElement.open) {\n const itemRect = item.getBoundingClientRect()\n const padding = 8\n const canOpenRight = itemRect.right + submenu.panel.getBoundingClientRect().width + padding <= window.innerWidth\n // 同帧关闭→重开会复用同一 panel 产生两个 in-flight 定位 promise,完成序不保证\n // 后者胜出;按 panel 键控的代数 token 只允许最新一次调用写入,迟到旧 promise 丢弃。\n const epoch = (this._submenuPositionEpochs.get(submenu.panel) ?? 0) + 1\n this._submenuPositionEpochs.set(submenu.panel, epoch)\n void computePosition(item, submenu.panel, {\n strategy: 'fixed',\n placement: canOpenRight ? 'right-start' : 'left-start',\n middleware: [shift({ padding, crossAxis: true })]\n }).then(({ x, y, middlewareData }) => {\n if (!this._activeSubmenus.includes(submenu) || epoch !== this._submenuPositionEpochs.get(submenu.panel)) return\n // 与主菜单 dialog 路径一致:origin 由 shift 增量推导,视口预判只决定 placement。\n const shiftX = middlewareData.shift?.x ?? 0\n const shiftY = middlewareData.shift?.y ?? 0\n const horizontalOrigin = shiftX < 0 ? 'right' : 'left'\n const verticalOrigin = shiftY < 0 ? 'bottom' : 'top'\n submenu.panel.style.left = `${x}px`\n submenu.panel.style.top = `${y}px`\n submenu.panel.style.setProperty(\n '--wui-internal-overlay-transform-origin',\n `${verticalOrigin} ${horizontalOrigin}`\n )\n submenu.panel.style.visibility = ''\n })\n return\n }\n\n const itemRect = item.getBoundingClientRect()\n const submenuRect = submenu.panel.getBoundingClientRect()\n const padding = 8\n const canOpenRight = itemRect.right + submenuRect.width + padding <= window.innerWidth\n const left = canOpenRight ? itemRect.right : Math.max(padding, itemRect.left - submenuRect.width)\n const top = Math.min(Math.max(padding, itemRect.top), window.innerHeight - submenuRect.height - padding)\n\n submenu.panel.style.left = `${left}px`\n submenu.panel.style.top = `${top}px`\n submenu.panel.style.setProperty('--wui-internal-overlay-transform-origin', canOpenRight ? 'top left' : 'top right')\n submenu.panel.style.visibility = ''\n }\n\n private _dispatchChange(open: boolean) {\n dispatchOpenChangeEvent(this, open)\n }\n\n private _onContextMenu = (e: MouseEvent) => {\n if (this.disabled) return\n e.preventDefault()\n this._restoreFocusTarget = e.target instanceof HTMLElement ? e.target : undefined\n if (this._openAt(e.clientX, e.clientY, false)) this._userOpenChange.mark()\n }\n\n private _onContextMenuOutside = (e: MouseEvent) => {\n if (this._isOpen && !this._outsideClickGuard.isInside(e)) {\n this._closeFromUser()\n }\n }\n\n private _onKeydown = (e: KeyboardEvent) => {\n if (this.disabled) return\n\n // 键盘 ContextMenu 键或 Shift+F10\n if (e.key === 'ContextMenu' || (e.shiftKey && e.key === 'F10')) {\n e.preventDefault()\n const focused = document.activeElement\n if (focused && focused !== document.body) {\n const rect = focused.getBoundingClientRect()\n if (this._openAt(rect.left, rect.bottom, true)) this._userOpenChange.mark()\n } else {\n if (this._openAt(window.innerWidth / 2, window.innerHeight / 2, true)) this._userOpenChange.mark()\n }\n return\n }\n }\n\n private _onClickOutside = (e: MouseEvent) => {\n if (!this._isOpen || this._outsideClickGuard.isArmed()) return\n if (this._outsideClickGuard.isInside(e)) return\n this._closeFromUser()\n }\n\n private _onMenuClick = (e: MouseEvent) => {\n const item = getMenuItemFromEvent(e)\n if (!item || item.hasAttribute('disabled')) return\n if (item.hasAttribute('submenu')) {\n this._openSubmenu(item)\n return\n }\n this._closeFromUser()\n }\n\n private _getLevelContainer(level: number) {\n return level === 0 ? this._menu : this._activeSubmenus[level - 1]\n }\n\n private _getLevelItems(level: number): HTMLElement[] {\n const container = this._getLevelContainer(level)\n if (!container) return []\n return getMenuChildren(container.content)\n }\n\n private _onWheel = (e: WheelEvent) => {\n this._preventBackgroundScroll(e)\n }\n\n private _onTouchMove = (e: TouchEvent) => {\n this._preventBackgroundScroll(e)\n }\n\n private _onDocumentKeydown = (e: KeyboardEvent) => {\n if (!this._isOpen) return\n // 鼠标右键打开的菜单焦点不在菜单内,e.target !== this 时也必须能 Escape 关闭;\n // 菜单为模态浮层,按 Escape 即关闭,无需限定焦点位置\n handleMenuKeyboard(this._keyboardDelegate, e)\n }\n\n private _closeLastSubmenuOrMenu() {\n if (this._activeSubmenus.length > 0) {\n const level = this._activeSubmenus.length - 1\n const parent = this._activeSubmenuItems[level]\n this._closeSubmenusFrom(level)\n focusMenuItem(parent)\n this._hoverBinder.bind()\n } else {\n this._closeFromUser()\n }\n }\n\n private _preventBackgroundScroll(e: Event) {\n if (!this._isOpen || this.noScrollLock || this._isMenuPanelEvent(e)) return\n e.preventDefault()\n }\n\n private _syncScrollLock(isOpen = this._isOpen) {\n this._scrollLock.sync(isOpen && !this.noScrollLock)\n }\n\n private _isMenuPanelEvent(e: Event): boolean {\n const panels = [this._menu?.panel, ...this._activeSubmenus.map(menu => menu.panel)].filter(\n (panel): panel is HTMLElement => panel instanceof HTMLElement\n )\n return panels.some(panel => overlayComposition.containsEvent(panel, e))\n }\n\n override render() {\n return html`\n <div class=\"context-menu-anchor\">\n <slot @slotchange=${this._onSlotChange}></slot>\n </div>\n `\n }\n\n private _onSlotChange() {\n this._hideMenuItems()\n // 打开期间宿主重建顶层项时,新成员要移入 portal 才对用户可见;\n // 关闭状态下无需移动,等下次打开时由 _setupMenuItems 统一处理。\n if (this._isOpen) this._scheduleRefresh()\n }\n\n declare readonly $events: {\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-context-menu': WebUiContextMenu\n }\n}\n"],"mappings":"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"}
@@ -18,12 +18,16 @@ var p = class extends s {
18
18
  }), this._onTransitionEnd = (e) => {
19
19
  this._presence.handleTransitionEnd(e);
20
20
  }, this._onNativeClose = () => {
21
- if (this.open) {
21
+ if (!this.open) {
22
+ this._presence.handleNativeClose();
23
+ return;
24
+ }
25
+ if (!this._presence.handleNativeClose()) {
22
26
  if (this.controlled) {
23
27
  this._presence.sync(!0), this.emitOpenChange(!1);
24
28
  return;
25
29
  }
26
- this._presence.handleNativeClose(), this._userOpenChange.mark(), this.open = !1;
30
+ this._userOpenChange.mark(), this.open = !1;
27
31
  }
28
32
  };
29
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/dialog/index.ts"],"sourcesContent":["import { html, LitElement, type PropertyValues, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport '@/components/button'\nimport glass from '@/assets/glass.css?inline'\nimport { UserChangeController } from '@/shared/events/user-change'\nimport { dispatchOpenChangeEvent } from '@/shared/open-state'\nimport { defineNativeDialogPresence } from '@/shared/overlay/native-dialog-presence'\nimport { defineScrollLockLease } from '@/shared/scroll-lock/scroll-lock'\n\nimport style from './style.css?inline'\n\n@customElement('web-ui-dialog')\nexport class WebUiDialog extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n @property({ type: Boolean, reflect: true }) open = false\n @property({ type: Boolean, reflect: true, attribute: 'no-scroll-lock' }) noScrollLock = false\n @property({ type: Boolean, reflect: true, attribute: 'no-backdrop-close' }) noBackdropClose = false\n @property({ type: Boolean, reflect: true, attribute: 'no-escape-close' }) noEscapeClose = false\n\n /**\n * Controlled 模式下,Escape 和遮罩点击只派发 `open-change` 请求,\n * 不会自行修改 `open`。Consumer 回写 `open` 后才执行关闭动画。\n * 程序化 API(showModal/close/直接赋值 open)不受此模式影响,始终直通。\n */\n @property({ type: Boolean, reflect: true }) controlled = false\n\n @state() private _hasBody = false\n private readonly _userOpenChange = new UserChangeController()\n\n private readonly _scrollLock = defineScrollLockLease().make()\n private readonly _presence = defineNativeDialogPresence().make({\n getDialog: () => this.dialog,\n isConnected: () => this.isConnected,\n isOpen: () => this.open\n })\n\n private get dialog() {\n return this.shadowRoot?.querySelector('dialog') ?? null\n }\n\n protected override updated(props: PropertyValues) {\n super.updated(props)\n if (!this.isConnected) return\n\n if (props.has('open')) {\n if (this._userOpenChange.consume()) this.emitOpenChange()\n this._presence.sync(this.open)\n }\n if (props.has('open') || props.has('noScrollLock')) this._syncScrollLock()\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._presence.dispose()\n this._scrollLock.release()\n }\n\n // 以模态方式打开对话框(命令式)\n showModal() {\n if (this.open) return\n this.open = true\n }\n\n close() {\n this.open = false\n }\n\n private handleCancel(e: Event) {\n // 子控件(例如 file input)可能派发冒泡的 cancel;只让 native dialog 自身的 cancel 关闭。\n if (e.target !== e.currentTarget) return\n\n // 保留 top layer 直到视觉退场完成,避免原生关闭跳过退出动画。\n e.preventDefault()\n if (this.noEscapeClose) return\n if (this.controlled) {\n this.emitOpenChange(false)\n return\n }\n this._userOpenChange.mark()\n this.close()\n }\n\n private handleBackdropClick(e: MouseEvent) {\n if (e.target !== (e.currentTarget as HTMLDialogElement)) return\n if (this.noBackdropClose) return\n if (this.controlled) {\n this.emitOpenChange(false)\n return\n }\n this._userOpenChange.mark()\n this.close()\n }\n\n // controlled 下派发关闭请求:detail 固定 false(用户只能请求关闭,打开永远由 Consumer 写)。\n private emitOpenChange(open = this.open) {\n dispatchOpenChangeEvent(this, open)\n }\n\n private _onTransitionEnd = (event: TransitionEvent) => {\n this._presence.handleTransitionEnd(event)\n }\n\n private _onNativeClose = () => {\n if (!this.open) return\n\n // controlled 下原生关闭(如表单 method=\"dialog\")视为未经 Consumer 批准的状态丢失:\n // 恢复受控状态并派发关闭请求,由 Consumer 决定是否关闭。\n if (this.controlled) {\n this._presence.sync(true)\n this.emitOpenChange(false)\n return\n }\n\n this._presence.handleNativeClose()\n this._userOpenChange.mark()\n this.open = false\n }\n\n private _syncScrollLock(isOpen = this.open) {\n this._scrollLock.sync(isOpen && !this.noScrollLock)\n }\n\n private _onBodySlotChange(e: Event) {\n if (!(e.target instanceof HTMLSlotElement)) return\n this._hasBody = e.target.assignedElements().length > 0\n }\n\n override render() {\n return html`\n <dialog\n @cancel=${this.handleCancel}\n @close=${this._onNativeClose}\n @click=${this.handleBackdropClick}\n @transitionend=${this._onTransitionEnd}\n >\n <div class=\"wui-dialog-body wui-glass\">\n ${\n this._hasBody\n ? html`<slot name=\"body\" @slotchange=${this._onBodySlotChange}></slot>`\n : html`\n <slot name=\"body\" @slotchange=${this._onBodySlotChange} hidden></slot>\n <div class=\"title\"><slot name=\"title\"></slot></div>\n <div class=\"desc\"><slot></slot></div>\n <div class=\"wui-dialog-footer\"><slot name=\"footer\"></slot></div>\n `\n }\n </div>\n </dialog>\n `\n }\n\n declare readonly $events: {\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-dialog': WebUiDialog\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/dialog/index.ts"],"sourcesContent":["import { html, LitElement, type PropertyValues, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport '@/components/button'\nimport glass from '@/assets/glass.css?inline'\nimport { UserChangeController } from '@/shared/events/user-change'\nimport { dispatchOpenChangeEvent } from '@/shared/open-state'\nimport { defineNativeDialogPresence } from '@/shared/overlay/native-dialog-presence'\nimport { defineScrollLockLease } from '@/shared/scroll-lock/scroll-lock'\n\nimport style from './style.css?inline'\n\n@customElement('web-ui-dialog')\nexport class WebUiDialog extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n @property({ type: Boolean, reflect: true }) open = false\n @property({ type: Boolean, reflect: true, attribute: 'no-scroll-lock' }) noScrollLock = false\n @property({ type: Boolean, reflect: true, attribute: 'no-backdrop-close' }) noBackdropClose = false\n @property({ type: Boolean, reflect: true, attribute: 'no-escape-close' }) noEscapeClose = false\n\n /**\n * Controlled 模式下,Escape 和遮罩点击只派发 `open-change` 请求,\n * 不会自行修改 `open`。Consumer 回写 `open` 后才执行关闭动画。\n * 程序化 API(showModal/close/直接赋值 open)不受此模式影响,始终直通。\n */\n @property({ type: Boolean, reflect: true }) controlled = false\n\n @state() private _hasBody = false\n private readonly _userOpenChange = new UserChangeController()\n\n private readonly _scrollLock = defineScrollLockLease().make()\n private readonly _presence = defineNativeDialogPresence().make({\n getDialog: () => this.dialog,\n isConnected: () => this.isConnected,\n isOpen: () => this.open\n })\n\n private get dialog() {\n return this.shadowRoot?.querySelector('dialog') ?? null\n }\n\n protected override updated(props: PropertyValues) {\n super.updated(props)\n if (!this.isConnected) return\n\n if (props.has('open')) {\n if (this._userOpenChange.consume()) this.emitOpenChange()\n this._presence.sync(this.open)\n }\n if (props.has('open') || props.has('noScrollLock')) this._syncScrollLock()\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._presence.dispose()\n this._scrollLock.release()\n }\n\n // 以模态方式打开对话框(命令式)\n showModal() {\n if (this.open) return\n this.open = true\n }\n\n close() {\n this.open = false\n }\n\n private handleCancel(e: Event) {\n // 子控件(例如 file input)可能派发冒泡的 cancel;只让 native dialog 自身的 cancel 关闭。\n if (e.target !== e.currentTarget) return\n\n // 保留 top layer 直到视觉退场完成,避免原生关闭跳过退出动画。\n e.preventDefault()\n if (this.noEscapeClose) return\n if (this.controlled) {\n this.emitOpenChange(false)\n return\n }\n this._userOpenChange.mark()\n this.close()\n }\n\n private handleBackdropClick(e: MouseEvent) {\n if (e.target !== (e.currentTarget as HTMLDialogElement)) return\n if (this.noBackdropClose) return\n if (this.controlled) {\n this.emitOpenChange(false)\n return\n }\n this._userOpenChange.mark()\n this.close()\n }\n\n // controlled 下派发关闭请求:detail 固定 false(用户只能请求关闭,打开永远由 Consumer 写)。\n private emitOpenChange(open = this.open) {\n dispatchOpenChangeEvent(this, open)\n }\n\n private _onTransitionEnd = (event: TransitionEvent) => {\n this._presence.handleTransitionEnd(event)\n }\n\n private _onNativeClose = () => {\n // 关闭态下的 close 事件只可能是我们自己 finishClosing 排队的异步事件(或冗余的\n // 外部关闭):交给 presence 消费 self-close 标志,避免标志泄漏到下一次真实关闭。\n if (!this.open) {\n this._presence.handleNativeClose()\n return\n }\n\n // 我们自己 dialog.close() 排队的 close 事件是异步任务:正常时序在本关闭会话内\n // 到达,快速「关闭→重开」时它在重新打开之后才到达(过期事件)。两种情况都已\n // 完成清理,由 presence 消费并返回 true,不能当成外部关闭把刚重开的 dialog 关掉。\n if (this._presence.handleNativeClose()) return\n\n // controlled 下原生关闭(如表单 method=\"dialog\")视为未经 Consumer 批准的状态丢失:\n // 恢复受控状态并派发关闭请求,由 Consumer 决定是否关闭。\n if (this.controlled) {\n this._presence.sync(true)\n this.emitOpenChange(false)\n return\n }\n\n this._userOpenChange.mark()\n this.open = false\n }\n\n private _syncScrollLock(isOpen = this.open) {\n this._scrollLock.sync(isOpen && !this.noScrollLock)\n }\n\n private _onBodySlotChange(e: Event) {\n if (!(e.target instanceof HTMLSlotElement)) return\n this._hasBody = e.target.assignedElements().length > 0\n }\n\n override render() {\n return html`\n <dialog\n @cancel=${this.handleCancel}\n @close=${this._onNativeClose}\n @click=${this.handleBackdropClick}\n @transitionend=${this._onTransitionEnd}\n >\n <div class=\"wui-dialog-body wui-glass\">\n ${\n this._hasBody\n ? html`<slot name=\"body\" @slotchange=${this._onBodySlotChange}></slot>`\n : html`\n <slot name=\"body\" @slotchange=${this._onBodySlotChange} hidden></slot>\n <div class=\"title\"><slot name=\"title\"></slot></div>\n <div class=\"desc\"><slot></slot></div>\n <div class=\"wui-dialog-footer\"><slot name=\"footer\"></slot></div>\n `\n }\n </div>\n </dialog>\n `\n }\n\n declare readonly $events: {\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-dialog': WebUiDialog\n }\n}\n"],"mappings":";;;;;;;;;;;AAaO,IAAM,IAAN,cAA0B,EAAW;;EA2FX,aAxFoB,KAAA,OAAA,IACqC,KAAA,eAAA,IACM,KAAA,kBAAA,IACJ,KAAA,gBAAA,IAOjC,KAAA,aAAA,IAE7B,KAAA,WAAA,IACO,KAAA,kBAAA,IAAI,EAAqB,GAE7B,KAAA,cAAA,EAAsB,CAAC,CAAC,KAAK,GAC/B,KAAA,YAAA,EAA2B,CAAC,CAAC,KAAK;GAC7D,iBAAiB,KAAK;GACtB,mBAAmB,KAAK;GACxB,cAAc,KAAK;EACrB,CAAC,GAgE2B,KAAA,oBAAA,MAA2B;GACrD,KAAK,UAAU,oBAAoB,CAAK;EAC1C,GAE+B,KAAA,uBAAA;GAG7B,IAAI,CAAC,KAAK,MAAM;IACd,KAAK,UAAU,kBAAkB;IACjC;GACF;GAKI,UAAK,UAAU,kBAAkB,GAIrC;QAAI,KAAK,YAAY;KAEnB,AADA,KAAK,UAAU,KAAK,EAAI,GACxB,KAAK,eAAe,EAAK;KACzB;IACF;IAGA,AADA,KAAK,gBAAgB,KAAK,GAC1B,KAAK,OAAO;GAHZ;EAIF;;;EAjHyB,KAAA,SAAA,CAAC,EAAU,CAAK,GAAG,EAAU,CAAK,CAAC;;CAwB5D,IAAY,SAAS;EACnB,OAAO,KAAK,YAAY,cAAc,QAAQ,KAAK;CACrD;CAEA,QAA2B,GAAuB;EAChD,MAAM,QAAQ,CAAK,GACd,KAAK,gBAEN,EAAM,IAAI,MAAM,MACd,KAAK,gBAAgB,QAAQ,KAAG,KAAK,eAAe,GACxD,KAAK,UAAU,KAAK,KAAK,IAAI,KAE3B,EAAM,IAAI,MAAM,KAAK,EAAM,IAAI,cAAc,MAAG,KAAK,gBAAgB;CAC3E;CAEA,uBAAgC;EAG9B,AAFA,MAAM,qBAAqB,GAC3B,KAAK,UAAU,QAAQ,GACvB,KAAK,YAAY,QAAQ;CAC3B;CAGA,YAAY;EACN,AACJ,KAAK,SAAO;CACd;CAEA,QAAQ;EACN,KAAK,OAAO;CACd;CAEA,aAAqB,GAAU;EAEzB,MAAE,WAAW,EAAE,kBAGnB,EAAE,eAAe,GACb,MAAK,gBACT;OAAI,KAAK,YAAY;IACnB,KAAK,eAAe,EAAK;IACzB;GACF;GAEA,AADA,KAAK,gBAAgB,KAAK,GAC1B,KAAK,MAAM;EAFX;CAGF;CAEA,oBAA4B,GAAe;EACrC,MAAE,WAAY,EAAE,iBAChB,MAAK,iBACT;OAAI,KAAK,YAAY;IACnB,KAAK,eAAe,EAAK;IACzB;GACF;GAEA,AADA,KAAK,gBAAgB,KAAK,GAC1B,KAAK,MAAM;EAFX;CAGF;CAGA,eAAuB,IAAO,KAAK,MAAM;EACvC,EAAwB,MAAM,CAAI;CACpC;CA+BA,gBAAwB,IAAS,KAAK,MAAM;EAC1C,KAAK,YAAY,KAAK,KAAU,CAAC,KAAK,YAAY;CACpD;CAEA,kBAA0B,GAAU;EAC5B,EAAE,kBAAkB,oBAC1B,KAAK,WAAW,EAAE,OAAO,iBAAiB,CAAC,CAAC,SAAS;CACvD;CAEA,SAAkB;EAChB,OAAO,CAAI;;kBAEG,KAAK,aAAa;iBACnB,KAAK,eAAe;iBACpB,KAAK,oBAAoB;yBACjB,KAAK,iBAAiB;;;YAInC,KAAK,WACD,CAAI,iCAAiC,KAAK,kBAAkB,YAC5D,CAAI;kDAC8B,KAAK,kBAAkB;;;;kBAK9D;;;;CAIT;AAKF;AArJG,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,QAAA,KAAA,CAAA,GACzC,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;CAAM,WAAW;AAAiB,CAAC,CAAA,GAAA,EAAA,WAAA,gBAAA,KAAA,CAAA,GACtE,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;CAAM,WAAW;AAAoB,CAAC,CAAA,GAAA,EAAA,WAAA,mBAAA,KAAA,CAAA,GACzE,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;CAAM,WAAW;AAAkB,CAAC,CAAA,GAAA,EAAA,WAAA,iBAAA,KAAA,CAAA,GAOvE,EAAA,CAAA,EAAS;CAAE,MAAM;CAAS,SAAS;AAAK,CAAC,CAAA,GAAA,EAAA,WAAA,cAAA,KAAA,CAAA,GAEzC,EAAA,CAAA,EAAM,CAAA,GAAA,EAAA,WAAA,YAAA,KAAA,CAAA,GAhBR,IAAA,EAAA,CAAA,EAAc,eAAe,CAAA,GAAA,CAAA"}