@greypan/web-ui 11.0.0 → 11.2.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 (173) hide show
  1. package/README.CN.md +105 -41
  2. package/README.md +69 -0
  3. package/dist/assets/overlay-motion.js +1 -1
  4. package/dist/assets/overlay-motion.js.map +1 -1
  5. package/dist/assets/selection-control.js +1 -1
  6. package/dist/assets/selection-control.js.map +1 -1
  7. package/dist/classes/glass.js +6 -0
  8. package/dist/classes/glass.js.map +1 -0
  9. package/dist/classes/glow.js +6 -0
  10. package/dist/classes/glow.js.map +1 -0
  11. package/dist/classes/style.css +1 -0
  12. package/dist/components/autocomplete/index.d.ts +7 -0
  13. package/dist/components/autocomplete/index.js +33 -13
  14. package/dist/components/autocomplete/index.js.map +1 -1
  15. package/dist/components/autocomplete/style.js +1 -1
  16. package/dist/components/autocomplete/style.js.map +1 -1
  17. package/dist/components/avatar/index.js +2 -2
  18. package/dist/components/avatar/index.js.map +1 -1
  19. package/dist/components/avatar/style.js +1 -1
  20. package/dist/components/avatar/style.js.map +1 -1
  21. package/dist/components/back-top/index.d.ts +4 -0
  22. package/dist/components/back-top/index.js +60 -22
  23. package/dist/components/back-top/index.js.map +1 -1
  24. package/dist/components/back-top/style.js +1 -1
  25. package/dist/components/back-top/style.js.map +1 -1
  26. package/dist/components/badge/index.d.ts +3 -0
  27. package/dist/components/badge/index.js +29 -14
  28. package/dist/components/badge/index.js.map +1 -1
  29. package/dist/components/badge/style.js +1 -1
  30. package/dist/components/badge/style.js.map +1 -1
  31. package/dist/components/button/index.d.ts +3 -0
  32. package/dist/components/button/index.js +27 -18
  33. package/dist/components/button/index.js.map +1 -1
  34. package/dist/components/button/style.js +1 -1
  35. package/dist/components/button/style.js.map +1 -1
  36. package/dist/components/button-group/index.d.ts +3 -0
  37. package/dist/components/button-group/index.js +15 -2
  38. package/dist/components/button-group/index.js.map +1 -1
  39. package/dist/components/button-group/style.js +1 -1
  40. package/dist/components/button-group/style.js.map +1 -1
  41. package/dist/components/checkbox/index.js +6 -6
  42. package/dist/components/checkbox/index.js.map +1 -1
  43. package/dist/components/checkbox/style.js +1 -1
  44. package/dist/components/checkbox/style.js.map +1 -1
  45. package/dist/components/collapse/index.d.ts +15 -7
  46. package/dist/components/collapse/index.js +44 -26
  47. package/dist/components/collapse/index.js.map +1 -1
  48. package/dist/components/collapse/style.js +1 -1
  49. package/dist/components/collapse/style.js.map +1 -1
  50. package/dist/components/dialog/index.d.ts +1 -0
  51. package/dist/components/dialog/index.js +5 -2
  52. package/dist/components/dialog/index.js.map +1 -1
  53. package/dist/components/dialog/style.js +1 -1
  54. package/dist/components/dialog/style.js.map +1 -1
  55. package/dist/components/drawer/index.js +1 -1
  56. package/dist/components/drawer/index.js.map +1 -1
  57. package/dist/components/dropdown/index.d.ts +16 -0
  58. package/dist/components/dropdown/index.js +147 -18
  59. package/dist/components/dropdown/index.js.map +1 -1
  60. package/dist/components/dropdown-item/style.js +1 -1
  61. package/dist/components/dropdown-item/style.js.map +1 -1
  62. package/dist/components/editable-text/index.js +7 -3
  63. package/dist/components/editable-text/index.js.map +1 -1
  64. package/dist/components/editable-text/style.js +1 -1
  65. package/dist/components/editable-text/style.js.map +1 -1
  66. package/dist/components/empty/index.d.ts +10 -22
  67. package/dist/components/empty/index.js +19 -35
  68. package/dist/components/empty/index.js.map +1 -1
  69. package/dist/components/empty/style.js +1 -1
  70. package/dist/components/empty/style.js.map +1 -1
  71. package/dist/components/image-preview/index.js +2 -2
  72. package/dist/components/image-preview/index.js.map +1 -1
  73. package/dist/components/input/index.d.ts +1 -0
  74. package/dist/components/input/index.js +5 -2
  75. package/dist/components/input/index.js.map +1 -1
  76. package/dist/components/input/style.js +1 -1
  77. package/dist/components/input/style.js.map +1 -1
  78. package/dist/components/input-number/index.d.ts +31 -1
  79. package/dist/components/input-number/index.js +281 -22
  80. package/dist/components/input-number/index.js.map +1 -1
  81. package/dist/components/input-number/style.js +1 -1
  82. package/dist/components/input-number/style.js.map +1 -1
  83. package/dist/components/layout/index.js +44 -39
  84. package/dist/components/layout/index.js.map +1 -1
  85. package/dist/components/layout/style.js +1 -1
  86. package/dist/components/layout/style.js.map +1 -1
  87. package/dist/components/middle-ellipsis/index.d.ts +8 -1
  88. package/dist/components/middle-ellipsis/index.js +68 -10
  89. package/dist/components/middle-ellipsis/index.js.map +1 -1
  90. package/dist/components/option/style.js +1 -1
  91. package/dist/components/option/style.js.map +1 -1
  92. package/dist/components/popover/index.js +1 -1
  93. package/dist/components/popover/index.js.map +1 -1
  94. package/dist/components/popover/style.js +1 -1
  95. package/dist/components/popover/style.js.map +1 -1
  96. package/dist/components/radio/index.d.ts +5 -0
  97. package/dist/components/radio/index.js +33 -23
  98. package/dist/components/radio/index.js.map +1 -1
  99. package/dist/components/radio/interaction.d.ts +4 -0
  100. package/dist/components/radio/interaction.js +17 -0
  101. package/dist/components/radio/interaction.js.map +1 -0
  102. package/dist/components/radio/style.js +1 -1
  103. package/dist/components/radio/style.js.map +1 -1
  104. package/dist/components/radio-group/index.d.ts +22 -0
  105. package/dist/components/radio-group/index.js +219 -28
  106. package/dist/components/radio-group/index.js.map +1 -1
  107. package/dist/components/segmented/index.d.ts +2 -0
  108. package/dist/components/segmented/index.js +74 -18
  109. package/dist/components/segmented/index.js.map +1 -1
  110. package/dist/components/segmented/style.js +1 -1
  111. package/dist/components/segmented/style.js.map +1 -1
  112. package/dist/components/segmented-trigger/index.js +3 -2
  113. package/dist/components/segmented-trigger/index.js.map +1 -1
  114. package/dist/components/segmented-trigger/style.js +1 -1
  115. package/dist/components/segmented-trigger/style.js.map +1 -1
  116. package/dist/components/select/index.d.ts +8 -0
  117. package/dist/components/select/index.js +76 -25
  118. package/dist/components/select/index.js.map +1 -1
  119. package/dist/components/select/style.js +1 -1
  120. package/dist/components/select/style.js.map +1 -1
  121. package/dist/components/slider/index.d.ts +15 -0
  122. package/dist/components/slider/index.js +175 -39
  123. package/dist/components/slider/index.js.map +1 -1
  124. package/dist/components/slider/style.js +1 -1
  125. package/dist/components/slider/style.js.map +1 -1
  126. package/dist/components/spinner/index.d.ts +15 -0
  127. package/dist/components/spinner/index.js +79 -22
  128. package/dist/components/spinner/index.js.map +1 -1
  129. package/dist/components/spinner/style.js +1 -1
  130. package/dist/components/spinner/style.js.map +1 -1
  131. package/dist/components/svg-draw-lines/index.js +48 -12
  132. package/dist/components/svg-draw-lines/index.js.map +1 -1
  133. package/dist/components/switch/index.d.ts +11 -3
  134. package/dist/components/switch/index.js +57 -53
  135. package/dist/components/switch/index.js.map +1 -1
  136. package/dist/components/switch/style.js +1 -1
  137. package/dist/components/switch/style.js.map +1 -1
  138. package/dist/components/textarea/index.js +2 -2
  139. package/dist/components/textarea/index.js.map +1 -1
  140. package/dist/components/textarea/style.js +1 -1
  141. package/dist/components/textarea/style.js.map +1 -1
  142. package/dist/components/theme/index.d.ts +1 -0
  143. package/dist/components/theme/index.js +26 -15
  144. package/dist/components/theme/index.js.map +1 -1
  145. package/dist/components/theme/style.js +1 -1
  146. package/dist/components/theme/style.js.map +1 -1
  147. package/dist/components/toast/style.js +1 -1
  148. package/dist/components/toast/style.js.map +1 -1
  149. package/dist/components/toast/toast.js +1 -1
  150. package/dist/components/toast/toast.js.map +1 -1
  151. package/dist/components/tooltip/index.d.ts +1 -0
  152. package/dist/components/tooltip/index.js +10 -5
  153. package/dist/components/tooltip/index.js.map +1 -1
  154. package/dist/icons/generated/andrsrxn-inbox.d.ts +6 -0
  155. package/dist/icons/generated/andrsrxn-inbox.js +10 -0
  156. package/dist/icons/generated/andrsrxn-inbox.js.map +1 -0
  157. package/dist/icons/index.d.ts +1 -0
  158. package/dist/icons/index.js +75 -74
  159. package/dist/shared/focus/pointer-focus.js +12 -10
  160. package/dist/shared/focus/pointer-focus.js.map +1 -1
  161. package/dist/shared/gesture/drag-gesture.js +4 -4
  162. package/dist/shared/gesture/drag-gesture.js.map +1 -1
  163. package/dist/shared/group-management/index.js +43 -18
  164. package/dist/shared/group-management/index.js.map +1 -1
  165. package/dist/shared/menu-portal/menu-portal.js +1 -1
  166. package/dist/shared/menu-portal/menu-portal.js.map +1 -1
  167. package/dist/shared/overlay/overlay-root.js +1 -1
  168. package/dist/shared/overlay/overlay-root.js.map +1 -1
  169. package/dist/shared/overlay/overlay.js +7 -1
  170. package/dist/shared/overlay/overlay.js.map +1 -1
  171. package/package.json +5 -1
  172. package/dist/assets/glass.js +0 -6
  173. package/dist/assets/glass.js.map +0 -1
@@ -14,7 +14,27 @@ import O from "./style.js";
14
14
  import { LitElement as k, html as A, unsafeCSS as j } from "lit";
15
15
  import { customElement as M, property as N, state as P } from "lit/decorators.js";
16
16
  //#region src/components/dropdown/index.ts
17
- var F = "web-ui-menu-level-", I = "wui-dropdown-menu-item", L = 0, R = class extends k {
17
+ var F = "web-ui-menu-level-", I = "wui-dropdown-menu-item";
18
+ function L(e) {
19
+ return e instanceof Element && e.assignedSlot ? e.assignedSlot : e.parentNode instanceof ShadowRoot ? e.parentNode.host : e.parentNode;
20
+ }
21
+ function R(e, t) {
22
+ let n = e;
23
+ for (; n;) {
24
+ if (n === t) return !0;
25
+ n = L(n);
26
+ }
27
+ return !1;
28
+ }
29
+ function z(e) {
30
+ let t = e;
31
+ for (; t;) {
32
+ if (t instanceof HTMLDialogElement && t.open && t.matches(":modal")) return !0;
33
+ t = L(t);
34
+ }
35
+ return !1;
36
+ }
37
+ var B = 0, V = class extends k {
18
38
  constructor(...e) {
19
39
  super(...e), this.open = !1, this.disabled = !1, this.matchWidth = !1, this.noScrollLock = !1, this._placement = "bottom-start", this._offset = 4, this._activePath = [], this._overlays = /* @__PURE__ */ new Map(), this._overlay = s().make({
20
40
  requestClose: () => this._keyboardDelegate.closeDeepestOrAll(),
@@ -48,11 +68,14 @@ var F = "web-ui-menu-level-", I = "wui-dropdown-menu-item", L = 0, R = class ext
48
68
  let n = this._getLevelItems(t).indexOf(e);
49
69
  n >= 0 && this._toggleSubmenu(t, n, !0);
50
70
  },
51
- closeToParent: (e) => (this._closeSubmenuFrom(e), this._getLevelItems(e - 1)[this._activePath[e - 1]]),
71
+ closeToParent: (e) => {
72
+ let t = this._getLevelItems(e - 1)[this._activePath[e - 1]];
73
+ return this._closeSubmenuFrom(e), t;
74
+ },
52
75
  closeDeepestOrAll: () => {
53
76
  this._activePath.length > 0 ? this._closeSubmenuFrom(this._activePath.length) : this._closeAll(!0);
54
77
  }
55
- }, this._userOpenChange = new l(), this._shouldOpenInstantly = !0, this._suppressInitialFocusVisible = !0, this._menuSyncScheduled = !1, this._level0ItemAnchors = /* @__PURE__ */ new Map(), this._menuContentObserver = new MutationObserver(() => {
78
+ }, this._userOpenChange = new l(), this._skipFocusRestoreOnClose = !1, this._shouldOpenInstantly = !0, this._suppressInitialFocusVisible = !0, this._menuSyncScheduled = !1, this._level0ItemAnchors = /* @__PURE__ */ new Map(), this._menuContentObserver = new MutationObserver(() => {
56
79
  this.open && this._scheduleMenuSync();
57
80
  }), this._onTriggerClick = (e) => {
58
81
  if (!this.disabled) {
@@ -63,7 +86,61 @@ var F = "web-ui-menu-level-", I = "wui-dropdown-menu-item", L = 0, R = class ext
63
86
  }
64
87
  }
65
88
  }, this._onClickOutside = (e) => {
66
- this.isOpen && !this._outsideClickGuard.isArmed() && (this._outsideClickGuard.isInside(e) || this._closeAll(!0));
89
+ this._pointerInteraction && (this._pointerInteraction.completed = !0, this._pointerInteraction.clickInsideMenu = this._outsideClickGuard.isInside(e), this._pointerInteraction = void 0, this._resumePendingFocusOutCheck()), this.isOpen && !this._outsideClickGuard.isArmed() && (this._outsideClickGuard.isInside(e) || this._closeAll(!0));
90
+ }, this._onPointerDown = (e) => {
91
+ let t = !!(this.open && this._handle?.containsEvent(e));
92
+ this._pointerInteraction = {
93
+ startedInsideMenu: t,
94
+ startedWithinDropdown: !!(this.open && (t || e.composedPath().includes(this))),
95
+ completed: !1
96
+ };
97
+ }, this._onPointerUp = (e) => {
98
+ let t = this._pointerInteraction;
99
+ t && (t.completed = !0, t.clickInsideMenu = !!this._handle?.containsEvent(e), this._pointerInteraction = void 0, this._resumePendingFocusOutCheck());
100
+ }, this._onPointerCancel = () => {
101
+ let e = this._pointerInteraction;
102
+ e && (e.completed = !0, e.clickInsideMenu = e.startedInsideMenu, this._pointerInteraction = void 0, this._resumePendingFocusOutCheck());
103
+ }, this._onFocusOut = (e) => {
104
+ let t = this._handle;
105
+ if (!this.open || !t?.containsEvent(e)) return;
106
+ let n = this._pointerInteraction, r = e.composedPath()[0];
107
+ if (r instanceof Node && !r.isConnected) return;
108
+ let i = e.relatedTarget;
109
+ if (i instanceof Node && [...this._overlays.values()].some(({ overlay: e }) => R(i, e))) return;
110
+ let a = i instanceof Node;
111
+ a && (this._skipFocusRestoreOnClose = !0);
112
+ let o = () => {
113
+ if (this.open && this._handle === t) {
114
+ if (this._pendingTabNavigation) {
115
+ this._pendingFocusOutCheck = () => this._overlay.scheduleFrame(o);
116
+ return;
117
+ }
118
+ if (n?.startedWithinDropdown) {
119
+ if (!n.completed) {
120
+ this._pendingFocusOutCheck = () => this._overlay.scheduleFrame(o);
121
+ return;
122
+ }
123
+ if (n.clickInsideMenu) return;
124
+ }
125
+ if (t.hasFocusWithin()) {
126
+ a && (this._skipFocusRestoreOnClose = !1);
127
+ return;
128
+ }
129
+ this._skipFocusRestoreOnClose = !0, this._closeAll(!0);
130
+ }
131
+ };
132
+ this._overlay.scheduleFrame(o);
133
+ }, this._onFocusIn = (e) => {
134
+ let t = this._handle;
135
+ if (!this.open || !t) return;
136
+ if (!t.containsEvent(e)) {
137
+ if (this._pendingTabNavigation || this._pointerInteraction?.startedWithinDropdown && !this._pointerInteraction.completed) return;
138
+ this._skipFocusRestoreOnClose = !0, this._closeAll(!0);
139
+ return;
140
+ }
141
+ this._skipFocusRestoreOnClose = !1;
142
+ let n = p(e);
143
+ n && this._setMenuTabStop(n);
67
144
  }, this._onMenuClick = (e) => {
68
145
  let t = p(e);
69
146
  if (!t || t.hasAttribute("disabled") || !t.hasAttribute("submenu")) return;
@@ -72,7 +149,26 @@ var F = "web-ui-menu-level-", I = "wui-dropdown-menu-item", L = 0, R = class ext
72
149
  let r = this._getLevelItems(n).indexOf(t);
73
150
  r >= 0 && this._toggleSubmenu(n, r, e.detail === 0);
74
151
  }, this._onKeydown = (e) => {
75
- !this.disabled && this.open && T(this._keyboardDelegate, e);
152
+ this.open && e.key !== "Tab" && (this.disabled || T(this._keyboardDelegate, e));
153
+ }, this._onTabKeydown = (e) => {
154
+ if (e.key !== "Tab" || !this.open || e.defaultPrevented) return;
155
+ let t = p(e);
156
+ if (!t || this._getFocusedLevel(t) === void 0) return;
157
+ let n = [...this._overlays.values()].some(({ overlay: e }) => z(e)), r = {
158
+ event: e,
159
+ focusedItem: t,
160
+ previousFocus: t.shadowRoot?.activeElement instanceof HTMLElement ? t.shadowRoot.activeElement : this._getDeepActiveElement(),
161
+ focusTrigger: !n || !e.shiftKey
162
+ };
163
+ this._pendingTabNavigation = r, this._setMenuTabStop(), r.focusTrigger && this._focusTriggerForTab(), setTimeout(() => {
164
+ if (this._pendingTabNavigation === r) {
165
+ if (this._pendingTabNavigation = void 0, e.defaultPrevented) {
166
+ this._setMenuTabStop(t), r.previousFocus?.isConnected && this._getDeepActiveElement() !== r.previousFocus && r.previousFocus.focus();
167
+ return;
168
+ }
169
+ r.focusTrigger || !this._handle?.hasFocusWithin() ? (this._skipFocusRestoreOnClose = !0, this._closeAll(!0)) : this._setMenuTabStop(t);
170
+ }
171
+ }, 0);
76
172
  };
77
173
  }
78
174
  static {
@@ -94,7 +190,7 @@ var F = "web-ui-menu-level-", I = "wui-dropdown-menu-item", L = 0, R = class ext
94
190
  return this.open || this._activePath.length > 0;
95
191
  }
96
192
  connectedCallback() {
97
- super.connectedCallback(), this._overlay.resume(), this.addEventListener("keydown", this._onKeydown), document.addEventListener("click", this._onClickOutside), this._menuContentObserver.observe(this, {
193
+ super.connectedCallback(), this._overlay.resume(), this.addEventListener("keydown", this._onKeydown), window.addEventListener("keydown", this._onTabKeydown), document.addEventListener("pointerdown", this._onPointerDown, !0), document.addEventListener("pointerup", this._onPointerUp, !0), document.addEventListener("pointercancel", this._onPointerCancel, !0), document.addEventListener("click", this._onClickOutside), document.addEventListener("focusin", this._onFocusIn, !0), document.addEventListener("focusout", this._onFocusOut, !0), this._menuContentObserver.observe(this, {
98
194
  childList: !0,
99
195
  subtree: !0
100
196
  }), this.open && this.hasUpdated && this._syncOpenOverlay(this._isFocusOrphaned());
@@ -103,10 +199,10 @@ var F = "web-ui-menu-level-", I = "wui-dropdown-menu-item", L = 0, R = class ext
103
199
  this.shadowRoot?.querySelector("slot[name=\"trigger\"]")?.addEventListener("slotchange", () => this.requestUpdate());
104
200
  }
105
201
  disconnectedCallback() {
106
- super.disconnectedCallback(), this._menuContentObserver.disconnect(), this.removeEventListener("keydown", this._onKeydown), document.removeEventListener("click", this._onClickOutside), this._outsideClickGuard.dispose(), this._hoverBinder.dispose(), this._overlay.suspend(), this._scrollLock.release(), this._cleanupClosedMenu();
202
+ super.disconnectedCallback(), this._menuContentObserver.disconnect(), this._pointerInteraction = void 0, this._pendingFocusOutCheck = void 0, this._pendingTabNavigation = void 0, this.removeEventListener("keydown", this._onKeydown), window.removeEventListener("keydown", this._onTabKeydown), document.removeEventListener("pointerdown", this._onPointerDown, !0), document.removeEventListener("pointerup", this._onPointerUp, !0), document.removeEventListener("pointercancel", this._onPointerCancel, !0), document.removeEventListener("click", this._onClickOutside), document.removeEventListener("focusin", this._onFocusIn, !0), document.removeEventListener("focusout", this._onFocusOut, !0), this._outsideClickGuard.dispose(), this._hoverBinder.dispose(), this._overlay.suspend(), this._scrollLock.release(), this._cleanupClosedMenu();
107
203
  }
108
204
  updated(e) {
109
- this._syncTriggerAria(), e.has("open") && (this.open ? this._syncOpenOverlay(!0) : (this._overlay.invalidate(), this._syncScrollLock(), this._suppressInitialFocusVisible = !0, this._handle?.release(), this._handle = null, this._closeRootAfterPresence()), this._userOpenChange.consume() && r(this, this.open)), e.has("noScrollLock") && this._syncScrollLock(), (e.has("placement") || e.has("offset") || e.has("matchWidth")) && this._overlays.get(0)?.api.update({
205
+ this._syncTriggerAria(), e.has("open") && (this.open ? (this._skipFocusRestoreOnClose = !1, this._syncOpenOverlay(!0)) : (this._overlay.invalidate(), this._syncScrollLock(), this._suppressInitialFocusVisible = !0, this._handle?.release(), this._handle = null, this._closeRootAfterPresence()), this._userOpenChange.consume() && r(this, this.open)), e.has("noScrollLock") && this._syncScrollLock(), (e.has("placement") || e.has("offset") || e.has("matchWidth")) && this._overlays.get(0)?.api.update({
110
206
  placement: this.placement,
111
207
  offset: this.offset,
112
208
  matchWidth: this.matchWidth
@@ -116,8 +212,16 @@ var F = "web-ui-menu-level-", I = "wui-dropdown-menu-item", L = 0, R = class ext
116
212
  let e = document.activeElement;
117
213
  return e === null || e === document.body || e === document.documentElement;
118
214
  }
215
+ _getDeepActiveElement() {
216
+ let e = document.activeElement;
217
+ for (; e instanceof HTMLElement;) {
218
+ let t = e.shadowRoot?.activeElement;
219
+ if (!(t instanceof HTMLElement)) return e;
220
+ e = t;
221
+ }
222
+ }
119
223
  _syncOpenOverlay(e) {
120
- this._restoreFocusTarget ??= document.activeElement instanceof HTMLElement ? document.activeElement : void 0, this._outsideClickGuard.arm(), this._syncScrollLock(), this._hideAllSubmenuChildren(), this._overlay.invalidate(), this._overlay.scheduleFrame(() => {
224
+ this._restoreFocusTarget ??= this._getDeepActiveElement(), this._outsideClickGuard.arm(), this._syncScrollLock(), this._hideAllSubmenuChildren(), this._overlay.invalidate(), this._overlay.scheduleFrame(() => {
121
225
  this._ensureOverlay(0, this._shouldOpenInstantly), this._shouldOpenInstantly = !0, e && d(C(this._overlays.get(0)?.content)[0], { suppressFocusVisible: this._suppressInitialFocusVisible }), this._syncTriggerAria();
122
226
  }), this._bindHoversAfterUpdate();
123
227
  }
@@ -137,11 +241,19 @@ var F = "web-ui-menu-level-", I = "wui-dropdown-menu-item", L = 0, R = class ext
137
241
  this._closeSubmenuFrom(1, !0), this._closingSubmenus.restoreAll(), this._syncActiveAttrs();
138
242
  }
139
243
  _cleanupClosedMenu() {
140
- this._closeAllSubmenus(), this._returnLevel0Items(), this._disposeAll();
244
+ this._closeAllSubmenus(), this._returnLevel0Items(), this._resetMenuTabStops(), this._disposeAll(), this._syncTriggerAria();
245
+ }
246
+ _resetMenuTabStops() {
247
+ this.querySelectorAll("web-ui-dropdown-item").forEach((e) => {
248
+ let t = e.shadowRoot?.querySelector("[role=\"menuitem\"]");
249
+ t && (t.tabIndex = e.hasAttribute("disabled") ? -1 : 0);
250
+ });
141
251
  }
142
252
  async _closeRootAfterPresence() {
143
253
  let e = this._overlays.get(0)?.overlay;
144
- (!e || await a(e)) && !this.open && this.isConnected && (this._cleanupClosedMenu(), this._restoreFocusTarget?.focus(), this._restoreFocusTarget = void 0);
254
+ if (e && !await a(e) || this.open || !this.isConnected) return;
255
+ let t = [...this._overlays.values(), ...this._closingSubmenus.closing()].some((e) => e.overlay.matches(":focus-within"));
256
+ this._cleanupClosedMenu(), t && !this._skipFocusRestoreOnClose && this._restoreFocusTarget?.focus(), this._skipFocusRestoreOnClose = !1, this._restoreFocusTarget = void 0;
145
257
  }
146
258
  _hideAllSubmenuChildren() {
147
259
  m(this, `${F}-hidden`);
@@ -230,7 +342,7 @@ var F = "web-ui-menu-level-", I = "wui-dropdown-menu-item", L = 0, R = class ext
230
342
  }
231
343
  _buildOverlay(e, t = !1) {
232
344
  let { panel: n, content: r } = E("dropdown-overlay", this);
233
- n.setAttribute("role", "menu"), e === 0 && (n.id = `wui-dropdown-menu-${++L}`), n.dataset.level = String(e), n.addEventListener("click", this._onMenuClick), n.addEventListener("keydown", this._onKeydown);
345
+ n.setAttribute("role", "menu"), e === 0 && (n.id = `wui-dropdown-menu-${++B}`), n.dataset.level = String(e), n.addEventListener("click", this._onMenuClick), n.addEventListener("keydown", this._onKeydown);
234
346
  let a = e === 0 ? this._queryTriggerAnchor() : this._getSubmenuTriggerAnchor(e - 1);
235
347
  if (a) {
236
348
  let s = i().make({
@@ -287,6 +399,13 @@ var F = "web-ui-menu-level-", I = "wui-dropdown-menu-item", L = 0, R = class ext
287
399
  let e = (this.shadowRoot?.querySelector("slot[name=\"trigger\"]"))?.assignedElements()[0];
288
400
  return e instanceof HTMLElement ? e : null;
289
401
  }
402
+ _focusTriggerForTab() {
403
+ let e = this._queryTriggerAnchor();
404
+ if (!e) return;
405
+ e.focus();
406
+ let t = this._getDeepActiveElement();
407
+ t && R(t, e) || (e.shadowRoot?.querySelector("button:not(:disabled), input:not(:disabled), select:not(:disabled), textarea:not(:disabled), a[href], [tabindex]:not([tabindex=\"-1\"])"))?.focus();
408
+ }
290
409
  _syncTriggerAria() {
291
410
  let e = this._queryTriggerAnchor();
292
411
  if (!e) return;
@@ -300,6 +419,16 @@ var F = "web-ui-menu-level-", I = "wui-dropdown-menu-item", L = 0, R = class ext
300
419
  let n = this._getLevelItems(e)[t];
301
420
  return n ? n.shadowRoot?.querySelector(".item-inner") ?? n : null;
302
421
  }
422
+ _resumePendingFocusOutCheck() {
423
+ let e = this._pendingFocusOutCheck;
424
+ this._pendingFocusOutCheck = void 0, e?.();
425
+ }
426
+ _setMenuTabStop(e) {
427
+ for (let { content: t } of this._overlays.values()) t.querySelectorAll("web-ui-dropdown-item").forEach((t) => {
428
+ let n = t.shadowRoot?.querySelector("[role=\"menuitem\"]");
429
+ n && (n.tabIndex = t === e && !t.hasAttribute("disabled") ? 0 : -1);
430
+ });
431
+ }
303
432
  _getFocusedLevel(e) {
304
433
  if (e) return [...this._overlays.entries()].find(([, t]) => t.overlay.contains(e))?.[0];
305
434
  }
@@ -317,22 +446,22 @@ var F = "web-ui-menu-level-", I = "wui-dropdown-menu-item", L = 0, R = class ext
317
446
  e([N({
318
447
  type: Boolean,
319
448
  reflect: !0
320
- })], R.prototype, "open", void 0), e([N({
449
+ })], V.prototype, "open", void 0), e([N({
321
450
  type: Boolean,
322
451
  reflect: !0
323
- })], R.prototype, "disabled", void 0), e([N({
452
+ })], V.prototype, "disabled", void 0), e([N({
324
453
  type: Boolean,
325
454
  reflect: !0,
326
455
  attribute: "match-width"
327
- })], R.prototype, "matchWidth", void 0), e([N({
456
+ })], V.prototype, "matchWidth", void 0), e([N({
328
457
  type: Boolean,
329
458
  reflect: !0,
330
459
  attribute: "no-scroll-lock"
331
- })], R.prototype, "noScrollLock", void 0), e([N({
460
+ })], V.prototype, "noScrollLock", void 0), e([N({
332
461
  type: String,
333
462
  reflect: !0
334
- })], R.prototype, "placement", null), e([N({ type: Number })], R.prototype, "offset", null), e([P()], R.prototype, "_activePath", void 0), R = e([M("web-ui-dropdown")], R);
463
+ })], V.prototype, "placement", null), e([N({ type: Number })], V.prototype, "offset", null), e([P()], V.prototype, "_activePath", void 0), V = e([M("web-ui-dropdown")], V);
335
464
  //#endregion
336
- export { R as WebUiDropdown };
465
+ export { V as WebUiDropdown };
337
466
 
338
467
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/dropdown/index.ts"],"sourcesContent":["import type { Placement } from '@floating-ui/dom'\nimport { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\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 } 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 type MenuItemAnchors\n} from '@/shared/menu-portal/menu-tree'\nimport { normalizeLiteral, normalizeNumber } from '@/shared/normalize'\nimport { dispatchOpenChangeEvent } from '@/shared/open-state'\nimport { defineOpenOverlay, type OpenOverlayHandle } from '@/shared/overlay/open-overlay'\nimport { defineOverlay, type OverlayApi } from '@/shared/overlay/overlay'\nimport { FLOATING_PLACEMENTS } from '@/shared/overlay/placement-props'\nimport { hideOverlayPresence, showOverlayPresence } from '@/shared/overlay/presence'\nimport { defineScrollLockLease } from '@/shared/scroll-lock/scroll-lock'\n\nimport style from './style.css?inline'\n\nexport type { Placement }\n\nconst SLOT_PREFIX = 'web-ui-menu-level-'\n// 一级 menu item 的模板位 marker(机制与 context-menu 共用,见 menu-tree 的托管项锚说明)。\nconst MENU_ITEM_MARKER = 'wui-dropdown-menu-item'\n\nlet dropdownIdCounter = 0\n\ninterface MenuOverlay {\n api: OverlayApi\n overlay: HTMLElement\n content: HTMLElement\n /** 该层为 submenu 时的会话 handle;根层 handle 由组件单独持有(见 `_handle`)。 */\n handle?: OpenOverlayHandle\n}\n\n@customElement('web-ui-dropdown')\nexport class WebUiDropdown extends LitElement {\n static override styles = unsafeCSS(style)\n\n @property({ type: Boolean, reflect: true }) open = false\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true, attribute: 'match-width' }) matchWidth = false\n @property({ type: Boolean, reflect: true, attribute: 'no-scroll-lock' }) noScrollLock = false\n\n private _placement: Placement = 'bottom-start'\n\n @property({ type: String, reflect: true })\n get placement(): Placement {\n return this._placement\n }\n set placement(v: string) {\n this._placement = normalizeLiteral(v, FLOATING_PLACEMENTS, 'bottom-start')\n }\n\n private _offset = 4\n\n @property({ type: Number })\n get offset(): number {\n return this._offset\n }\n set offset(v: number) {\n this._offset = normalizeNumber(v, 0, 100, 4)\n }\n\n @state() private _activePath: number[] = []\n\n private readonly _overlays = new Map<number, MenuOverlay>()\n /** 实例作用域的帧事务入口(合并了原 lifecycle)。 */\n private readonly _overlay = defineOpenOverlay().make({\n requestClose: () => this._keyboardDelegate.closeDeepestOrAll(),\n isConnected: () => this.isConnected\n })\n private readonly _scrollLock = defineScrollLockLease().make()\n /**\n * 当前 Escape 候选的会话 handle(level 0)。panel 要等一帧才建好,而 Escape 可能在这之前\n * 到达:先以宿主为 panel claim 一次,panel 就绪后 release 旧会话、再以真实 panel 重新 claim。\n * submenu 的 handle 存在各自 `MenuOverlay.handle` 上(经 adopt 进本 handle 子树)。\n */\n private _handle: OpenOverlayHandle | null = null\n // 行为层(hover / outside-click / 键盘 / submenu 收尾)由 shared/menu-behavior 驱动\n private readonly _outsideClickGuard = createMenuOutsideClickGuard(\n this,\n // 根 handle 的 contains 递归覆盖全部已 adopt 的子层,一次查询替代逐层判定。\n node => this._handle?.contains(node) ?? false\n )\n private readonly _closingSubmenus = createClosingSubmenuStack<MenuOverlay>({\n getPanel: container => container.overlay,\n restoreItems: (container, parentItem) => moveMenuChildren(container.content, parentItem),\n dispose: container => {\n container.handle?.release()\n container.overlay.remove()\n container.api.dispose()\n }\n })\n private readonly _hoverDelegate: MenuHoverDelegate = {\n getOpenDepth: () => this._activePath.length,\n getLevelItems: level => this._getLevelItems(level),\n getActiveItem: level => this._getLevelItems(level)[this._activePath[level]],\n isSubmenuItem: item => item.hasAttribute('submenu'),\n openSubmenu: item => {\n const level = this._getFocusedLevel(item)\n if (level === undefined) return\n const itemIndex = this._getLevelItems(level).indexOf(item)\n if (itemIndex >= 0) this._toggleSubmenu(level, itemIndex)\n },\n closeFrom: level => this._closeSubmenuFrom(level + 1)\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._overlays.values()].map(({ overlay }) => overlay),\n 'web-ui-dropdown-item'\n ),\n getLevelOf: item => this._getFocusedLevel(item),\n getEnabledItems: level => getEnabledMenuLevelItems(this._overlays.get(level)?.content),\n isSubmenuItem: item => item.hasAttribute('submenu'),\n openSubmenuInstant: item => {\n const level = this._getFocusedLevel(item)\n if (level === undefined) return\n const itemIndex = this._getLevelItems(level).indexOf(item)\n if (itemIndex >= 0) this._toggleSubmenu(level, itemIndex, true)\n },\n closeToParent: level => {\n this._closeSubmenuFrom(level)\n return this._getLevelItems(level - 1)[this._activePath[level - 1]]\n },\n closeDeepestOrAll: () => {\n if (this._activePath.length > 0) this._closeSubmenuFrom(this._activePath.length)\n else this._closeAll(true)\n }\n }\n private readonly _userOpenChange = new UserChangeController()\n private _restoreFocusTarget?: HTMLElement\n private _shouldOpenInstantly = true\n /**\n * 本次打开是否抑制首项的 `:focus-visible` accent 视觉(口径与 context-menu 一致)。\n *\n * 默认 `true`(抑制),只有键盘激活触发的打开才置 `false`:首项的焦点是组件程序化\n * 落的,而各引擎对「程序化 focus 是否算 focus-visible」判定不同 —— Chromium 走启发式\n * 通常不匹配,WKWebView 则会匹配(用户在 Interweave 桌面 app 实测到蓝底白字),\n * 于是同一段代码只在 WebKit 侧暴露出缺陷。取默认抑制而非默认保留,是因为冷启动的\n * `open` 属性路径拿不到任何手势模态信息,抑制是唯一确定安全的一侧;误伤键盘用户的\n * 代价有界:`handleMenuKeyboard` 首次方向键即以无参 `focusMenuItem` 重新落焦,\n * `menu-tree` 的 `toggleAttribute` 无条件清掉本属性,accent 当场回来。\n */\n private _suppressInitialFocusVisible = true\n private _menuSyncScheduled = false\n private readonly _level0ItemAnchors: MenuItemAnchors = new Map()\n // 打开期实时渲染:框架(Vue/React 条件渲染)可能在 menu 打开期间持续插入 menu item。\n // 观察宿主子树(新增项可能被框架 wrapper 包裹)与各层级 panel content 的子树\n // (打开中的 submenu 父项已被迁入 content,其新增子项只在这里可见),下一帧统一\n // 把新子树迁入对应层级 panel;panel 尺寸变化由 defineOverlay 的 autoUpdate 跟进重定位。\n private readonly _menuContentObserver = new MutationObserver(() => {\n if (this.open) this._scheduleMenuSync()\n })\n\n get isOpen(): boolean {\n return this.open || this._activePath.length > 0\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._overlay.resume()\n this.addEventListener('keydown', this._onKeydown)\n document.addEventListener('click', this._onClickOutside)\n this._menuContentObserver.observe(this, { childList: true, subtree: true })\n /*\n * 重挂载对账:`disconnectedCallback` 会拆掉 panel、把 menu item 迁回宿主,但 `open` 是公开\n * prop,不因卸载而改写。Lit 在 detach 期间不记 `changedProperties`,重连后 `updated()`\n * 不再命中 `changed.has('open')`,panel 于是永久缺席:宿主仍反射 `open` 与\n * `aria-expanded`,Escape 和 outside click 却无层可关。首连时 `open` 在\n * `changedProperties` 里、由 `updated()` 负责,`hasUpdated` 就是用来只认重连的。\n */\n if (this.open && this.hasUpdated) this._syncOpenOverlay(this._isFocusOrphaned())\n }\n\n override firstUpdated() {\n // trigger slot 内容增删不触发宿主响应式更新:显式请求一轮渲染,\n // 由 updated() 的 ARIA 回写覆盖晚到的 trigger 元素。\n this.shadowRoot\n ?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]')\n ?.addEventListener('slotchange', () => this.requestUpdate())\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._menuContentObserver.disconnect()\n this.removeEventListener('keydown', this._onKeydown)\n document.removeEventListener('click', this._onClickOutside)\n this._outsideClickGuard.dispose()\n this._hoverBinder.dispose()\n // 停止帧调度;登记由 _cleanupClosedMenu → _disposeAll 撤销。\n this._overlay.suspend()\n this._scrollLock.release()\n this._cleanupClosedMenu()\n }\n\n protected override updated(changed: Map<string, unknown>) {\n // ARIA 回写不依赖 open 分支,任何渲染后都保持与宿主状态同步。\n this._syncTriggerAria()\n\n if (changed.has('open')) {\n if (this.open) {\n this._syncOpenOverlay(true)\n } else {\n this._overlay.invalidate()\n this._syncScrollLock()\n /*\n * 复位打开模态:`open` 真正翻回 false 才是「上一次打开会话结束」的唯一信号,\n * 下一会话若不经 `_openMenu()`(宿主直接翻 `open` 属性)就从默认口径重新起算,\n * 不会把上一次键盘打开留下的 `false` 带进这次鼠标驱动的声明式打开。\n * 刻意不复位在 `disconnectedCallback`/`_cleanupClosedMenu`:重挂载对账(:188)\n * 期间 `open` 始终为 true,那次重取焦点属于同一会话,应保留原模态。\n */\n this._suppressInitialFocusVisible = true\n /*\n * release ⟺ 关闭:新模块里「已登记」就等于「参与仲裁」,不再由 host.isOpen()\n * 兜底过滤,所以必须在这里撤销,不能等到退场动画结束。\n */\n this._handle?.release()\n this._handle = null\n void this._closeRootAfterPresence()\n }\n if (this._userOpenChange.consume()) {\n dispatchOpenChangeEvent(this, this.open)\n }\n }\n if (changed.has('noScrollLock')) this._syncScrollLock()\n if (changed.has('placement') || changed.has('offset') || changed.has('matchWidth')) {\n this._overlays.get(0)?.api.update({\n placement: this.placement,\n offset: this.offset,\n matchWidth: this.matchWidth\n })\n }\n this._hoverBinder.bind()\n }\n\n /**\n * 焦点是否已无归属:被 detach 打掉的焦点会落回 `body`,用户主动点到别处时不会。\n * 重挂载对账只在前者才把焦点夺回 menu,否则等于从消费者手里抢焦点。\n */\n private _isFocusOrphaned(): boolean {\n const active = document.activeElement\n return active === null || active === document.body || active === document.documentElement\n }\n\n /**\n * 打开态的唯一对账入口:panel、滚动锁、outside click、hover 与 menu 焦点都从这里收敛,\n * `updated()` 的打开分支与重连对账共用它,两条路径必须落到同一个状态。\n */\n private _syncOpenOverlay(takeFocus: boolean) {\n this._restoreFocusTarget ??= document.activeElement instanceof HTMLElement ? document.activeElement : undefined\n this._outsideClickGuard.arm()\n this._syncScrollLock()\n this._hideAllSubmenuChildren()\n this._overlay.invalidate()\n this._overlay.scheduleFrame(() => {\n this._ensureOverlay(0, this._shouldOpenInstantly)\n this._shouldOpenInstantly = true\n if (takeFocus) {\n focusMenuItem(getEnabledMenuLevelItems(this._overlays.get(0)?.content)[0], {\n suppressFocusVisible: this._suppressInitialFocusVisible\n })\n }\n // panel id 在 overlay 构建后才有:回写 aria-controls 指向。\n this._syncTriggerAria()\n })\n this._bindHoversAfterUpdate()\n }\n\n /*\n * 命令式打开,不派发 open-change。命令式入口没有手势模态信息,按与 context-menu 的\n * `openAt()` 同一口径抑制首项 accent。\n */\n openMenu() {\n this._openMenu(true, false, true)\n }\n\n private _openMenu(isInstant: boolean, fromUser: boolean, suppressFocusVisible: boolean) {\n if (this.disabled || this.open) return\n this._outsideClickGuard.arm()\n this._shouldOpenInstantly = isInstant\n this._suppressInitialFocusVisible = suppressFocusVisible\n if (fromUser) this._userOpenChange.mark()\n // panel 要等一帧才建好,而 Escape 可能在这之前到达:先用宿主当 panel claim 一次;\n // panel 就绪后 _buildOverlay 会 release 这个占位会话,再以真实 panel 重新 claim。\n this._claimRoot(this._overlays.get(0)?.overlay ?? this)\n this.open = true\n }\n\n // 命令式关闭全部层级,不派发 open-change。\n closeAll() {\n this._closeAll(false)\n }\n\n private _closeAll(fromUser: boolean) {\n if (!this.open) return\n if (fromUser) this._userOpenChange.mark()\n this.open = false\n }\n\n private _closeAllSubmenus() {\n this._closeSubmenuFrom(1, true)\n this._closingSubmenus.restoreAll()\n this._syncActiveAttrs()\n }\n\n private _cleanupClosedMenu() {\n this._closeAllSubmenus()\n this._returnLevel0Items()\n this._disposeAll()\n }\n\n private async _closeRootAfterPresence() {\n const overlay = this._overlays.get(0)?.overlay\n if (overlay && !(await hideOverlayPresence(overlay))) return\n if (this.open || !this.isConnected) return\n\n this._cleanupClosedMenu()\n this._restoreFocusTarget?.focus()\n this._restoreFocusTarget = undefined\n }\n\n private _hideAllSubmenuChildren() {\n hideNestedMenuChildren(this, `${SLOT_PREFIX}-hidden`)\n }\n\n private _toggleSubmenu(level: number, itemIndex: number, isInstant = false) {\n if (this._activePath[level] === itemIndex) {\n return\n }\n\n this._closeSubmenuFrom(level + 1)\n\n this._activePath = [...this._activePath.slice(0, level), itemIndex]\n this._syncActiveAttrs()\n\n const item = this._getLevelItems(level)[itemIndex]\n if (item?.hasAttribute('submenu')) {\n this._overlay.scheduleFrame(() => {\n if (!this.open || this._activePath[level] !== itemIndex) return\n const restored = this._ensureOverlay(level + 1, isInstant, item)\n if (!restored) this._populateOverlay(level + 1, item)\n })\n }\n\n this._bindHoversAfterUpdate()\n }\n\n private _closeSubmenuFrom(level: number, isInstant = false) {\n for (let lv = this._activePath.length; lv >= level; lv--) {\n const overlay = this._overlays.get(lv)\n const parentItem = this._getLevelItems(lv - 1)[this._activePath[lv - 1]]\n if (!overlay) continue\n\n if (!parentItem || isInstant) {\n this._depopulateOverlay(lv, parentItem)\n this._disposeOverlay(lv)\n } else {\n this._overlays.delete(lv)\n this._closingSubmenus.closeAsync(parentItem, overlay)\n }\n }\n const nextActivePath = this._activePath.slice(0, level - 1)\n if (nextActivePath.length !== this._activePath.length) {\n this._activePath = nextActivePath\n }\n this._syncActiveAttrs()\n }\n\n private _syncActiveAttrs() {\n this.querySelectorAll('web-ui-dropdown-item').forEach(item => {\n item.removeAttribute('active')\n })\n this._overlays.forEach((_, level) => {\n this._getLevelItems(level).forEach(item => item.removeAttribute('active'))\n })\n this._activePath.forEach((itemIndex, level) => {\n const item = this._getLevelItems(level)[itemIndex]\n if (item?.matches('web-ui-dropdown-item')) {\n item.setAttribute('active', '')\n }\n })\n }\n\n private _getLevelItems(level: number): HTMLElement[] {\n const content = this._overlays.get(level)?.content\n return content ? getMenuChildren(content) : []\n }\n\n private _populateLevel0() {\n const content = this._overlays.get(0)?.content\n if (!content) return\n // 初次打开即建立 marker 锚:宿主此后始终持有模板序骨架,打开期框架插入与\n // 关闭归还都以它为基准(机制与 context-menu 共用,见 menu-tree)。\n reconcileManagedMenuItems(this, content, this._level0ItemAnchors, MENU_ITEM_MARKER)\n orderManagedMenuItems(this, content, this._level0ItemAnchors, MENU_ITEM_MARKER)\n }\n\n private _scheduleMenuSync() {\n if (this._menuSyncScheduled) return\n this._menuSyncScheduled = true\n requestAnimationFrame(() => {\n this._menuSyncScheduled = false\n if (!this.open) return\n this._syncOpenMenuContent()\n })\n }\n\n // 打开期的统一内容同步:把打开期间框架新增的 menu 子树迁入对应层级 panel。\n // 一级项走 marker 锚 reconcile(保序 + 关闭按模板位归还);panel 尺寸变化由\n // defineOverlay 的 autoUpdate 跟进重定位。\n private _syncOpenMenuContent() {\n const level0Content = this._overlays.get(0)?.content\n // 迁移前隐藏宿主中新项的嵌套子项(hidden slot 属性随元素一起迁移)。\n this._hideAllSubmenuChildren()\n if (level0Content) {\n reconcileManagedMenuItems(this, level0Content, this._level0ItemAnchors, MENU_ITEM_MARKER)\n // 新迁入项的嵌套子项未打 hidden slot,会经 dropdown-item 默认 slot 渲染进\n // 父项 label 叠到 menu 上;panel 项在 panel 内渲染,宿主查询够不到,须对 content 补隐藏。\n hideNestedMenuChildren(level0Content, `${SLOT_PREFIX}-hidden`)\n // 框架注释锚点复位独立于元素重排:锚点漂移不收敛会破坏后续翻转的插入点(同 context-menu)。\n const frameworkAnchors = captureFrameworkAnchors(level0Content, MENU_ITEM_MARKER)\n orderManagedMenuItems(this, level0Content, this._level0ItemAnchors, MENU_ITEM_MARKER)\n restoreFrameworkAnchors(level0Content, frameworkAnchors)\n }\n for (const [level, overlay] of this._overlays) {\n if (level === 0) continue\n const parentItem = this._getLevelItems(level - 1)[this._activePath[level - 1]]\n if (parentItem) moveMenuChildren(parentItem, overlay.content)\n hideNestedMenuChildren(overlay.content, `${SLOT_PREFIX}-hidden`)\n }\n this._hoverBinder.bind()\n }\n\n private _returnLevel0Items() {\n const content = this._overlays.get(0)?.content\n if (content) returnManagedMenuItemsToSlot(this, content, this._level0ItemAnchors)\n }\n\n private _populateOverlay(level: number, submenuItem: HTMLElement) {\n const content = this._overlays.get(level)?.content\n if (content) moveMenuChildren(submenuItem, content)\n }\n\n private _depopulateOverlay(level: number, parentItem?: HTMLElement) {\n const content = this._overlays.get(level)?.content\n if (!content) return\n const targetLevel = level - 1\n const submenuItem = parentItem ?? this._getLevelItems(targetLevel)[this._activePath[targetLevel]]\n if (submenuItem) moveMenuChildren(content, submenuItem)\n }\n\n /*\n * 登记与「panel 是否本帧新建」解耦,与 context-menu 的根层修复同构。\n *\n * 退场被打断时(`_closeRootAfterPresence` 在 `hideOverlayPresence` 返回 false 后提前\n * return)panel 仍在 DOM 里,而关闭分支已经把 handle 撤了。此时重开走的是 `_ensureOverlay`\n * 的两条复用分支,它们不会重跑 `_buildOverlay`——原先只有 `_buildOverlay` 会 claim/adopt,\n * 于是出现「panel 可见 + `open === true` 却没有任何登记」:Escape 关不掉它(仲裁看不到它),\n * 守卫里 `contains` 恒 false,点 panel 内部反被当成外部点击关掉整张 menu。\n *\n * `open` 属性路径(`updated()` 里 scheduleFrame 到 `_ensureOverlay(0)`)与 `openMenu()`\n * 都落在复用分支上,因此**所有**根 claim 都必须走这里 —— 只在 `_ensureOverlay` 里补 claim\n * 是不够的:`openMenu()` 会先把 handle 建好,使那次补 claim 变成 no-op,子层照样被漏掉。\n *\n * 新 claim 即新会话,旧会话连同其全部 adopt 子树一起作废,因此**仍在场的**子层必须\n * 在这里统一重挂。来源有两个:`_overlays` 里登记的层级,以及本轮已退场、被移出\n * `_overlays` 却仍在 DOM 里的收尾栈 panel —— 只看前者会漏掉后者(见下)。\n */\n private _claimRoot(panel: HTMLElement): OpenOverlayHandle {\n this._handle?.release()\n this._handle = this._overlay.claim(panel)\n for (const [level, sub] of this._overlays) {\n if (level === 0) continue\n sub.handle = this._handle.adopt(sub.overlay)\n }\n /*\n * 收尾栈里的 submenu panel 同样「可见但已脱离快照」:`_closeSubmenuFrom` 只把它们移出\n * `_overlays`,层仍挂在旧 handle 下、panel 仍在 DOM 里退场。不重挂的话它们会被判成 panel 外,\n * 点它内部就关掉整张 menu —— base 的 `composition.contains` 走登记树、且退场期间不注销,\n * 所以这条是相对 base 的行为回归,不是 parity。\n * 新 handle 要写回容器:收尾结束时 adapter.dispose 释放的是 `container.handle`。\n */\n for (const container of this._closingSubmenus.closing()) {\n container.handle = this._handle.adopt(container.overlay)\n }\n return this._handle\n }\n\n /** handle 缺失时补登记;panel 还没建好时以宿主代填,与 `_openMenu` 的占位会话同一口径。 */\n private _ensureRootHandle(): OpenOverlayHandle {\n return this._handle ?? this._claimRoot(this._overlays.get(0)?.overlay ?? this)\n }\n\n private _ensureOverlay(level: number, isInstant = false, submenuItem?: HTMLElement): boolean {\n const closingOverlay = submenuItem ? this._closingSubmenus.take(submenuItem) : undefined\n if (closingOverlay) {\n // 从 closing 栈取回的 panel:登记已在关闭时撤销,这里必须重新挂回根 handle 子树。\n closingOverlay.handle = this._ensureRootHandle().adopt(closingOverlay.overlay)\n this._overlays.set(level, closingOverlay)\n closingOverlay.api.open()\n showOverlayPresence(closingOverlay.overlay, { isInstant })\n return true\n }\n const existing = this._overlays.get(level)\n if (existing) {\n this._ensureRootHandle()\n existing.api.open()\n showOverlayPresence(existing.overlay, { isInstant })\n return false\n }\n this._buildOverlay(level, isInstant)\n return false\n }\n\n private _buildOverlay(level: number, isInstant = false) {\n const { panel: overlay, content } = createMenuPortalOverlay('dropdown-overlay', this)\n overlay.setAttribute('role', 'menu')\n // 根层级 panel 带 id:trigger 的 aria-controls 指向它(Q9a)。\n if (level === 0) overlay.id = `wui-dropdown-menu-${++dropdownIdCounter}`\n overlay.dataset.level = String(level)\n overlay.addEventListener('click', this._onMenuClick)\n overlay.addEventListener('keydown', this._onKeydown)\n\n const anchor = level === 0 ? this._queryTriggerAnchor() : this._getSubmenuTriggerAnchor(level - 1)\n\n if (anchor) {\n const ctrl = defineOverlay().make({\n anchor,\n overlay,\n placement: level === 0 ? this.placement : 'right-start',\n offset: level === 0 ? this.offset : 0,\n // menu 至少与 trigger/父项同宽,内容可更宽(floor 来自 --wui-overlay-min-width)\n minAnchorWidth: true,\n matchWidth: level === 0 ? this.matchWidth : false,\n strategy: 'fixed'\n })\n if (level === 0) {\n // panel 就绪:释放「以宿主代填」的占位会话,换成真实 panel。\n this._claimRoot(overlay)\n this._overlays.set(level, { api: ctrl, overlay, content })\n this._populateLevel0()\n } else {\n /*\n * 子层进根 handle 子树,默认不是独立候选 —— 「在树里但不是这一层」由此表达;\n * 原先按 level 找父 panel 的判断随之消失。用 `_ensureRootHandle()` 而不是 `_handle?.`:\n * 后者在 handle 意外缺失时会静默跳过 adopt,留下一棵无人认领的子树。\n */\n const handle = this._ensureRootHandle().adopt(overlay)\n this._overlays.set(level, { api: ctrl, overlay, content, handle })\n }\n // submenu 父项在 panel content 内,其新增子项只有观察 content 子树才能看到\n this._menuContentObserver.observe(content, { childList: true, subtree: true })\n ctrl.open()\n showOverlayPresence(overlay, { isInstant })\n }\n }\n\n private _disposeOverlay(level: number) {\n const overlay = this._overlays.get(level)\n if (level === 0) {\n // 根 handle 撤销会递归撤销全部已 adopt 的子层。\n this._handle?.release()\n this._handle = null\n }\n // 子层 handle 随所属 MenuOverlay 释放;已被根层递归撤销时幂等无操作。\n overlay?.handle?.release()\n overlay?.overlay.removeEventListener('click', this._onMenuClick)\n overlay?.overlay.removeEventListener('keydown', this._onKeydown)\n overlay?.overlay.remove()\n overlay?.api.dispose()\n this._overlays.delete(level)\n this._rebindMenuContentObservers()\n }\n\n // jsdom 的 MutationObserver 不实现 unobserve;统一 disconnect 后重绑剩余目标。\n private _rebindMenuContentObservers() {\n this._menuContentObserver.disconnect()\n this._menuContentObserver.observe(this, { childList: true, subtree: true })\n for (const overlay of this._overlays.values()) {\n this._menuContentObserver.observe(overlay.content, { childList: true, subtree: true })\n }\n }\n\n private _disposeAll() {\n /*\n * 先无条件撤销根 handle。`_openMenu` 会先用宿主当 panel claim 一次占位会话(真实 panel 要等\n * 一帧才建好),若这段时间内宿主被卸载、`_buildOverlay` 没机会跑,`_overlays` 仍是空的\n * —— 只遍历 `_overlays` 就会漏掉它:该层永久留在模块注册表里强引用整个组件,且宿主\n * 重挂载后 `panel.isConnected` 又为真,占位层重新成为候选、吞掉 Escape。\n */\n this._handle?.release()\n this._handle = null\n for (const level of this._overlays.keys()) {\n this._disposeOverlay(level)\n }\n }\n\n private _syncScrollLock(isOpen = this.open) {\n this._scrollLock.sync(isOpen && !this.noScrollLock)\n }\n\n private _queryTriggerAnchor(): HTMLElement | null {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]')\n const el = slot?.assignedElements()[0]\n return el instanceof HTMLElement ? el : null\n }\n\n /*\n * trigger 语义回写(Q9a):slot 进来的元素是真正的可聚焦交互元素,\n * aria-haspopup / aria-expanded / aria-controls 必须设在它身上;\n * 组件没有 trigger 包装 div,此前完全没有 ARIA 接线。\n */\n private _syncTriggerAria() {\n const trigger = this._queryTriggerAnchor()\n if (!trigger) return\n trigger.setAttribute('aria-haspopup', 'menu')\n trigger.setAttribute('aria-expanded', String(this.open))\n const rootOverlay = this._overlays.get(0)?.overlay\n if (rootOverlay?.id) trigger.setAttribute('aria-controls', rootOverlay.id)\n else trigger.removeAttribute('aria-controls')\n }\n\n private _getSubmenuTriggerAnchor(level: number): HTMLElement | null {\n const idx = this._activePath[level]\n if (idx === undefined) return null\n const items = this._getLevelItems(level)\n const item = items[idx]\n if (!item) return null\n return item.shadowRoot?.querySelector('.item-inner') ?? item\n }\n\n private _onTriggerClick = (event: MouseEvent) => {\n if (this.disabled) return\n if (this.open) {\n this._closeAll(true)\n } else {\n /*\n * `detail === 0` ⇔ 键盘激活(Enter/Space 触发的 click),`detail > 0` ⇔ 指针点击。\n * 同一个信号既决定是否免入场过渡,也决定首项要不要留 `:focus-visible`:\n * 键盘打开首项即应有 accent 焦点视觉,指针打开则抑制(见 `_suppressInitialFocusVisible`)。\n */\n const fromKeyboard = event.detail === 0\n this._openMenu(fromKeyboard, true, !fromKeyboard)\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._closeAll(true)\n }\n\n private _onMenuClick = (e: MouseEvent) => {\n const item = getMenuItemFromEvent(e)\n if (!item || item.hasAttribute('disabled') || !item.hasAttribute('submenu')) return\n\n const level = this._getFocusedLevel(item)\n if (level === undefined) return\n const itemIndex = this._getLevelItems(level).indexOf(item)\n if (itemIndex >= 0) this._toggleSubmenu(level, itemIndex, e.detail === 0)\n }\n\n private _onKeydown = (e: KeyboardEvent) => {\n if (this.disabled || !this.open) return\n\n // overlay 上键盘事件 target 是 menu item 而非组件自身,不能限定 e.target === this,\n // 否则鼠标打开、焦点在 menu item 时 Escape 无法关闭\n handleMenuKeyboard(this._keyboardDelegate, e)\n }\n\n private _getFocusedLevel(item?: HTMLElement): number | undefined {\n if (!item) return undefined\n const overlay = [...this._overlays.entries()].find(([, value]) => value.overlay.contains(item))\n return overlay?.[0]\n }\n\n private _bindHoversAfterUpdate() {\n requestAnimationFrame(() => this._hoverBinder.bind())\n }\n\n override render() {\n return html`\n <div class=\"dropdown-trigger\" @click=${this._onTriggerClick}>\n <slot name=\"trigger\"></slot>\n </div>\n `\n }\n\n declare readonly $events: {\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-dropdown': WebUiDropdown\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/dropdown/index.ts"],"sourcesContent":["import type { Placement } from '@floating-ui/dom'\nimport { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\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 } 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 type MenuItemAnchors\n} from '@/shared/menu-portal/menu-tree'\nimport { normalizeLiteral, normalizeNumber } from '@/shared/normalize'\nimport { dispatchOpenChangeEvent } from '@/shared/open-state'\nimport { defineOpenOverlay, type OpenOverlayHandle } from '@/shared/overlay/open-overlay'\nimport { defineOverlay, type OverlayApi } from '@/shared/overlay/overlay'\nimport { FLOATING_PLACEMENTS } from '@/shared/overlay/placement-props'\nimport { hideOverlayPresence, showOverlayPresence } from '@/shared/overlay/presence'\nimport { defineScrollLockLease } from '@/shared/scroll-lock/scroll-lock'\n\nimport style from './style.css?inline'\n\nexport type { Placement }\n\nconst SLOT_PREFIX = 'web-ui-menu-level-'\n// 一级 menu item 的模板位 marker(机制与 context-menu 共用,见 menu-tree 的托管项锚说明)。\nconst MENU_ITEM_MARKER = 'wui-dropdown-menu-item'\n\nfunction getComposedParent(node: Node): Node | null {\n if (node instanceof Element && node.assignedSlot) return node.assignedSlot\n return node.parentNode instanceof ShadowRoot ? node.parentNode.host : node.parentNode\n}\n\nfunction isComposedDescendant(node: Node, ancestor: Node): boolean {\n let current: Node | null = node\n while (current) {\n if (current === ancestor) return true\n current = getComposedParent(current)\n }\n return false\n}\n\nfunction hasNativeModalAncestor(node: Node): boolean {\n let current: Node | null = node\n while (current) {\n if (current instanceof HTMLDialogElement && current.open && current.matches(':modal')) return true\n current = getComposedParent(current)\n }\n return false\n}\n\nlet dropdownIdCounter = 0\n\ninterface MenuOverlay {\n api: OverlayApi\n overlay: HTMLElement\n content: HTMLElement\n /** 该层为 submenu 时的会话 handle;根层 handle 由组件单独持有(见 `_handle`)。 */\n handle?: OpenOverlayHandle\n}\n\ntype PointerInteraction = {\n startedInsideMenu: boolean\n startedWithinDropdown: boolean\n completed: boolean\n clickInsideMenu?: boolean\n}\n\n@customElement('web-ui-dropdown')\nexport class WebUiDropdown extends LitElement {\n static override styles = unsafeCSS(style)\n\n @property({ type: Boolean, reflect: true }) open = false\n @property({ type: Boolean, reflect: true }) disabled = false\n @property({ type: Boolean, reflect: true, attribute: 'match-width' }) matchWidth = false\n @property({ type: Boolean, reflect: true, attribute: 'no-scroll-lock' }) noScrollLock = false\n\n private _placement: Placement = 'bottom-start'\n\n @property({ type: String, reflect: true })\n get placement(): Placement {\n return this._placement\n }\n set placement(v: string) {\n this._placement = normalizeLiteral(v, FLOATING_PLACEMENTS, 'bottom-start')\n }\n\n private _offset = 4\n\n @property({ type: Number })\n get offset(): number {\n return this._offset\n }\n set offset(v: number) {\n this._offset = normalizeNumber(v, 0, 100, 4)\n }\n\n @state() private _activePath: number[] = []\n\n private readonly _overlays = new Map<number, MenuOverlay>()\n /** 实例作用域的帧事务入口(合并了原 lifecycle)。 */\n private readonly _overlay = defineOpenOverlay().make({\n requestClose: () => this._keyboardDelegate.closeDeepestOrAll(),\n isConnected: () => this.isConnected\n })\n private readonly _scrollLock = defineScrollLockLease().make()\n /**\n * 当前 Escape 候选的会话 handle(level 0)。panel 要等一帧才建好,而 Escape 可能在这之前\n * 到达:先以宿主为 panel claim 一次,panel 就绪后 release 旧会话、再以真实 panel 重新 claim。\n * submenu 的 handle 存在各自 `MenuOverlay.handle` 上(经 adopt 进本 handle 子树)。\n */\n private _handle: OpenOverlayHandle | null = null\n // 行为层(hover / outside-click / 键盘 / submenu 收尾)由 shared/menu-behavior 驱动\n private readonly _outsideClickGuard = createMenuOutsideClickGuard(\n this,\n // 根 handle 的 contains 递归覆盖全部已 adopt 的子层,一次查询替代逐层判定。\n node => this._handle?.contains(node) ?? false\n )\n private readonly _closingSubmenus = createClosingSubmenuStack<MenuOverlay>({\n getPanel: container => container.overlay,\n restoreItems: (container, parentItem) => moveMenuChildren(container.content, parentItem),\n dispose: container => {\n container.handle?.release()\n container.overlay.remove()\n container.api.dispose()\n }\n })\n private readonly _hoverDelegate: MenuHoverDelegate = {\n getOpenDepth: () => this._activePath.length,\n getLevelItems: level => this._getLevelItems(level),\n getActiveItem: level => this._getLevelItems(level)[this._activePath[level]],\n isSubmenuItem: item => item.hasAttribute('submenu'),\n openSubmenu: item => {\n const level = this._getFocusedLevel(item)\n if (level === undefined) return\n const itemIndex = this._getLevelItems(level).indexOf(item)\n if (itemIndex >= 0) this._toggleSubmenu(level, itemIndex)\n },\n closeFrom: level => this._closeSubmenuFrom(level + 1)\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._overlays.values()].map(({ overlay }) => overlay),\n 'web-ui-dropdown-item'\n ),\n getLevelOf: item => this._getFocusedLevel(item),\n getEnabledItems: level => getEnabledMenuLevelItems(this._overlays.get(level)?.content),\n isSubmenuItem: item => item.hasAttribute('submenu'),\n openSubmenuInstant: item => {\n const level = this._getFocusedLevel(item)\n if (level === undefined) return\n const itemIndex = this._getLevelItems(level).indexOf(item)\n if (itemIndex >= 0) this._toggleSubmenu(level, itemIndex, true)\n },\n closeToParent: level => {\n const parentItem = this._getLevelItems(level - 1)[this._activePath[level - 1]]\n this._closeSubmenuFrom(level)\n return parentItem\n },\n closeDeepestOrAll: () => {\n if (this._activePath.length > 0) this._closeSubmenuFrom(this._activePath.length)\n else this._closeAll(true)\n }\n }\n private readonly _userOpenChange = new UserChangeController()\n private _restoreFocusTarget?: HTMLElement\n private _skipFocusRestoreOnClose = false\n private _pointerInteraction?: PointerInteraction\n private _pendingFocusOutCheck?: () => void\n private _pendingTabNavigation?: {\n event: KeyboardEvent\n focusedItem: HTMLElement\n previousFocus?: HTMLElement\n focusTrigger: boolean\n }\n private _shouldOpenInstantly = true\n /**\n * 本次打开是否抑制首项的 `:focus-visible` accent 视觉(口径与 context-menu 一致)。\n *\n * 默认 `true`(抑制),只有键盘激活触发的打开才置 `false`:首项的焦点是组件程序化\n * 落的,而各引擎对「程序化 focus 是否算 focus-visible」判定不同 —— Chromium 走启发式\n * 通常不匹配,WKWebView 则会匹配(用户在 Interweave 桌面 app 实测到蓝底白字),\n * 于是同一段代码只在 WebKit 侧暴露出缺陷。取默认抑制而非默认保留,是因为冷启动的\n * `open` 属性路径拿不到任何手势模态信息,抑制是唯一确定安全的一侧;误伤键盘用户的\n * 代价有界:`handleMenuKeyboard` 首次方向键即以无参 `focusMenuItem` 重新落焦,\n * `menu-tree` 的 `toggleAttribute` 无条件清掉本属性,accent 当场回来。\n */\n private _suppressInitialFocusVisible = true\n private _menuSyncScheduled = false\n private readonly _level0ItemAnchors: MenuItemAnchors = new Map()\n // 打开期实时渲染:框架(Vue/React 条件渲染)可能在 menu 打开期间持续插入 menu item。\n // 观察宿主子树(新增项可能被框架 wrapper 包裹)与各层级 panel content 的子树\n // (打开中的 submenu 父项已被迁入 content,其新增子项只在这里可见),下一帧统一\n // 把新子树迁入对应层级 panel;panel 尺寸变化由 defineOverlay 的 autoUpdate 跟进重定位。\n private readonly _menuContentObserver = new MutationObserver(() => {\n if (this.open) this._scheduleMenuSync()\n })\n\n get isOpen(): boolean {\n return this.open || this._activePath.length > 0\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._overlay.resume()\n this.addEventListener('keydown', this._onKeydown)\n window.addEventListener('keydown', this._onTabKeydown)\n document.addEventListener('pointerdown', this._onPointerDown, true)\n document.addEventListener('pointerup', this._onPointerUp, true)\n document.addEventListener('pointercancel', this._onPointerCancel, true)\n document.addEventListener('click', this._onClickOutside)\n document.addEventListener('focusin', this._onFocusIn, true)\n document.addEventListener('focusout', this._onFocusOut, true)\n this._menuContentObserver.observe(this, { childList: true, subtree: true })\n /*\n * 重挂载对账:`disconnectedCallback` 会拆掉 panel、把 menu item 迁回宿主,但 `open` 是公开\n * prop,不因卸载而改写。Lit 在 detach 期间不记 `changedProperties`,重连后 `updated()`\n * 不再命中 `changed.has('open')`,panel 于是永久缺席:宿主仍反射 `open` 与\n * `aria-expanded`,Escape 和 outside click 却无层可关。首连时 `open` 在\n * `changedProperties` 里、由 `updated()` 负责,`hasUpdated` 就是用来只认重连的。\n */\n if (this.open && this.hasUpdated) this._syncOpenOverlay(this._isFocusOrphaned())\n }\n\n override firstUpdated() {\n // trigger slot 内容增删不触发宿主响应式更新:显式请求一轮渲染,\n // 由 updated() 的 ARIA 回写覆盖晚到的 trigger 元素。\n this.shadowRoot\n ?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]')\n ?.addEventListener('slotchange', () => this.requestUpdate())\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._menuContentObserver.disconnect()\n this._pointerInteraction = undefined\n this._pendingFocusOutCheck = undefined\n this._pendingTabNavigation = undefined\n this.removeEventListener('keydown', this._onKeydown)\n window.removeEventListener('keydown', this._onTabKeydown)\n document.removeEventListener('pointerdown', this._onPointerDown, true)\n document.removeEventListener('pointerup', this._onPointerUp, true)\n document.removeEventListener('pointercancel', this._onPointerCancel, true)\n document.removeEventListener('click', this._onClickOutside)\n document.removeEventListener('focusin', this._onFocusIn, true)\n document.removeEventListener('focusout', this._onFocusOut, true)\n this._outsideClickGuard.dispose()\n this._hoverBinder.dispose()\n // 停止帧调度;登记由 _cleanupClosedMenu → _disposeAll 撤销。\n this._overlay.suspend()\n this._scrollLock.release()\n this._cleanupClosedMenu()\n }\n\n protected override updated(changed: Map<string, unknown>) {\n // ARIA 回写不依赖 open 分支,任何渲染后都保持与宿主状态同步。\n this._syncTriggerAria()\n\n if (changed.has('open')) {\n if (this.open) {\n this._skipFocusRestoreOnClose = false\n this._syncOpenOverlay(true)\n } else {\n this._overlay.invalidate()\n this._syncScrollLock()\n /*\n * 复位打开模态:`open` 真正翻回 false 才是「上一次打开会话结束」的唯一信号,\n * 下一会话若不经 `_openMenu()`(宿主直接翻 `open` 属性)就从默认口径重新起算,\n * 不会把上一次键盘打开留下的 `false` 带进这次鼠标驱动的声明式打开。\n * 刻意不复位在 `disconnectedCallback`/`_cleanupClosedMenu`:重挂载对账(:188)\n * 期间 `open` 始终为 true,那次重取焦点属于同一会话,应保留原模态。\n */\n this._suppressInitialFocusVisible = true\n /*\n * release ⟺ 关闭:新模块里「已登记」就等于「参与仲裁」,不再由 host.isOpen()\n * 兜底过滤,所以必须在这里撤销,不能等到退场动画结束。\n */\n this._handle?.release()\n this._handle = null\n void this._closeRootAfterPresence()\n }\n if (this._userOpenChange.consume()) {\n dispatchOpenChangeEvent(this, this.open)\n }\n }\n if (changed.has('noScrollLock')) this._syncScrollLock()\n if (changed.has('placement') || changed.has('offset') || changed.has('matchWidth')) {\n this._overlays.get(0)?.api.update({\n placement: this.placement,\n offset: this.offset,\n matchWidth: this.matchWidth\n })\n }\n this._hoverBinder.bind()\n }\n\n /**\n * 焦点是否已无归属:被 detach 打掉的焦点会落回 `body`,用户主动点到别处时不会。\n * 重挂载对账只在前者才把焦点夺回 menu,否则等于从消费者手里抢焦点。\n */\n private _isFocusOrphaned(): boolean {\n const active = document.activeElement\n return active === null || active === document.body || active === document.documentElement\n }\n\n /** Resolve the actual focus node through open shadow roots. */\n private _getDeepActiveElement(): HTMLElement | undefined {\n let active: Element | null = document.activeElement\n while (active instanceof HTMLElement) {\n const nested = active.shadowRoot?.activeElement\n if (!(nested instanceof HTMLElement)) return active\n active = nested\n }\n return undefined\n }\n\n /**\n * 打开态的唯一对账入口:panel、滚动锁、outside click、hover 与 menu 焦点都从这里收敛,\n * `updated()` 的打开分支与重连对账共用它,两条路径必须落到同一个状态。\n */\n private _syncOpenOverlay(takeFocus: boolean) {\n this._restoreFocusTarget ??= this._getDeepActiveElement()\n this._outsideClickGuard.arm()\n this._syncScrollLock()\n this._hideAllSubmenuChildren()\n this._overlay.invalidate()\n this._overlay.scheduleFrame(() => {\n this._ensureOverlay(0, this._shouldOpenInstantly)\n this._shouldOpenInstantly = true\n if (takeFocus) {\n focusMenuItem(getEnabledMenuLevelItems(this._overlays.get(0)?.content)[0], {\n suppressFocusVisible: this._suppressInitialFocusVisible\n })\n }\n // panel id 在 overlay 构建后才有:回写 aria-controls 指向。\n this._syncTriggerAria()\n })\n this._bindHoversAfterUpdate()\n }\n\n /*\n * 命令式打开,不派发 open-change。命令式入口没有手势模态信息,按与 context-menu 的\n * `openAt()` 同一口径抑制首项 accent。\n */\n openMenu() {\n this._openMenu(true, false, true)\n }\n\n private _openMenu(isInstant: boolean, fromUser: boolean, suppressFocusVisible: boolean) {\n if (this.disabled || this.open) return\n this._outsideClickGuard.arm()\n this._shouldOpenInstantly = isInstant\n this._suppressInitialFocusVisible = suppressFocusVisible\n if (fromUser) this._userOpenChange.mark()\n // panel 要等一帧才建好,而 Escape 可能在这之前到达:先用宿主当 panel claim 一次;\n // panel 就绪后 _buildOverlay 会 release 这个占位会话,再以真实 panel 重新 claim。\n this._claimRoot(this._overlays.get(0)?.overlay ?? this)\n this.open = true\n }\n\n // 命令式关闭全部层级,不派发 open-change。\n closeAll() {\n this._closeAll(false)\n }\n\n private _closeAll(fromUser: boolean) {\n if (!this.open) return\n if (fromUser) this._userOpenChange.mark()\n this.open = false\n }\n\n private _closeAllSubmenus() {\n this._closeSubmenuFrom(1, true)\n this._closingSubmenus.restoreAll()\n this._syncActiveAttrs()\n }\n\n private _cleanupClosedMenu() {\n this._closeAllSubmenus()\n this._returnLevel0Items()\n this._resetMenuTabStops()\n this._disposeAll()\n this._syncTriggerAria()\n }\n\n private _resetMenuTabStops() {\n this.querySelectorAll<HTMLElement>('web-ui-dropdown-item').forEach(item => {\n const control = item.shadowRoot?.querySelector<HTMLElement>('[role=\"menuitem\"]')\n if (control) control.tabIndex = item.hasAttribute('disabled') ? -1 : 0\n })\n }\n\n private async _closeRootAfterPresence() {\n const overlay = this._overlays.get(0)?.overlay\n if (overlay && !(await hideOverlayPresence(overlay))) return\n if (this.open || !this.isConnected) return\n\n // submenu panels 与 root panel 是兄弟节点;整张 menu 收尾会移除所有仍持有焦点的层级。\n const shouldRestoreFocus = [...this._overlays.values(), ...this._closingSubmenus.closing()].some(menuOverlay =>\n menuOverlay.overlay.matches(':focus-within')\n )\n this._cleanupClosedMenu()\n if (shouldRestoreFocus && !this._skipFocusRestoreOnClose) this._restoreFocusTarget?.focus()\n this._skipFocusRestoreOnClose = false\n this._restoreFocusTarget = undefined\n }\n\n private _hideAllSubmenuChildren() {\n hideNestedMenuChildren(this, `${SLOT_PREFIX}-hidden`)\n }\n\n private _toggleSubmenu(level: number, itemIndex: number, isInstant = false) {\n if (this._activePath[level] === itemIndex) {\n return\n }\n\n this._closeSubmenuFrom(level + 1)\n\n this._activePath = [...this._activePath.slice(0, level), itemIndex]\n this._syncActiveAttrs()\n\n const item = this._getLevelItems(level)[itemIndex]\n if (item?.hasAttribute('submenu')) {\n this._overlay.scheduleFrame(() => {\n if (!this.open || this._activePath[level] !== itemIndex) return\n const restored = this._ensureOverlay(level + 1, isInstant, item)\n if (!restored) this._populateOverlay(level + 1, item)\n })\n }\n\n this._bindHoversAfterUpdate()\n }\n\n private _closeSubmenuFrom(level: number, isInstant = false) {\n for (let lv = this._activePath.length; lv >= level; lv--) {\n const overlay = this._overlays.get(lv)\n const parentItem = this._getLevelItems(lv - 1)[this._activePath[lv - 1]]\n if (!overlay) continue\n\n if (!parentItem || isInstant) {\n this._depopulateOverlay(lv, parentItem)\n this._disposeOverlay(lv)\n } else {\n this._overlays.delete(lv)\n this._closingSubmenus.closeAsync(parentItem, overlay)\n }\n }\n const nextActivePath = this._activePath.slice(0, level - 1)\n if (nextActivePath.length !== this._activePath.length) {\n this._activePath = nextActivePath\n }\n this._syncActiveAttrs()\n }\n\n private _syncActiveAttrs() {\n this.querySelectorAll('web-ui-dropdown-item').forEach(item => {\n item.removeAttribute('active')\n })\n this._overlays.forEach((_, level) => {\n this._getLevelItems(level).forEach(item => item.removeAttribute('active'))\n })\n this._activePath.forEach((itemIndex, level) => {\n const item = this._getLevelItems(level)[itemIndex]\n if (item?.matches('web-ui-dropdown-item')) {\n item.setAttribute('active', '')\n }\n })\n }\n\n private _getLevelItems(level: number): HTMLElement[] {\n const content = this._overlays.get(level)?.content\n return content ? getMenuChildren(content) : []\n }\n\n private _populateLevel0() {\n const content = this._overlays.get(0)?.content\n if (!content) return\n // 初次打开即建立 marker 锚:宿主此后始终持有模板序骨架,打开期框架插入与\n // 关闭归还都以它为基准(机制与 context-menu 共用,见 menu-tree)。\n reconcileManagedMenuItems(this, content, this._level0ItemAnchors, MENU_ITEM_MARKER)\n orderManagedMenuItems(this, content, this._level0ItemAnchors, MENU_ITEM_MARKER)\n }\n\n private _scheduleMenuSync() {\n if (this._menuSyncScheduled) return\n this._menuSyncScheduled = true\n requestAnimationFrame(() => {\n this._menuSyncScheduled = false\n if (!this.open) return\n this._syncOpenMenuContent()\n })\n }\n\n // 打开期的统一内容同步:把打开期间框架新增的 menu 子树迁入对应层级 panel。\n // 一级项走 marker 锚 reconcile(保序 + 关闭按模板位归还);panel 尺寸变化由\n // defineOverlay 的 autoUpdate 跟进重定位。\n private _syncOpenMenuContent() {\n const level0Content = this._overlays.get(0)?.content\n // 迁移前隐藏宿主中新项的嵌套子项(hidden slot 属性随元素一起迁移)。\n this._hideAllSubmenuChildren()\n if (level0Content) {\n reconcileManagedMenuItems(this, level0Content, this._level0ItemAnchors, MENU_ITEM_MARKER)\n // 新迁入项的嵌套子项未打 hidden slot,会经 dropdown-item 默认 slot 渲染进\n // 父项 label 叠到 menu 上;panel 项在 panel 内渲染,宿主查询够不到,须对 content 补隐藏。\n hideNestedMenuChildren(level0Content, `${SLOT_PREFIX}-hidden`)\n // 框架注释锚点复位独立于元素重排:锚点漂移不收敛会破坏后续翻转的插入点(同 context-menu)。\n const frameworkAnchors = captureFrameworkAnchors(level0Content, MENU_ITEM_MARKER)\n orderManagedMenuItems(this, level0Content, this._level0ItemAnchors, MENU_ITEM_MARKER)\n restoreFrameworkAnchors(level0Content, frameworkAnchors)\n }\n for (const [level, overlay] of this._overlays) {\n if (level === 0) continue\n const parentItem = this._getLevelItems(level - 1)[this._activePath[level - 1]]\n if (parentItem) moveMenuChildren(parentItem, overlay.content)\n hideNestedMenuChildren(overlay.content, `${SLOT_PREFIX}-hidden`)\n }\n this._hoverBinder.bind()\n }\n\n private _returnLevel0Items() {\n const content = this._overlays.get(0)?.content\n if (content) returnManagedMenuItemsToSlot(this, content, this._level0ItemAnchors)\n }\n\n private _populateOverlay(level: number, submenuItem: HTMLElement) {\n const content = this._overlays.get(level)?.content\n if (content) moveMenuChildren(submenuItem, content)\n }\n\n private _depopulateOverlay(level: number, parentItem?: HTMLElement) {\n const content = this._overlays.get(level)?.content\n if (!content) return\n const targetLevel = level - 1\n const submenuItem = parentItem ?? this._getLevelItems(targetLevel)[this._activePath[targetLevel]]\n if (submenuItem) moveMenuChildren(content, submenuItem)\n }\n\n /*\n * 登记与「panel 是否本帧新建」解耦,与 context-menu 的根层修复同构。\n *\n * 退场被打断时(`_closeRootAfterPresence` 在 `hideOverlayPresence` 返回 false 后提前\n * return)panel 仍在 DOM 里,而关闭分支已经把 handle 撤了。此时重开走的是 `_ensureOverlay`\n * 的两条复用分支,它们不会重跑 `_buildOverlay`——原先只有 `_buildOverlay` 会 claim/adopt,\n * 于是出现「panel 可见 + `open === true` 却没有任何登记」:Escape 关不掉它(仲裁看不到它),\n * 守卫里 `contains` 恒 false,点 panel 内部反被当成外部点击关掉整张 menu。\n *\n * `open` 属性路径(`updated()` 里 scheduleFrame 到 `_ensureOverlay(0)`)与 `openMenu()`\n * 都落在复用分支上,因此**所有**根 claim 都必须走这里 —— 只在 `_ensureOverlay` 里补 claim\n * 是不够的:`openMenu()` 会先把 handle 建好,使那次补 claim 变成 no-op,子层照样被漏掉。\n *\n * 新 claim 即新会话,旧会话连同其全部 adopt 子树一起作废,因此**仍在场的**子层必须\n * 在这里统一重挂。来源有两个:`_overlays` 里登记的层级,以及本轮已退场、被移出\n * `_overlays` 却仍在 DOM 里的收尾栈 panel —— 只看前者会漏掉后者(见下)。\n */\n private _claimRoot(panel: HTMLElement): OpenOverlayHandle {\n this._handle?.release()\n this._handle = this._overlay.claim(panel)\n for (const [level, sub] of this._overlays) {\n if (level === 0) continue\n sub.handle = this._handle.adopt(sub.overlay)\n }\n /*\n * 收尾栈里的 submenu panel 同样「可见但已脱离快照」:`_closeSubmenuFrom` 只把它们移出\n * `_overlays`,层仍挂在旧 handle 下、panel 仍在 DOM 里退场。不重挂的话它们会被判成 panel 外,\n * 点它内部就关掉整张 menu —— base 的 `composition.contains` 走登记树、且退场期间不注销,\n * 所以这条是相对 base 的行为回归,不是 parity。\n * 新 handle 要写回容器:收尾结束时 adapter.dispose 释放的是 `container.handle`。\n */\n for (const container of this._closingSubmenus.closing()) {\n container.handle = this._handle.adopt(container.overlay)\n }\n return this._handle\n }\n\n /** handle 缺失时补登记;panel 还没建好时以宿主代填,与 `_openMenu` 的占位会话同一口径。 */\n private _ensureRootHandle(): OpenOverlayHandle {\n return this._handle ?? this._claimRoot(this._overlays.get(0)?.overlay ?? this)\n }\n\n private _ensureOverlay(level: number, isInstant = false, submenuItem?: HTMLElement): boolean {\n const closingOverlay = submenuItem ? this._closingSubmenus.take(submenuItem) : undefined\n if (closingOverlay) {\n // 从 closing 栈取回的 panel:登记已在关闭时撤销,这里必须重新挂回根 handle 子树。\n closingOverlay.handle = this._ensureRootHandle().adopt(closingOverlay.overlay)\n this._overlays.set(level, closingOverlay)\n closingOverlay.api.open()\n showOverlayPresence(closingOverlay.overlay, { isInstant })\n return true\n }\n const existing = this._overlays.get(level)\n if (existing) {\n this._ensureRootHandle()\n existing.api.open()\n showOverlayPresence(existing.overlay, { isInstant })\n return false\n }\n this._buildOverlay(level, isInstant)\n return false\n }\n\n private _buildOverlay(level: number, isInstant = false) {\n const { panel: overlay, content } = createMenuPortalOverlay('dropdown-overlay', this)\n overlay.setAttribute('role', 'menu')\n // 根层级 panel 带 id:trigger 的 aria-controls 指向它(Q9a)。\n if (level === 0) overlay.id = `wui-dropdown-menu-${++dropdownIdCounter}`\n overlay.dataset.level = String(level)\n overlay.addEventListener('click', this._onMenuClick)\n overlay.addEventListener('keydown', this._onKeydown)\n\n const anchor = level === 0 ? this._queryTriggerAnchor() : this._getSubmenuTriggerAnchor(level - 1)\n\n if (anchor) {\n const ctrl = defineOverlay().make({\n anchor,\n overlay,\n placement: level === 0 ? this.placement : 'right-start',\n offset: level === 0 ? this.offset : 0,\n // menu 至少与 trigger/父项同宽,内容可更宽(floor 来自 --wui-overlay-min-width)\n minAnchorWidth: true,\n matchWidth: level === 0 ? this.matchWidth : false,\n strategy: 'fixed'\n })\n if (level === 0) {\n // panel 就绪:释放「以宿主代填」的占位会话,换成真实 panel。\n this._claimRoot(overlay)\n this._overlays.set(level, { api: ctrl, overlay, content })\n this._populateLevel0()\n } else {\n /*\n * 子层进根 handle 子树,默认不是独立候选 —— 「在树里但不是这一层」由此表达;\n * 原先按 level 找父 panel 的判断随之消失。用 `_ensureRootHandle()` 而不是 `_handle?.`:\n * 后者在 handle 意外缺失时会静默跳过 adopt,留下一棵无人认领的子树。\n */\n const handle = this._ensureRootHandle().adopt(overlay)\n this._overlays.set(level, { api: ctrl, overlay, content, handle })\n }\n // submenu 父项在 panel content 内,其新增子项只有观察 content 子树才能看到\n this._menuContentObserver.observe(content, { childList: true, subtree: true })\n ctrl.open()\n showOverlayPresence(overlay, { isInstant })\n }\n }\n\n private _disposeOverlay(level: number) {\n const overlay = this._overlays.get(level)\n if (level === 0) {\n // 根 handle 撤销会递归撤销全部已 adopt 的子层。\n this._handle?.release()\n this._handle = null\n }\n // 子层 handle 随所属 MenuOverlay 释放;已被根层递归撤销时幂等无操作。\n overlay?.handle?.release()\n overlay?.overlay.removeEventListener('click', this._onMenuClick)\n overlay?.overlay.removeEventListener('keydown', this._onKeydown)\n overlay?.overlay.remove()\n overlay?.api.dispose()\n this._overlays.delete(level)\n this._rebindMenuContentObservers()\n }\n\n // jsdom 的 MutationObserver 不实现 unobserve;统一 disconnect 后重绑剩余目标。\n private _rebindMenuContentObservers() {\n this._menuContentObserver.disconnect()\n this._menuContentObserver.observe(this, { childList: true, subtree: true })\n for (const overlay of this._overlays.values()) {\n this._menuContentObserver.observe(overlay.content, { childList: true, subtree: true })\n }\n }\n\n private _disposeAll() {\n /*\n * 先无条件撤销根 handle。`_openMenu` 会先用宿主当 panel claim 一次占位会话(真实 panel 要等\n * 一帧才建好),若这段时间内宿主被卸载、`_buildOverlay` 没机会跑,`_overlays` 仍是空的\n * —— 只遍历 `_overlays` 就会漏掉它:该层永久留在模块注册表里强引用整个组件,且宿主\n * 重挂载后 `panel.isConnected` 又为真,占位层重新成为候选、吞掉 Escape。\n */\n this._handle?.release()\n this._handle = null\n for (const level of this._overlays.keys()) {\n this._disposeOverlay(level)\n }\n }\n\n private _syncScrollLock(isOpen = this.open) {\n this._scrollLock.sync(isOpen && !this.noScrollLock)\n }\n\n private _queryTriggerAnchor(): HTMLElement | null {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]')\n const el = slot?.assignedElements()[0]\n return el instanceof HTMLElement ? el : null\n }\n\n private _focusTriggerForTab() {\n const trigger = this._queryTriggerAnchor()\n if (!trigger) return\n trigger.focus()\n const active = this._getDeepActiveElement()\n if (active && isComposedDescendant(active, trigger)) return\n\n const control = trigger.shadowRoot?.querySelector<HTMLElement>(\n 'button:not(:disabled), input:not(:disabled), select:not(:disabled), textarea:not(:disabled), a[href], [tabindex]:not([tabindex=\"-1\"])'\n )\n control?.focus()\n }\n\n /*\n * trigger 语义回写(Q9a):slot 进来的元素是真正的可聚焦交互元素,\n * aria-haspopup / aria-expanded / aria-controls 必须设在它身上;\n * 组件没有 trigger 包装 div,此前完全没有 ARIA 接线。\n */\n private _syncTriggerAria() {\n const trigger = this._queryTriggerAnchor()\n if (!trigger) return\n trigger.setAttribute('aria-haspopup', 'menu')\n trigger.setAttribute('aria-expanded', String(this.open))\n const rootOverlay = this._overlays.get(0)?.overlay\n if (rootOverlay?.id) trigger.setAttribute('aria-controls', rootOverlay.id)\n else trigger.removeAttribute('aria-controls')\n }\n\n private _getSubmenuTriggerAnchor(level: number): HTMLElement | null {\n const idx = this._activePath[level]\n if (idx === undefined) return null\n const items = this._getLevelItems(level)\n const item = items[idx]\n if (!item) return null\n return item.shadowRoot?.querySelector('.item-inner') ?? item\n }\n\n private _onTriggerClick = (event: MouseEvent) => {\n if (this.disabled) return\n if (this.open) {\n this._closeAll(true)\n } else {\n /*\n * `detail === 0` ⇔ 键盘激活(Enter/Space 触发的 click),`detail > 0` ⇔ 指针点击。\n * 同一个信号既决定是否免入场过渡,也决定首项要不要留 `:focus-visible`:\n * 键盘打开首项即应有 accent 焦点视觉,指针打开则抑制(见 `_suppressInitialFocusVisible`)。\n */\n const fromKeyboard = event.detail === 0\n this._openMenu(fromKeyboard, true, !fromKeyboard)\n }\n }\n\n private _onClickOutside = (e: MouseEvent) => {\n if (this._pointerInteraction) {\n this._pointerInteraction.completed = true\n this._pointerInteraction.clickInsideMenu = this._outsideClickGuard.isInside(e)\n this._pointerInteraction = undefined\n this._resumePendingFocusOutCheck()\n }\n if (!this.isOpen || this._outsideClickGuard.isArmed()) return\n if (this._outsideClickGuard.isInside(e)) return\n this._closeAll(true)\n }\n\n private _onPointerDown = (event: PointerEvent) => {\n const startedInsideMenu = Boolean(this.open && this._handle?.containsEvent(event))\n this._pointerInteraction = {\n startedInsideMenu,\n // Trigger 的默认焦点动作也可能先于 click 让菜单项失焦;等 pointerup 后再检查,\n // 让同一次 trigger click 先执行开合切换,避免按住 trigger 时抢先关、松开后又重开。\n startedWithinDropdown: Boolean(this.open && (startedInsideMenu || event.composedPath().includes(this))),\n completed: false\n }\n }\n\n private _onPointerUp = (event: PointerEvent) => {\n const interaction = this._pointerInteraction\n if (!interaction) return\n interaction.completed = true\n interaction.clickInsideMenu = Boolean(this._handle?.containsEvent(event))\n this._pointerInteraction = undefined\n this._resumePendingFocusOutCheck()\n }\n\n private _onPointerCancel = () => {\n const interaction = this._pointerInteraction\n if (!interaction) return\n interaction.completed = true\n interaction.clickInsideMenu = interaction.startedInsideMenu\n this._pointerInteraction = undefined\n this._resumePendingFocusOutCheck()\n }\n\n private _resumePendingFocusOutCheck() {\n const check = this._pendingFocusOutCheck\n this._pendingFocusOutCheck = undefined\n check?.()\n }\n\n private _onFocusOut = (event: FocusEvent) => {\n const handle = this._handle\n if (!this.open || !handle?.containsEvent(event)) return\n const pointerInteraction = this._pointerInteraction\n const source = event.composedPath()[0]\n // Lit 更新条目时可能替换焦点控件并从已脱离的节点派发 focusout。\n if (source instanceof Node && !source.isConnected) return\n const next = event.relatedTarget\n if (\n next instanceof Node &&\n [...this._overlays.values()].some(({ overlay }) => isComposedDescendant(next, overlay))\n ) {\n return\n }\n const movedToKnownOutsideTarget = next instanceof Node\n if (movedToKnownOutsideTarget) this._skipFocusRestoreOnClose = true\n\n const checkFocus = () => {\n if (!this.open || this._handle !== handle) return\n if (this._pendingTabNavigation) {\n this._pendingFocusOutCheck = () => this._overlay.scheduleFrame(checkFocus)\n return\n }\n if (pointerInteraction?.startedWithinDropdown) {\n if (!pointerInteraction.completed) {\n // pointerdown 可能先让 menu item 失焦;等同一手势的 pointerup/click 确认是否点在 menu 内。\n this._pendingFocusOutCheck = () => this._overlay.scheduleFrame(checkFocus)\n return\n }\n if (pointerInteraction.clickInsideMenu) return\n }\n if (handle.hasFocusWithin()) {\n if (movedToKnownOutsideTarget) this._skipFocusRestoreOnClose = false\n return\n }\n this._skipFocusRestoreOnClose = true\n this._closeAll(true)\n }\n this._overlay.scheduleFrame(checkFocus)\n }\n\n private _onFocusIn = (event: FocusEvent) => {\n const handle = this._handle\n if (!this.open || !handle) return\n if (!handle.containsEvent(event)) {\n if (this._pendingTabNavigation) return\n if (this._pointerInteraction?.startedWithinDropdown && !this._pointerInteraction.completed) return\n this._skipFocusRestoreOnClose = true\n this._closeAll(true)\n return\n }\n this._skipFocusRestoreOnClose = false\n const focusedItem = getMenuItemFromEvent(event)\n if (!focusedItem) return\n\n this._setMenuTabStop(focusedItem)\n }\n\n private _setMenuTabStop(focusedItem?: HTMLElement) {\n for (const { content } of this._overlays.values()) {\n content.querySelectorAll<HTMLElement>('web-ui-dropdown-item').forEach(item => {\n const control = item.shadowRoot?.querySelector<HTMLElement>('[role=\"menuitem\"]')\n if (control) control.tabIndex = item === focusedItem && !item.hasAttribute('disabled') ? 0 : -1\n })\n }\n }\n\n private _onMenuClick = (e: MouseEvent) => {\n const item = getMenuItemFromEvent(e)\n if (!item || item.hasAttribute('disabled') || !item.hasAttribute('submenu')) return\n\n const level = this._getFocusedLevel(item)\n if (level === undefined) return\n const itemIndex = this._getLevelItems(level).indexOf(item)\n if (itemIndex >= 0) this._toggleSubmenu(level, itemIndex, e.detail === 0)\n }\n\n private _onKeydown = (e: KeyboardEvent) => {\n if (!this.open) return\n\n if (e.key === 'Tab') return\n if (this.disabled) return\n\n // overlay 上键盘事件 target 是 menu item 而非组件自身,不能限定 e.target === this,\n // 否则鼠标打开、焦点在 menu item 时 Escape 无法关闭\n handleMenuKeyboard(this._keyboardDelegate, e)\n }\n\n private _onTabKeydown = (e: KeyboardEvent) => {\n if (e.key !== 'Tab' || !this.open || e.defaultPrevented) return\n const focusedItem = getMenuItemFromEvent(e)\n if (!focusedItem || this._getFocusedLevel(focusedItem) === undefined) return\n\n const isInsideNativeModal = [...this._overlays.values()].some(({ overlay }) => hasNativeModalAncestor(overlay))\n const navigation = {\n event: e,\n focusedItem,\n previousFocus:\n focusedItem.shadowRoot?.activeElement instanceof HTMLElement\n ? focusedItem.shadowRoot.activeElement\n : this._getDeepActiveElement(),\n focusTrigger: !isInsideNativeModal || !e.shiftKey\n }\n this._pendingTabNavigation = navigation\n this._setMenuTabStop()\n if (navigation.focusTrigger) this._focusTriggerForTab()\n\n // 等当前键盘事件及默认动作结束,再读取包括后注册 window listener 在内的最终取消状态。\n setTimeout(() => {\n if (this._pendingTabNavigation !== navigation) return\n this._pendingTabNavigation = undefined\n\n if (e.defaultPrevented) {\n this._setMenuTabStop(focusedItem)\n if (navigation.previousFocus?.isConnected && this._getDeepActiveElement() !== navigation.previousFocus) {\n navigation.previousFocus.focus()\n }\n return\n }\n\n if (navigation.focusTrigger || !this._handle?.hasFocusWithin()) {\n this._skipFocusRestoreOnClose = true\n this._closeAll(true)\n } else {\n this._setMenuTabStop(focusedItem)\n }\n }, 0)\n }\n\n private _getFocusedLevel(item?: HTMLElement): number | undefined {\n if (!item) return undefined\n const overlay = [...this._overlays.entries()].find(([, value]) => value.overlay.contains(item))\n return overlay?.[0]\n }\n\n private _bindHoversAfterUpdate() {\n requestAnimationFrame(() => this._hoverBinder.bind())\n }\n\n override render() {\n return html`\n <div class=\"dropdown-trigger\" @click=${this._onTriggerClick}>\n <slot name=\"trigger\"></slot>\n </div>\n `\n }\n\n declare readonly $events: {\n 'open-change': CustomEvent<{ open: boolean }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-dropdown': WebUiDropdown\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  //#region src/components/dropdown-item/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host{display:block}:host([disabled]){cursor:not-allowed;opacity:.4}.item-inner{-webkit-user-select:none;user-select:none;gap:var(--wui-space-2,8px);height:32px;padding:0 var(--wui-space-2,8px);border-radius:var(--wui-radius-control,calc(infinity * 1px));font-size:var(--wui-font-size,14px);color:inherit;white-space:nowrap;outline:none;align-items:center;display:flex}.item-inner:focus-visible{color:var(--wui-color-on-accent,#fff);background:var(--wui-color-accent,#08f)}:host([active]) .item-inner{color:inherit;background:var(--wui-color-border,#0000001a)}:host([data-wui-menu-focus-suppressed]) .item-inner:focus-visible{color:inherit;background:0 0}@media (hover:hover) and (pointer:fine){:host([data-wui-menu-focus-suppressed]) .item-inner:hover,:host(:not([active])) .item-inner:hover:not(:focus-visible){color:inherit;background:var(--wui-color-border,#0000001a)}}.item-label{min-width:0;color:inherit;text-overflow:ellipsis;flex:1;overflow:hidden}.item-suffix{opacity:.4;flex:none}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host{display:block}:host([disabled]){cursor:not-allowed;opacity:.4}.item-inner{-webkit-user-select:none;user-select:none;gap:var(--wui-space-2,8px);height:32px;padding:0 var(--wui-space-2,8px);border-radius:var(--wui-radius-control,calc(infinity * 1px));font-size:var(--wui-font-size,14px);color:inherit;white-space:nowrap;outline:none;align-items:center;display:flex}.item-inner:focus-visible{color:var(--wui-color-on-accent,#fff);background:var(--wui-color-accent,#0071e3)}:host([active]) .item-inner{color:inherit;background:var(--wui-color-border,#0000001a)}:host([data-wui-menu-focus-suppressed]) .item-inner:focus-visible{color:inherit;background:0 0}@media (hover:hover) and (pointer:fine){:host([data-wui-menu-focus-suppressed]) .item-inner:hover,:host(:not([active])) .item-inner:hover:not(:focus-visible){color:inherit;background:var(--wui-color-border,#0000001a)}}.item-label{min-width:0;color:inherit;text-overflow:ellipsis;flex:1;overflow:hidden}.item-suffix{opacity:.4;flex:none}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/dropdown-item/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.item-inner {\n user-select: none;\n\n display: flex;\n gap: var(--wui-space-2, 8px);\n align-items: center;\n\n height: 32px;\n padding: 0 var(--wui-space-2, 8px);\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n font-size: var(--wui-font-size, 14px);\n color: inherit;\n white-space: nowrap;\n\n outline: none;\n}\n\n.item-inner:focus-visible {\n color: var(--wui-color-on-accent, #fff);\n background: var(--wui-color-accent, #08f);\n}\n\n:host([active]) .item-inner {\n color: inherit;\n background: var(--wui-color-border, rgb(0 0 0 / 0.1));\n}\n\n:host([data-wui-menu-focus-suppressed]) .item-inner:focus-visible {\n color: inherit;\n background: transparent;\n}\n\n@media (hover: hover) and (pointer: fine) {\n :host([data-wui-menu-focus-suppressed]) .item-inner:hover,\n :host(:not([active])) .item-inner:hover:not(:focus-visible) {\n color: inherit;\n background: var(--wui-color-border, rgb(0 0 0 / 0.1));\n }\n}\n\n.item-label {\n overflow: hidden;\n flex: 1;\n\n min-width: 0;\n\n color: inherit;\n text-overflow: ellipsis;\n}\n\n.item-suffix {\n flex: none;\n opacity: 0.4;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/dropdown-item/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: block;\n}\n\n:host([disabled]) {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.item-inner {\n user-select: none;\n\n display: flex;\n gap: var(--wui-space-2, 8px);\n align-items: center;\n\n height: 32px;\n padding: 0 var(--wui-space-2, 8px);\n border-radius: var(--wui-radius-control, calc(infinity * 1px));\n\n font-size: var(--wui-font-size, 14px);\n color: inherit;\n white-space: nowrap;\n\n outline: none;\n}\n\n.item-inner:focus-visible {\n color: var(--wui-color-on-accent, #fff);\n background: var(--wui-color-accent, #0071e3);\n}\n\n:host([active]) .item-inner {\n color: inherit;\n background: var(--wui-color-border, rgb(0 0 0 / 0.1));\n}\n\n:host([data-wui-menu-focus-suppressed]) .item-inner:focus-visible {\n color: inherit;\n background: transparent;\n}\n\n@media (hover: hover) and (pointer: fine) {\n :host([data-wui-menu-focus-suppressed]) .item-inner:hover,\n :host(:not([active])) .item-inner:hover:not(:focus-visible) {\n color: inherit;\n background: var(--wui-color-border, rgb(0 0 0 / 0.1));\n }\n}\n\n.item-label {\n overflow: hidden;\n flex: 1;\n\n min-width: 0;\n\n color: inherit;\n text-overflow: ellipsis;\n}\n\n.item-suffix {\n flex: none;\n opacity: 0.4;\n}\n"],"mappings":""}
@@ -185,10 +185,14 @@ var y = class extends t(o) {
185
185
  render() {
186
186
  return s`
187
187
  <div class="layers" @pointerdown=${this._onPointerDown} @click=${this._onClick}>
188
- <span class=${p({
188
+ <span
189
+ class=${p({
189
190
  text: !0,
190
- placeholder: this._value === ""
191
- })}>${this._displayText}</span>
191
+ placeholder: this._value === "",
192
+ "trailing-newline": this._value.endsWith("\n")
193
+ })}
194
+ >${this._displayText}</span
195
+ >
192
196
  <textarea
193
197
  id=${this._fieldId}
194
198
  class="editor"