@greypan/web-ui 3.0.1 → 5.0.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 (238) hide show
  1. package/README.CN.md +495 -125
  2. package/README.md +504 -125
  3. package/dist/_virtual/{_@oxc-project_runtime@0.140.0 → _@oxc-project_runtime@0.146.0}/helpers/esm/decorate.js +1 -1
  4. package/dist/assets/glass.js +1 -1
  5. package/dist/assets/glass.js.map +1 -1
  6. package/dist/assets/menu-portal.js +1 -1
  7. package/dist/assets/menu-portal.js.map +1 -1
  8. package/dist/assets/overlay-motion.js +1 -1
  9. package/dist/assets/overlay-motion.js.map +1 -1
  10. package/dist/assets/toast-containers.js +1 -1
  11. package/dist/assets/toast-containers.js.map +1 -1
  12. package/dist/components/autocomplete/index.d.ts +12 -12
  13. package/dist/components/autocomplete/index.js +162 -111
  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.d.ts +0 -1
  18. package/dist/components/avatar/index.js +8 -13
  19. package/dist/components/avatar/index.js.map +1 -1
  20. package/dist/components/back-top/index.js +2 -2
  21. package/dist/components/back-top/index.js.map +1 -1
  22. package/dist/components/back-top/style.js +1 -1
  23. package/dist/components/back-top/style.js.map +1 -1
  24. package/dist/components/badge/index.d.ts +1 -0
  25. package/dist/components/badge/index.js +12 -14
  26. package/dist/components/badge/index.js.map +1 -1
  27. package/dist/components/button/index.d.ts +2 -0
  28. package/dist/components/button/index.js +52 -38
  29. package/dist/components/button/index.js.map +1 -1
  30. package/dist/components/button/style.js +1 -1
  31. package/dist/components/button/style.js.map +1 -1
  32. package/dist/components/button-group/index.d.ts +1 -2
  33. package/dist/components/button-group/index.js +21 -23
  34. package/dist/components/button-group/index.js.map +1 -1
  35. package/dist/components/button-group/style.js +1 -1
  36. package/dist/components/button-group/style.js.map +1 -1
  37. package/dist/components/checkbox/index.d.ts +4 -7
  38. package/dist/components/checkbox/index.js +56 -38
  39. package/dist/components/checkbox/index.js.map +1 -1
  40. package/dist/components/checkbox/style.js +1 -1
  41. package/dist/components/checkbox/style.js.map +1 -1
  42. package/dist/components/checkbox-group/index.d.ts +4 -10
  43. package/dist/components/checkbox-group/index.js +74 -60
  44. package/dist/components/checkbox-group/index.js.map +1 -1
  45. package/dist/components/collapse/index.d.ts +66 -0
  46. package/dist/components/collapse/index.js +159 -0
  47. package/dist/components/collapse/index.js.map +1 -0
  48. package/dist/components/collapse/style.js +6 -0
  49. package/dist/components/collapse/style.js.map +1 -0
  50. package/dist/components/context-menu/index.d.ts +29 -0
  51. package/dist/components/context-menu/index.js +168 -53
  52. package/dist/components/context-menu/index.js.map +1 -1
  53. package/dist/components/dialog/index.d.ts +6 -0
  54. package/dist/components/dialog/index.js +34 -13
  55. package/dist/components/dialog/index.js.map +1 -1
  56. package/dist/components/dialog/style.js +1 -1
  57. package/dist/components/dialog/style.js.map +1 -1
  58. package/dist/components/drawer/index.d.ts +45 -0
  59. package/dist/components/drawer/index.js +270 -56
  60. package/dist/components/drawer/index.js.map +1 -1
  61. package/dist/components/drawer/style.js +1 -1
  62. package/dist/components/drawer/style.js.map +1 -1
  63. package/dist/components/dropdown/index.d.ts +2 -0
  64. package/dist/components/dropdown/index.js +24 -14
  65. package/dist/components/dropdown/index.js.map +1 -1
  66. package/dist/components/dropdown-divider/index.js +1 -1
  67. package/dist/components/dropdown-header/index.js +1 -1
  68. package/dist/components/dropdown-header/style.js +1 -1
  69. package/dist/components/dropdown-header/style.js.map +1 -1
  70. package/dist/components/dropdown-item/index.js +3 -2
  71. package/dist/components/dropdown-item/index.js.map +1 -1
  72. package/dist/components/dropdown-item/style.js +1 -1
  73. package/dist/components/dropdown-item/style.js.map +1 -1
  74. package/dist/components/empty/index.d.ts +1 -0
  75. package/dist/components/empty/index.js +24 -22
  76. package/dist/components/empty/index.js.map +1 -1
  77. package/dist/components/empty/style.js +1 -1
  78. package/dist/components/empty/style.js.map +1 -1
  79. package/dist/components/icon/index.js +1 -1
  80. package/dist/components/index.d.ts +1 -0
  81. package/dist/components/index.js +21 -20
  82. package/dist/components/input/index.d.ts +2 -3
  83. package/dist/components/input/index.js +62 -52
  84. package/dist/components/input/index.js.map +1 -1
  85. package/dist/components/input/style.js +1 -1
  86. package/dist/components/input/style.js.map +1 -1
  87. package/dist/components/input-number/index.d.ts +2 -3
  88. package/dist/components/input-number/index.js +58 -38
  89. package/dist/components/input-number/index.js.map +1 -1
  90. package/dist/components/input-number/style.js +1 -1
  91. package/dist/components/input-number/style.js.map +1 -1
  92. package/dist/components/layout/index.d.ts +76 -3
  93. package/dist/components/layout/index.js +250 -39
  94. package/dist/components/layout/index.js.map +1 -1
  95. package/dist/components/layout/style.js +1 -1
  96. package/dist/components/layout/style.js.map +1 -1
  97. package/dist/components/option/index.js +1 -1
  98. package/dist/components/option/style.js +1 -1
  99. package/dist/components/option/style.js.map +1 -1
  100. package/dist/components/popover/index.d.ts +2 -1
  101. package/dist/components/popover/index.js +14 -8
  102. package/dist/components/popover/index.js.map +1 -1
  103. package/dist/components/popover/style.js +1 -1
  104. package/dist/components/popover/style.js.map +1 -1
  105. package/dist/components/radio/index.d.ts +4 -7
  106. package/dist/components/radio/index.js +51 -37
  107. package/dist/components/radio/index.js.map +1 -1
  108. package/dist/components/radio/style.js +1 -1
  109. package/dist/components/radio/style.js.map +1 -1
  110. package/dist/components/radio-group/index.d.ts +4 -10
  111. package/dist/components/radio-group/index.js +70 -52
  112. package/dist/components/radio-group/index.js.map +1 -1
  113. package/dist/components/segmented/index.d.ts +14 -12
  114. package/dist/components/segmented/index.js +132 -54
  115. package/dist/components/segmented/index.js.map +1 -1
  116. package/dist/components/segmented/style.js +1 -1
  117. package/dist/components/segmented/style.js.map +1 -1
  118. package/dist/components/segmented-trigger/index.d.ts +1 -2
  119. package/dist/components/segmented-trigger/index.js +23 -21
  120. package/dist/components/segmented-trigger/index.js.map +1 -1
  121. package/dist/components/segmented-trigger/style.js +1 -1
  122. package/dist/components/segmented-trigger/style.js.map +1 -1
  123. package/dist/components/select/index.d.ts +13 -8
  124. package/dist/components/select/index.js +114 -75
  125. package/dist/components/select/index.js.map +1 -1
  126. package/dist/components/select/style.js +1 -1
  127. package/dist/components/select/style.js.map +1 -1
  128. package/dist/components/slider/index.d.ts +6 -7
  129. package/dist/components/slider/index.js +99 -64
  130. package/dist/components/slider/index.js.map +1 -1
  131. package/dist/components/slider/style.js +1 -1
  132. package/dist/components/slider/style.js.map +1 -1
  133. package/dist/components/spinner/index.d.ts +0 -2
  134. package/dist/components/spinner/index.js +14 -13
  135. package/dist/components/spinner/index.js.map +1 -1
  136. package/dist/components/spinner/style.js +1 -1
  137. package/dist/components/spinner/style.js.map +1 -1
  138. package/dist/components/svg-draw-lines/index.js +1 -1
  139. package/dist/components/switch/index.d.ts +13 -6
  140. package/dist/components/switch/index.js +102 -41
  141. package/dist/components/switch/index.js.map +1 -1
  142. package/dist/components/switch/style.js +1 -1
  143. package/dist/components/switch/style.js.map +1 -1
  144. package/dist/components/textarea/index.d.ts +5 -6
  145. package/dist/components/textarea/index.js +74 -67
  146. package/dist/components/textarea/index.js.map +1 -1
  147. package/dist/components/textarea/style.js +1 -1
  148. package/dist/components/textarea/style.js.map +1 -1
  149. package/dist/components/theme/index.js +1 -1
  150. package/dist/components/theme/style.js +1 -1
  151. package/dist/components/theme/style.js.map +1 -1
  152. package/dist/components/toast/style.js +1 -1
  153. package/dist/components/toast/style.js.map +1 -1
  154. package/dist/components/toast/toast.js +12 -12
  155. package/dist/components/toast/toast.js.map +1 -1
  156. package/dist/components/tooltip/index.js +3 -3
  157. package/dist/components/tooltip/index.js.map +1 -1
  158. package/dist/components/tooltip/style.js +1 -1
  159. package/dist/components/tooltip/style.js.map +1 -1
  160. package/dist/icons/generated/heroicons-arrow-down-16-solid.d.ts +6 -0
  161. package/dist/icons/generated/heroicons-arrow-up-16-solid.d.ts +6 -0
  162. package/dist/icons/generated/heroicons-bars-arrow-down-16-solid.d.ts +6 -0
  163. package/dist/icons/generated/heroicons-bars-arrow-down-16-solid.js +10 -0
  164. package/dist/icons/generated/heroicons-bars-arrow-down-16-solid.js.map +1 -0
  165. package/dist/icons/generated/heroicons-bars-arrow-up-16-solid.d.ts +6 -0
  166. package/dist/icons/generated/heroicons-bars-arrow-up-16-solid.js +10 -0
  167. package/dist/icons/generated/heroicons-bars-arrow-up-16-solid.js.map +1 -0
  168. package/dist/icons/generated/lucide-clapperboard.d.ts +6 -0
  169. package/dist/icons/generated/lucide-clapperboard.js +10 -0
  170. package/dist/icons/generated/lucide-clapperboard.js.map +1 -0
  171. package/dist/icons/generated/lucide-code.d.ts +6 -0
  172. package/dist/icons/generated/lucide-code.js +10 -0
  173. package/dist/icons/generated/lucide-code.js.map +1 -0
  174. package/dist/icons/generated/lucide-ellipsis-vertical.d.ts +6 -0
  175. package/dist/icons/generated/lucide-ellipsis-vertical.js +10 -0
  176. package/dist/icons/generated/lucide-ellipsis-vertical.js.map +1 -0
  177. package/dist/icons/generated/lucide-eye.d.ts +6 -0
  178. package/dist/icons/generated/lucide-eye.js +10 -0
  179. package/dist/icons/generated/lucide-eye.js.map +1 -0
  180. package/dist/icons/generated/lucide-headphones.d.ts +6 -0
  181. package/dist/icons/generated/lucide-headphones.js +10 -0
  182. package/dist/icons/generated/lucide-headphones.js.map +1 -0
  183. package/dist/icons/generated/lucide-link.d.ts +6 -0
  184. package/dist/icons/generated/lucide-link.js +10 -0
  185. package/dist/icons/generated/lucide-link.js.map +1 -0
  186. package/dist/icons/generated/lucide-list-filter.d.ts +6 -0
  187. package/dist/icons/generated/lucide-list-filter.js +10 -0
  188. package/dist/icons/generated/lucide-list-filter.js.map +1 -0
  189. package/dist/icons/generated/lucide-list-restart.d.ts +6 -0
  190. package/dist/icons/generated/lucide-list-restart.js +10 -0
  191. package/dist/icons/generated/lucide-list-restart.js.map +1 -0
  192. package/dist/icons/generated/lucide-pen-line.d.ts +6 -0
  193. package/dist/icons/generated/lucide-pen-line.js +10 -0
  194. package/dist/icons/generated/lucide-pen-line.js.map +1 -0
  195. package/dist/icons/generated/lucide-play.d.ts +6 -0
  196. package/dist/icons/generated/lucide-play.js +10 -0
  197. package/dist/icons/generated/lucide-play.js.map +1 -0
  198. package/dist/icons/generated/lucide-sliders-horizontal.d.ts +6 -0
  199. package/dist/icons/generated/lucide-sliders-horizontal.js +10 -0
  200. package/dist/icons/generated/lucide-sliders-horizontal.js.map +1 -0
  201. package/dist/icons/generated/lucide-tag.d.ts +6 -0
  202. package/dist/icons/generated/lucide-tag.js +10 -0
  203. package/dist/icons/generated/lucide-tag.js.map +1 -0
  204. package/dist/icons/generated/tabler-sort-ascending-letters.d.ts +6 -0
  205. package/dist/icons/generated/tabler-sort-ascending-letters.js +10 -0
  206. package/dist/icons/generated/tabler-sort-ascending-letters.js.map +1 -0
  207. package/dist/icons/index.d.ts +15 -0
  208. package/dist/icons/index.js +18 -3
  209. package/dist/node_modules/.pnpm/@floating-ui_core@1.8.0/node_modules/@floating-ui/core/dist/floating-ui.core.js +1 -3
  210. package/dist/node_modules/.pnpm/@floating-ui_core@1.8.0/node_modules/@floating-ui/core/dist/floating-ui.core.js.map +1 -1
  211. package/dist/node_modules/.pnpm/@floating-ui_utils@0.2.12/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js +2 -1
  212. package/dist/node_modules/.pnpm/@floating-ui_utils@0.2.12/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js.map +1 -1
  213. package/dist/shared/events/user-change.js.map +1 -1
  214. package/dist/shared/form-association/index.js +41 -0
  215. package/dist/shared/form-association/index.js.map +1 -0
  216. package/dist/shared/gesture/drag-gesture.js +133 -0
  217. package/dist/shared/gesture/drag-gesture.js.map +1 -0
  218. package/dist/shared/gesture/physics.js +45 -0
  219. package/dist/shared/gesture/physics.js.map +1 -0
  220. package/dist/shared/group-management/index.js +111 -0
  221. package/dist/shared/group-management/index.js.map +1 -0
  222. package/dist/shared/menu-portal/menu-portal.js +22 -10
  223. package/dist/shared/menu-portal/menu-portal.js.map +1 -1
  224. package/dist/shared/menu-portal/menu-tree.js +22 -7
  225. package/dist/shared/menu-portal/menu-tree.js.map +1 -1
  226. package/dist/shared/option-portal/index.js +65 -0
  227. package/dist/shared/option-portal/index.js.map +1 -0
  228. package/dist/shared/overlay/native-dialog-presence.js.map +1 -1
  229. package/dist/shared/overlay/nested-drawer-layers.js +55 -0
  230. package/dist/shared/overlay/nested-drawer-layers.js.map +1 -0
  231. package/dist/shared/overlay/overlay.js +1 -1
  232. package/dist/shared/overlay/overlay.js.map +1 -1
  233. package/dist/shared/overlay/portal.js +47 -13
  234. package/dist/shared/overlay/portal.js.map +1 -1
  235. package/dist/shared/overlay/presence.js.map +1 -1
  236. package/dist/shared/visible-area/index.js +69 -0
  237. package/dist/shared/visible-area/index.js.map +1 -0
  238. package/package.json +8 -4
@@ -1,65 +1,276 @@
1
- import e from "../../_virtual/_@oxc-project_runtime@0.140.0/helpers/esm/decorate.js";
1
+ import e from "../../_virtual/_@oxc-project_runtime@0.146.0/helpers/esm/decorate.js";
2
2
  import "../icon/index.js";
3
3
  import t from "../../icons/generated/radix-icons-panel-left-minimized.js";
4
4
  import n from "../../assets/glass.js";
5
5
  import "../button/index.js";
6
- import r from "./style.js";
7
- import { LitElement as i, html as a, unsafeCSS as o } from "lit";
8
- import { customElement as s, state as c } from "lit/decorators.js";
9
- import { classMap as l } from "lit/directives/class-map.js";
6
+ import { attachDragGesture as r } from "../../shared/gesture/drag-gesture.js";
7
+ import { clamp as i } from "../../shared/gesture/physics.js";
8
+ import "../drawer/index.js";
9
+ import { VisibleAreaController as a, defineVisibleAreaTracker as o } from "../../shared/visible-area/index.js";
10
+ import s from "./style.js";
11
+ import { LitElement as c, html as l, nothing as u, unsafeCSS as d } from "lit";
12
+ import { customElement as f, property as p, state as m } from "lit/decorators.js";
13
+ import { classMap as h } from "lit/directives/class-map.js";
14
+ import { styleMap as g } from "lit/directives/style-map.js";
10
15
  //#region src/components/layout/index.ts
11
- var u = class extends i {
16
+ var _ = class extends c {
12
17
  constructor(...e) {
13
- super(...e), this._sidebarOpen = !1;
18
+ super(...e), this.sidebarCollapsed = !1, this.sidebarWidth = "240px", this.collapsedWidth = "68px", this.sidebarResizable = !1, this.sidebarMinWidth = "", this.sidebarMaxWidth = "", this.sidebarOpen = !1, this.headerGlow = !1, this._isMobile = !1, this._visibleBanner = o({ onVisibleAreaChange: (e) => {
19
+ this.style.setProperty("--wui-layout-visible-banner-height", `${e.height}px`);
20
+ } }).make(), this._visibleBannerController = new a(this, this._visibleBanner), this._resizeGesture = null, this._resizeStartWidth = 0, this._resizeWidth = null, this._resizeTimeout = null, this._handleResize = () => {
21
+ this._resizeTimeout !== null && clearTimeout(this._resizeTimeout), this._resizeTimeout = setTimeout(() => {
22
+ this._checkMobile(), this._resizeTimeout = null;
23
+ }, 100);
24
+ };
14
25
  }
15
26
  static {
16
- this.styles = [o(n), o(r)];
27
+ this.styles = [d(n), d(s)];
17
28
  }
18
29
  _toggleSidebar() {
19
- this._sidebarOpen = !this._sidebarOpen;
30
+ if (this._isMobile) {
31
+ this._emitSidebarOpenChange(!this.sidebarOpen);
32
+ return;
33
+ }
34
+ this._emitSidebarCollapsedChange(!this.sidebarCollapsed);
20
35
  }
21
- _closeSidebar() {
22
- this._sidebarOpen = !1;
36
+ _emitSidebarCollapsedChange(e) {
37
+ this.dispatchEvent(new CustomEvent("sidebar-collapsed-change", {
38
+ detail: { collapsed: e },
39
+ bubbles: !0,
40
+ composed: !0
41
+ }));
23
42
  }
24
- _onSidebarClick(e) {
25
- e.target.closest("a, button, [role=\"button\"]") && this._closeSidebar();
43
+ _emitSidebarOpenChange(e) {
44
+ this.dispatchEvent(new CustomEvent("sidebar-open-change", {
45
+ detail: { open: e },
46
+ bubbles: !0,
47
+ composed: !0
48
+ }));
49
+ }
50
+ _onDrawerChange(e) {
51
+ e.stopPropagation(), this._emitSidebarOpenChange(e.detail.open);
52
+ }
53
+ _parsePx(e, t) {
54
+ let n = Number.parseFloat(e);
55
+ return Number.isFinite(n) ? n : t;
56
+ }
57
+ _resolveSidebarMinWidth() {
58
+ return this.sidebarMinWidth ? this._parsePx(this.sidebarMinWidth, this._parsePx(this.collapsedWidth, 68)) : this._parsePx(this.collapsedWidth, 68);
59
+ }
60
+ _resolveSidebarMaxWidth() {
61
+ let e = Math.floor(window.innerWidth / 2), t = this.sidebarMaxWidth ? this._parsePx(this.sidebarMaxWidth, e) : e;
62
+ return Math.max(Math.min(t, e), this._resolveSidebarMinWidth());
63
+ }
64
+ _isResizing() {
65
+ return this._resizeGesture?.isDragging() ?? !1;
66
+ }
67
+ _handleResizePointerDown(e) {
68
+ if (!this.sidebarResizable || this.sidebarCollapsed || this._isMobile || this._isResizing() || e.isPrimary === !1) return;
69
+ let t = this.renderRoot.querySelector("aside");
70
+ t && (this._resizeStartWidth = this._parsePx(window.getComputedStyle(t).width, this._parsePx(this.sidebarWidth, 240)), this._resizeWidth = null, t.classList.add("is-resizing"), this._resizeGesture = r(e, {
71
+ axis: "x",
72
+ onMove: (e) => {
73
+ let t = this._resizeStartWidth + e.deltaX, n = i(t, this._resolveSidebarMinWidth(), this._resolveSidebarMaxWidth());
74
+ this._resizeWidth = `${Math.round(n)}px`;
75
+ },
76
+ onEnd: () => {
77
+ if (this._resizeWidth === null) {
78
+ this._resetActiveResize();
79
+ return;
80
+ }
81
+ let e = this._resizeWidth;
82
+ this._resetActiveResize(), this.dispatchEvent(new CustomEvent("sidebar-width-change", {
83
+ detail: { width: e },
84
+ bubbles: !0,
85
+ composed: !0
86
+ }));
87
+ },
88
+ onCancel: () => {
89
+ this._resetActiveResize();
90
+ }
91
+ }));
92
+ }
93
+ _resetActiveResize() {
94
+ this._resizeGesture?.destroy(), this._resizeGesture = null, this.renderRoot.querySelector("aside")?.classList.remove("is-resizing"), this._resizeWidth = null;
95
+ }
96
+ _handleResizeKeydown(e) {
97
+ if (!this.sidebarResizable || this.sidebarCollapsed || this._isMobile || this._isResizing()) return;
98
+ let t = this._resolveSidebarMinWidth(), n = this._resolveSidebarMaxWidth(), r = this.renderRoot.querySelector("aside"), i = this._resizeWidth ? this._parsePx(this._resizeWidth, t) : this._parsePx(r ? window.getComputedStyle(r).width : this.sidebarWidth, t), a = e.shiftKey ? 64 : 16, o = null;
99
+ switch (e.key) {
100
+ case "ArrowLeft":
101
+ o = Math.max(t, i - a);
102
+ break;
103
+ case "ArrowRight":
104
+ o = Math.min(n, i + a);
105
+ break;
106
+ case "Home":
107
+ o = t;
108
+ break;
109
+ case "End":
110
+ o = n;
111
+ break;
112
+ case "Enter":
113
+ if (this._resizeWidth !== null) {
114
+ let e = this._resizeWidth;
115
+ this._resizeWidth = null, this.dispatchEvent(new CustomEvent("sidebar-width-change", {
116
+ detail: { width: e },
117
+ bubbles: !0,
118
+ composed: !0
119
+ }));
120
+ }
121
+ e.preventDefault();
122
+ return;
123
+ case "Escape":
124
+ this._resizeWidth = null, e.preventDefault();
125
+ return;
126
+ default: return;
127
+ }
128
+ e.preventDefault(), this._resizeWidth = `${Math.round(o)}px`;
129
+ }
130
+ _checkMobile() {
131
+ let e = window.innerWidth <= 640;
132
+ e !== this._isMobile && this._isResizing() && this._resetActiveResize(), this._isMobile = e;
133
+ }
134
+ connectedCallback() {
135
+ super.connectedCallback(), this._checkMobile(), window.addEventListener("resize", this._handleResize), this.updateComplete.then(() => {
136
+ this.isConnected && this._syncBannerPresence();
137
+ });
138
+ }
139
+ disconnectedCallback() {
140
+ super.disconnectedCallback(), this._resetActiveResize(), window.removeEventListener("resize", this._handleResize), this._resizeTimeout !== null && clearTimeout(this._resizeTimeout), this._resizeTimeout = null;
141
+ }
142
+ firstUpdated() {
143
+ this._syncBannerPresence();
144
+ }
145
+ _onBannerSlotChange() {
146
+ this._syncBannerPresence();
147
+ }
148
+ _syncBannerPresence() {
149
+ let e = this.renderRoot.querySelector("slot[name=\"banner\"]")?.assignedNodes().some((e) => e.nodeType === Node.ELEMENT_NODE || e.nodeType === Node.TEXT_NODE && !!e.textContent?.trim()) ?? !1, t = this.shadowRoot?.querySelector(".layout-banner") ?? null;
150
+ this._visibleBanner.setTarget(e ? t : null);
26
151
  }
27
152
  render() {
28
- return a`
29
- <div class="layout-grid">
30
- <header>
31
- <slot name="header"></slot>
32
- </header>
33
- <main>
34
- <slot></slot>
35
- </main>
36
- <aside class="${l({ open: this._sidebarOpen })}" @click="${this._onSidebarClick}">
37
- <div class="menu wui-glass"><slot name="sidebar"></slot></div>
38
- </aside>
39
- <footer>
40
- <slot name="tabbar"></slot>
41
- </footer>
42
- </div>
43
-
44
- <div class="${l({
45
- backdrop: !0,
46
- open: this._sidebarOpen
47
- })}" @click="${this._closeSidebar}"></div>
48
-
153
+ let e = !this.sidebarCollapsed, n = this._isMobile ? {} : { width: this._resizeWidth ?? (this.sidebarCollapsed ? this.collapsedWidth : this.sidebarWidth) }, r = e ? "折叠侧边栏" : "展开侧边栏", i = l`
49
154
  <web-ui-button
50
- class="mobile-toggle"
155
+ class="sidebar-toggle"
51
156
  icon
52
- variant="glass"
157
+ variant="secondary"
53
158
  @click="${this._toggleSidebar}"
54
- aria-label="打开导航菜单"
159
+ aria-label="${r}"
55
160
  >
56
161
  <web-ui-icon .icon=${t}></web-ui-icon>
57
162
  </web-ui-button>
163
+ `, a = l`
164
+ <div class="sidebar-viewport">
165
+ <slot name="sidebar"></slot>
166
+ </div>
167
+ `, o = l`
168
+ <div class="layout-body">
169
+ <div class="sidebar-wrapper">
170
+ <aside
171
+ class="${h({ collapsed: !e })}"
172
+ style="${g(n)}"
173
+ >
174
+ <div class="aside-panel wui-glass">
175
+ ${a}
176
+ <div class="sidebar-toggle-area">${i}</div>
177
+ </div>
178
+ ${this.sidebarResizable && !this.sidebarCollapsed ? l`
179
+ <div
180
+ class="sidebar-resize-handle"
181
+ role="separator"
182
+ tabindex="0"
183
+ aria-orientation="vertical"
184
+ aria-label="调整侧边栏宽度"
185
+ @pointerdown=${this._handleResizePointerDown}
186
+ @keydown=${this._handleResizeKeydown}
187
+ ></div>
188
+ ` : u}
189
+ </aside>
190
+ </div>
191
+ <div class="layout-content">
192
+ <header>
193
+ <slot name="header"></slot>
194
+ </header>
195
+ <main><slot></slot></main>
196
+ <footer><slot name="tabbar"></slot></footer>
197
+ </div>
198
+ </div>
199
+ `, s = l`
200
+ <div class="layout-content">
201
+ <header>
202
+ <web-ui-button
203
+ class="mobile-toggle"
204
+ icon
205
+ variant="glass"
206
+ @click="${this._toggleSidebar}"
207
+ aria-label="打开导航菜单"
208
+ >
209
+ <web-ui-icon .icon=${t}></web-ui-icon>
210
+ </web-ui-button>
211
+ <slot name="header"></slot>
212
+ </header>
213
+ <main><slot></slot></main>
214
+ <footer><slot name="tabbar"></slot></footer>
215
+ </div>
216
+
217
+ <web-ui-drawer
218
+ placement="left"
219
+ ?open="${this.sidebarOpen}"
220
+ controlled
221
+ draggable
222
+ dialog-label="主导航"
223
+ @open-change="${this._onDrawerChange}"
224
+ style="${g({ "--wui-layout-mobile-sidebar-width": this.sidebarWidth })}"
225
+ headless
226
+ >
227
+ <div class="aside-panel wui-glass mobile-sidebar">${a}</div>
228
+ </web-ui-drawer>
229
+ `;
230
+ return l`
231
+ <div class="layout-page">
232
+ <div class="layout-banner">
233
+ <slot name="banner" @slotchange="${this._onBannerSlotChange}"></slot>
234
+ </div>
235
+ ${this._isMobile ? s : o}
236
+ </div>
58
237
  `;
59
238
  }
60
239
  };
61
- e([c()], u.prototype, "_sidebarOpen", void 0), u = e([s("web-ui-layout")], u);
240
+ e([p({
241
+ type: Boolean,
242
+ attribute: "sidebar-collapsed",
243
+ reflect: !0
244
+ })], _.prototype, "sidebarCollapsed", void 0), e([p({
245
+ type: String,
246
+ attribute: "sidebar-width",
247
+ reflect: !0
248
+ })], _.prototype, "sidebarWidth", void 0), e([p({
249
+ type: String,
250
+ attribute: "collapsed-width",
251
+ reflect: !0
252
+ })], _.prototype, "collapsedWidth", void 0), e([p({
253
+ type: Boolean,
254
+ attribute: "sidebar-resizable",
255
+ reflect: !0
256
+ })], _.prototype, "sidebarResizable", void 0), e([p({
257
+ type: String,
258
+ attribute: "sidebar-min-width",
259
+ reflect: !0
260
+ })], _.prototype, "sidebarMinWidth", void 0), e([p({
261
+ type: String,
262
+ attribute: "sidebar-max-width",
263
+ reflect: !0
264
+ })], _.prototype, "sidebarMaxWidth", void 0), e([p({
265
+ type: Boolean,
266
+ attribute: "sidebar-open",
267
+ reflect: !0
268
+ })], _.prototype, "sidebarOpen", void 0), e([p({
269
+ type: Boolean,
270
+ attribute: "header-glow",
271
+ reflect: !0
272
+ })], _.prototype, "headerGlow", void 0), e([m()], _.prototype, "_isMobile", void 0), e([m()], _.prototype, "_resizeWidth", void 0), _ = e([f("web-ui-layout")], _);
62
273
  //#endregion
63
- export { u as WebUiLayout };
274
+ export { _ as WebUiLayout };
64
275
 
65
276
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/layout/index.ts"],"sourcesContent":["import { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\n\nimport glass from '@/assets/glass.css?inline'\nimport '@/components/icon'\nimport '@/components/button'\nimport { radixIconsPanelLeftMinimized } from '@/icons'\n\nimport style from './style.css?inline'\n\n@customElement('web-ui-layout')\nexport class WebUiLayout extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n @state() private _sidebarOpen = false\n\n private _toggleSidebar() {\n this._sidebarOpen = !this._sidebarOpen\n }\n\n private _closeSidebar() {\n this._sidebarOpen = false\n }\n\n private _onSidebarClick(e: MouseEvent) {\n const target = e.target as HTMLElement\n if (target.closest('a, button, [role=\"button\"]')) {\n this._closeSidebar()\n }\n }\n\n override render() {\n return html`\n <div class=\"layout-grid\">\n <header>\n <slot name=\"header\"></slot>\n </header>\n <main>\n <slot></slot>\n </main>\n <aside class=\"${classMap({ open: this._sidebarOpen })}\" @click=\"${this._onSidebarClick}\">\n <div class=\"menu wui-glass\"><slot name=\"sidebar\"></slot></div>\n </aside>\n <footer>\n <slot name=\"tabbar\"></slot>\n </footer>\n </div>\n\n <div class=\"${classMap({ backdrop: true, open: this._sidebarOpen })}\" @click=\"${this._closeSidebar}\"></div>\n\n <web-ui-button\n class=\"mobile-toggle\"\n icon\n variant=\"glass\"\n @click=\"${this._toggleSidebar}\"\n aria-label=\"打开导航菜单\"\n >\n <web-ui-icon .icon=${radixIconsPanelLeftMinimized}></web-ui-icon>\n </web-ui-button>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-layout': WebUiLayout\n }\n}\n"],"mappings":";;;;;;;;;;AAYO,IAAM,IAAN,cAA0B,EAAW;;EAGV,aAAA,KAAA,eAAA;;;EAFP,KAAA,SAAA,CAAC,EAAU,CAAK,GAAG,EAAU,CAAK,CAAC;;CAI5D,iBAAyB;EACvB,KAAK,eAAe,CAAC,KAAK;CAC5B;CAEA,gBAAwB;EACtB,KAAK,eAAe;CACtB;CAEA,gBAAwB,GAAe;EAErC,AADe,EAAE,OACN,QAAQ,8BAA4B,KAC7C,KAAK,cAAc;CAEvB;CAEA,SAAkB;EAChB,OAAO,CAAI;;;;;;;;wBAQS,EAAS,EAAE,MAAM,KAAK,aAAa,CAAC,EAAE,YAAY,KAAK,gBAAgB;;;;;;;;oBAQ3E,EAAS;GAAE,UAAU;GAAM,MAAM,KAAK;EAAa,CAAC,EAAE,YAAY,KAAK,cAAc;;;;;;kBAMvF,KAAK,eAAe;;;6BAGT,EAA6B;;;CAGxD;AACF;AA/CG,EAAA,CAAA,EAAM,CAAA,GAAA,EAAA,WAAA,gBAAA,KAAA,CAAA,GAJR,IAAA,EAAA,CAAA,EAAc,eAAe,CAAA,GAAA,CAAA"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/layout/index.ts"],"sourcesContent":["import { html, LitElement, nothing, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { styleMap } from 'lit/directives/style-map.js'\n\nimport glass from '@/assets/glass.css?inline'\nimport '@/components/icon'\nimport '@/components/button'\nimport '@/components/drawer'\nimport { radixIconsPanelLeftMinimized } from '@/icons'\nimport { attachDragGesture, clamp, type DragGestureHandle } from '@/shared/gesture'\nimport { defineVisibleAreaTracker, VisibleAreaController } from '@/shared/visible-area'\n\nimport style from './style.css?inline'\n\n/**\n * Layout 组件 - 提供页面布局框架,支持可折叠侧边栏\n *\n * @fires sidebar-collapsed-change - 桌面端侧边栏折叠状态变更请求时触发\n * @fires sidebar-open-change - 移动端侧边栏 Drawer 开关请求时触发\n * @fires sidebar-width-change - 桌面端侧边栏拖拽调宽结束时触发,携带最终宽度(受控请求)\n * @slot banner - 顶部 Banner 区域(全宽,随页面滚动,可选)\n * @slot header - 内容区顶部 header(sticky)\n * @slot sidebar - 侧边栏内容;Consumer 决定其内部固定区域与滚动容器\n * @slot tabbar - 底部 tabbar 区域\n * @slot default - 主内容区\n */\n@customElement('web-ui-layout')\nexport class WebUiLayout extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(style)]\n\n /**\n * 桌面端 Sidebar 的持久布局偏好。\n *\n * `true` 只会将桌面 Sidebar 收窄到 `collapsedWidth`,不会影响移动端 Drawer。\n * 它不与 `sidebarOpen` 合并:前者是跨视口保留的密度选择,后者是移动端瞬时的 modal 可见性。\n */\n @property({ type: Boolean, attribute: 'sidebar-collapsed', reflect: true })\n sidebarCollapsed = false\n\n @property({ type: String, attribute: 'sidebar-width', reflect: true })\n sidebarWidth = '240px'\n\n @property({ type: String, attribute: 'collapsed-width', reflect: true })\n collapsedWidth = '68px'\n\n /** 启用桌面端 Sidebar 拖拽调宽(折叠态隐藏 handle)。 */\n @property({ type: Boolean, attribute: 'sidebar-resizable', reflect: true })\n sidebarResizable = false\n\n /**\n * 拖拽调宽的下限(px,其他单位不解析);未设置时回退为 `collapsedWidth`,\n * 防止拖到不可用宽度。上限 `sidebar-max-width` 受内置 50vw 硬上限钳制。\n */\n @property({ type: String, attribute: 'sidebar-min-width', reflect: true })\n sidebarMinWidth = ''\n\n /** 拖拽调宽的上限(px,其他单位不解析);始终受内置 50vw 硬上限钳制。 */\n @property({ type: String, attribute: 'sidebar-max-width', reflect: true })\n sidebarMaxWidth = ''\n\n /**\n * 移动端 headless Drawer 的瞬时可见性。\n *\n * Drawer Toggle、Escape 和遮罩关闭都通过 `sidebar-open-change` 请求更新它;它不会改变桌面端的折叠偏好。\n * 因而不与 `sidebarCollapsed` 合并,避免响应式切换时将一次移动端交互误写为桌面端布局选择。\n */\n @property({ type: Boolean, attribute: 'sidebar-open', reflect: true })\n sidebarOpen = false\n\n /**\n * 启用 header 晕染效果\n */\n @property({ type: Boolean, attribute: 'header-glow', reflect: true })\n headerGlow = false\n\n @state() private _isMobile = false\n\n private readonly _visibleBanner = defineVisibleAreaTracker({\n onVisibleAreaChange: area => {\n this.style.setProperty('--wui-layout-visible-banner-height', `${area.height}px`)\n }\n }).make()\n\n private readonly _visibleBannerController = new VisibleAreaController(this, this._visibleBanner)\n\n private _toggleSidebar() {\n if (this._isMobile) {\n this._emitSidebarOpenChange(!this.sidebarOpen)\n return\n }\n\n this._emitSidebarCollapsedChange(!this.sidebarCollapsed)\n }\n\n private _emitSidebarCollapsedChange(collapsed: boolean) {\n this.dispatchEvent(\n new CustomEvent('sidebar-collapsed-change', {\n detail: { collapsed },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private _emitSidebarOpenChange(open: boolean) {\n this.dispatchEvent(\n new CustomEvent('sidebar-open-change', {\n detail: { open },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private _onDrawerChange(e: CustomEvent<{ open: boolean }>) {\n e.stopPropagation()\n this._emitSidebarOpenChange(e.detail.open)\n }\n\n // ===== 桌面端 Sidebar 拖拽调宽 =====\n\n private _resizeGesture: DragGestureHandle | null = null\n private _resizeStartWidth = 0\n // 拖拽中的临时宽度;由 render 的 styleMap 统一写入,避免与 Lit 样式管理竞争。\n @state() private _resizeWidth: string | null = null\n\n private _parsePx(value: string, fallback: number): number {\n const parsed = Number.parseFloat(value)\n return Number.isFinite(parsed) ? parsed : fallback\n }\n\n private _resolveSidebarMinWidth(): number {\n // 未设置时回退为折叠宽度,防止拖到不可用宽度。\n return this.sidebarMinWidth\n ? this._parsePx(this.sidebarMinWidth, this._parsePx(this.collapsedWidth, 68))\n : this._parsePx(this.collapsedWidth, 68)\n }\n\n private _resolveSidebarMaxWidth(): number {\n // 组件内置硬上限:Sidebar 最多占视口一半(无需调用方设置)。\n // 调用方 sidebar-max-width 在该上限内生效,防止拖拽占据整个视口。\n const halfViewport = Math.floor(window.innerWidth / 2)\n const configured = this.sidebarMaxWidth ? this._parsePx(this.sidebarMaxWidth, halfViewport) : halfViewport\n const upper = Math.min(configured, halfViewport)\n return Math.max(upper, this._resolveSidebarMinWidth())\n }\n\n private _isResizing(): boolean {\n return this._resizeGesture?.isDragging() ?? false\n }\n\n private _handleResizePointerDown(e: PointerEvent) {\n if (!this.sidebarResizable || this.sidebarCollapsed || this._isMobile || this._isResizing()) return\n // jsdom 等环境的 PointerEvent 可能缺失 isPrimary,仅在明确为 false(多点触控副指针)时拒绝。\n if (e.isPrimary === false) return\n\n const aside = this.renderRoot.querySelector('aside')\n if (!aside) return\n\n // 拖拽起点以 computed width 为准,并丢弃键盘未提交的调整(Enter 才提交、\n // Escape 撤回;抓取隐式放弃),保证零位移松手不会派发陈旧宽度。\n this._resizeStartWidth = this._parsePx(window.getComputedStyle(aside).width, this._parsePx(this.sidebarWidth, 240))\n this._resizeWidth = null\n aside.classList.add('is-resizing')\n\n this._resizeGesture = attachDragGesture(e, {\n axis: 'x',\n onMove: info => {\n // 向右拖增宽、向左拖收窄(handle 在右缘);钳制在 [min, max] 与视口内。\n const next = this._resizeStartWidth + info.deltaX\n const clamped = clamp(next, this._resolveSidebarMinWidth(), this._resolveSidebarMaxWidth())\n this._resizeWidth = `${Math.round(clamped)}px`\n },\n onEnd: () => {\n // 零位移松手(点击而非拖拽)不视为调宽动作:按 cancel 语义静默收尾。\n if (this._resizeWidth === null) {\n this._resetActiveResize()\n return\n }\n const width = this._resizeWidth\n this._resetActiveResize()\n // 受控契约:松手派发请求并交还 prop 管辖,由 Consumer 回写 sidebar-width。\n this.dispatchEvent(\n new CustomEvent('sidebar-width-change', {\n detail: { width },\n bubbles: true,\n composed: true\n })\n )\n },\n onCancel: () => {\n this._resetActiveResize()\n }\n })\n }\n\n // 终结进行中的拖拽:清手势状态、移除跟手 class,宽度过渡回 prop 管辖,不派发事件。\n // pointer cancel 与视口跨越移动端断点(handle 随桌面 layout 卸载)共用此收尾。\n private _resetActiveResize() {\n this._resizeGesture?.destroy()\n this._resizeGesture = null\n this.renderRoot.querySelector('aside')?.classList.remove('is-resizing')\n this._resizeWidth = null\n }\n\n // 键盘调宽(WAI-ARIA splitter 模式):方向键步进 16px(Shift 加速 64px)调整\n // 临时宽度,Enter 以受控请求派发 `sidebar-width-change`(与指针松手同语义),\n // Escape 撤回临时宽度交还 prop 管辖,Home/End 直接到 min/max。\n private _handleResizeKeydown(e: KeyboardEvent) {\n if (!this.sidebarResizable || this.sidebarCollapsed || this._isMobile || this._isResizing()) return\n\n const min = this._resolveSidebarMinWidth()\n const max = this._resolveSidebarMaxWidth()\n const aside = this.renderRoot.querySelector('aside')\n const current = this._resizeWidth\n ? this._parsePx(this._resizeWidth, min)\n : this._parsePx(aside ? window.getComputedStyle(aside).width : this.sidebarWidth, min)\n const step = e.shiftKey ? 64 : 16\n let next: number | null = null\n\n switch (e.key) {\n case 'ArrowLeft':\n next = Math.max(min, current - step)\n break\n case 'ArrowRight':\n next = Math.min(max, current + step)\n break\n case 'Home':\n next = min\n break\n case 'End':\n next = max\n break\n case 'Enter':\n // 无未提交调整时不派发(焦点停留时的回车噪声)\n if (this._resizeWidth !== null) {\n const width = this._resizeWidth\n this._resizeWidth = null\n this.dispatchEvent(\n new CustomEvent('sidebar-width-change', { detail: { width }, bubbles: true, composed: true })\n )\n }\n e.preventDefault()\n return\n case 'Escape':\n this._resizeWidth = null\n e.preventDefault()\n return\n default:\n return\n }\n e.preventDefault()\n this._resizeWidth = `${Math.round(next)}px`\n }\n\n private _checkMobile() {\n const nextMobile = window.innerWidth <= 640\n // 视口跨越移动端断点会卸载桌面 layout(handle 随之消失);必须先终结进行中的\n // 拖拽,否则 _resizePointerId 悬挂,切回桌面后所有新的拖拽在入口被拦截。\n if (nextMobile !== this._isMobile && this._isResizing()) this._resetActiveResize()\n this._isMobile = nextMobile\n }\n\n private _resizeTimeout: ReturnType<typeof setTimeout> | null = null\n\n private _handleResize = () => {\n if (this._resizeTimeout !== null) clearTimeout(this._resizeTimeout)\n this._resizeTimeout = setTimeout(() => {\n this._checkMobile()\n this._resizeTimeout = null\n }, 100)\n }\n\n override connectedCallback() {\n super.connectedCallback()\n this._checkMobile()\n window.addEventListener('resize', this._handleResize)\n void this.updateComplete.then(() => {\n if (this.isConnected) this._syncBannerPresence()\n })\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n this._resetActiveResize()\n window.removeEventListener('resize', this._handleResize)\n if (this._resizeTimeout !== null) clearTimeout(this._resizeTimeout)\n this._resizeTimeout = null\n }\n\n override firstUpdated() {\n this._syncBannerPresence()\n }\n\n private _onBannerSlotChange() {\n this._syncBannerPresence()\n }\n\n private _syncBannerPresence() {\n const bannerSlot = this.renderRoot.querySelector<HTMLSlotElement>('slot[name=\"banner\"]')\n const hasBanner =\n bannerSlot\n ?.assignedNodes()\n .some(\n node =>\n node.nodeType === Node.ELEMENT_NODE || (node.nodeType === Node.TEXT_NODE && !!node.textContent?.trim())\n ) ?? false\n const banner = this.shadowRoot?.querySelector<HTMLElement>('.layout-banner') ?? null\n this._visibleBanner.setTarget(hasBanner ? banner : null)\n }\n\n override render() {\n const isSidebarOpen = !this.sidebarCollapsed\n // 拖拽中的临时宽度优先于 prop 宽度;移动端宽度由 Drawer 内部变量管理。\n const sidebarStyle = this._isMobile\n ? {}\n : { width: this._resizeWidth ?? (this.sidebarCollapsed ? this.collapsedWidth : this.sidebarWidth) }\n\n const toggleLabel = isSidebarOpen ? '折叠侧边栏' : '展开侧边栏'\n\n const desktopToggle = html`\n <web-ui-button\n class=\"sidebar-toggle\"\n icon\n variant=\"secondary\"\n @click=\"${this._toggleSidebar}\"\n aria-label=\"${toggleLabel}\"\n >\n <web-ui-icon .icon=${radixIconsPanelLeftMinimized}></web-ui-icon>\n </web-ui-button>\n `\n\n const sidebarViewport = html`\n <div class=\"sidebar-viewport\">\n <slot name=\"sidebar\"></slot>\n </div>\n `\n\n // 桌面端布局\n const desktopLayout = html`\n <div class=\"layout-body\">\n <div class=\"sidebar-wrapper\">\n <aside\n class=\"${classMap({\n collapsed: !isSidebarOpen\n })}\"\n style=\"${styleMap(sidebarStyle)}\"\n >\n <div class=\"aside-panel wui-glass\">\n ${sidebarViewport}\n <div class=\"sidebar-toggle-area\">${desktopToggle}</div>\n </div>\n ${\n this.sidebarResizable && !this.sidebarCollapsed\n ? html`\n <div\n class=\"sidebar-resize-handle\"\n role=\"separator\"\n tabindex=\"0\"\n aria-orientation=\"vertical\"\n aria-label=\"调整侧边栏宽度\"\n @pointerdown=${this._handleResizePointerDown}\n @keydown=${this._handleResizeKeydown}\n ></div>\n `\n : nothing\n }\n </aside>\n </div>\n <div class=\"layout-content\">\n <header>\n <slot name=\"header\"></slot>\n </header>\n <main><slot></slot></main>\n <footer><slot name=\"tabbar\"></slot></footer>\n </div>\n </div>\n `\n\n // 移动端布局\n const mobileLayout = html`\n <div class=\"layout-content\">\n <header>\n <web-ui-button\n class=\"mobile-toggle\"\n icon\n variant=\"glass\"\n @click=\"${this._toggleSidebar}\"\n aria-label=\"打开导航菜单\"\n >\n <web-ui-icon .icon=${radixIconsPanelLeftMinimized}></web-ui-icon>\n </web-ui-button>\n <slot name=\"header\"></slot>\n </header>\n <main><slot></slot></main>\n <footer><slot name=\"tabbar\"></slot></footer>\n </div>\n\n <web-ui-drawer\n placement=\"left\"\n ?open=\"${this.sidebarOpen}\"\n controlled\n draggable\n dialog-label=\"主导航\"\n @open-change=\"${this._onDrawerChange}\"\n style=\"${styleMap({ '--wui-layout-mobile-sidebar-width': this.sidebarWidth })}\"\n headless\n >\n <div class=\"aside-panel wui-glass mobile-sidebar\">${sidebarViewport}</div>\n </web-ui-drawer>\n `\n\n return html`\n <div class=\"layout-page\">\n <div class=\"layout-banner\">\n <slot name=\"banner\" @slotchange=\"${this._onBannerSlotChange}\"></slot>\n </div>\n ${this._isMobile ? mobileLayout : desktopLayout}\n </div>\n `\n }\n\n declare readonly $events: {\n 'sidebar-collapsed-change': CustomEvent<{ collapsed: boolean }>\n 'sidebar-open-change': CustomEvent<{ open: boolean }>\n 'sidebar-width-change': CustomEvent<{ width: string }>\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'web-ui-layout': WebUiLayout\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  //#region src/components/layout/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host{display:block}.layout-grid{grid-template-areas:\"sidebar header\"\"sidebar content\";grid-template-columns:var(--web-ui-base-layout-sidebar-width,240px) 1fr;grid-template-rows:var(--web-ui-base-layout-header-height,64px) 1fr;box-sizing:border-box;min-height:100vh;display:grid}.layout-grid *{box-sizing:inherit}header{z-index:var(--wui-layer-header,10);grid-area:header;position:sticky;top:0;right:0}main{grid-area:content}aside{grid-area:sidebar;height:100vh;padding:8px;position:sticky;top:0;left:0}aside .menu{background-color:var(--wui-color-surface-overlay,#f6f6f6e0);border-radius:24px;height:100%}footer{grid-area:footer}.backdrop{display:none}.mobile-toggle{z-index:var(--wui-layer-header,20);visibility:hidden;position:fixed;top:12px;left:12px}@media (width<=640px){.layout-grid{grid-template-columns:1fr;grid-template-areas:\"header\"\"content\"}aside{z-index:var(--wui-layer-drawer,100);width:var(--web-ui-base-layout-sidebar-width,240px);height:100dvh;transition:transform var(--wui-duration-drawer-enter,.28s) ease;padding:8px;position:fixed;top:0;left:0;transform:translate(-100%)}aside.open{transform:translate(0)}.backdrop{z-index:var(--wui-layer-backdrop,90);background:#0000004d;display:none;position:fixed;inset:0}.backdrop.open{display:block}.mobile-toggle{visibility:visible}}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host{--wui-layout-visible-banner-height:0px;--wui-layout-header-glow-color:var(--wui-color-page,#fff);display:block}.layout-page{flex-direction:column;min-height:100dvh;display:flex}.layout-banner{z-index:var(--wui-layer-banner,30);position:relative}.layout-body{flex:1;display:flex}.sidebar-wrapper{align-self:stretch;position:relative}.sidebar-viewport{flex:1;min-height:0}.mobile-sidebar{width:calc(var(--wui-layout-mobile-sidebar-width,240px) - 16px);border-radius:var(--wui-layout-sidebar-radius,24px);background-color:var(--wui-color-surface-overlay,#f6f6f6d1);flex-direction:column;max-width:calc(100vw - 16px);height:calc(100dvh - 16px);min-height:0;margin:8px;display:flex}aside{z-index:var(--wui-layer-sidebar,50);max-width:50vw;height:calc(100vh - var(--wui-layout-visible-banner-height));height:calc(100dvh - var(--wui-layout-visible-banner-height));max-height:calc(100vh - var(--wui-layout-visible-banner-height));max-height:calc(100dvh - var(--wui-layout-visible-banner-height));transition:width var(--wui-duration-layout,.2s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1));flex-direction:column;flex-shrink:0;padding:8px;display:flex;position:sticky;top:0}aside .aside-panel{border-radius:var(--wui-layout-sidebar-radius,24px);background-color:var(--wui-color-surface-overlay,#f6f6f6d1);flex-direction:column;flex:1;min-height:0;display:flex}aside .sidebar-toggle-area{flex-shrink:0;align-items:center;display:flex}aside .sidebar-toggle{margin:8px}aside.collapsed .sidebar-viewport{overflow:hidden}.sidebar-resize-handle{touch-action:none;cursor:col-resize;z-index:1;width:12px;position:absolute;top:0;bottom:0;right:-6px}.sidebar-resize-handle:before{content:\"\";opacity:0;background:var(--wui-color-accent,#08f);width:3px;transition:opacity var(--wui-duration-feedback,.1s) ease;border-radius:999px;position:absolute;top:0;bottom:0;left:50%;translate:-50%}.sidebar-resize-handle:hover:before,.sidebar-resize-handle:focus-visible:before,aside.is-resizing .sidebar-resize-handle:before{opacity:1}aside.is-resizing{transition:none}.layout-content{flex-direction:column;flex:1;min-width:0;display:flex}header{isolation:isolate;z-index:var(--wui-layer-header,10);align-items:center;gap:8px;display:flex;position:sticky;top:0}.mobile-toggle{margin-left:var(--wui-layout-mobile-toggle-inset,8px)}:host([header-glow]) header:before{pointer-events:none;content:\"\";z-index:-1;opacity:.95;background-color:var(--wui-layout-header-glow-color);filter:blur(10px);position:absolute;inset:0;transform:translate(20px,-50%)scale(1.05,2)}main{flex:1}footer{z-index:var(--wui-layer-tabbar,40);position:sticky;bottom:0}@media (width<=640px){aside,.sidebar-wrapper{display:none}}@media (prefers-reduced-motion:reduce){aside,.sidebar-resize-handle:before{transition:none}}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/layout/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n display: block;\n}\n\n.layout-grid {\n display: grid;\n grid-template-areas:\n 'sidebar header'\n 'sidebar content';\n grid-template-columns: var(--web-ui-base-layout-sidebar-width, 240px) 1fr;\n grid-template-rows: var(--web-ui-base-layout-header-height, 64px) 1fr;\n\n box-sizing: border-box;\n min-height: 100dvh;\n min-height: 100vh;\n\n * {\n box-sizing: inherit;\n }\n}\n\nheader {\n position: sticky;\n z-index: var(--wui-layer-header, 10);\n top: 0;\n right: 0;\n\n grid-area: header;\n}\n\nmain {\n grid-area: content;\n}\n\naside {\n position: sticky;\n top: 0;\n left: 0;\n\n grid-area: sidebar;\n\n height: 100dvh;\n height: 100vh;\n padding: 8px;\n\n .menu {\n height: 100%;\n border-radius: 24px;\n background-color: var(--wui-color-surface-overlay, rgb(246 246 246 / 0.88));\n }\n}\n\nfooter {\n grid-area: footer;\n}\n\n.backdrop {\n display: none;\n}\n\n.mobile-toggle {\n position: fixed;\n z-index: var(--wui-layer-header, 20);\n top: 12px;\n left: 12px;\n\n visibility: hidden;\n}\n\n@media (width <= 640px) {\n .layout-grid {\n grid-template-areas:\n 'header'\n 'content';\n grid-template-columns: 1fr;\n }\n\n aside {\n position: fixed;\n z-index: var(--wui-layer-drawer, 100);\n top: 0;\n left: 0;\n transform: translateX(-100%);\n\n width: var(--web-ui-base-layout-sidebar-width, 240px);\n height: 100dvh;\n padding: 8px;\n\n transition: transform var(--wui-duration-drawer-enter, 280ms) ease;\n }\n\n aside.open {\n transform: translateX(0);\n }\n\n .backdrop {\n position: fixed;\n z-index: var(--wui-layer-backdrop, 90);\n inset: 0;\n\n display: none;\n\n background: rgb(0 0 0 / 0.3);\n }\n\n .backdrop.open {\n display: block;\n }\n\n .mobile-toggle {\n visibility: visible;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/layout/style.css?inline"],"sourcesContent":["*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n:host {\n --wui-layout-visible-banner-height: 0px;\n --wui-layout-header-glow-color: var(--wui-color-page, #fff);\n\n display: block;\n}\n\n/* 页面级滚动容器。Banner 位于正文前,随页面一起滚动。 */\n.layout-page {\n display: flex;\n flex-direction: column;\n min-height: 100vh;\n min-height: 100dvh;\n}\n\n.layout-banner {\n position: relative;\n z-index: var(--wui-layer-banner, 30);\n}\n\n/* 参考 book-fe:正文区域负责撑高 sidebar 的 relative wrapper。 */\n.layout-body {\n display: flex;\n flex: 1;\n}\n\n.sidebar-wrapper {\n position: relative;\n align-self: stretch;\n}\n\n/* Layout 只提供可用高度;Consumer 决定其内部 scrollport。 */\n.sidebar-viewport {\n flex: 1;\n min-height: 0;\n}\n\n/* headless drawer 只提供 overlay 基础设施;此卡片与桌面端 aside-panel 相同。 */\n.mobile-sidebar {\n display: flex;\n flex-direction: column;\n\n width: calc(var(--wui-layout-mobile-sidebar-width, 240px) - 16px);\n max-width: calc(100vw - 16px);\n height: calc(100vh - 16px);\n height: calc(100dvh - 16px);\n min-height: 0;\n margin: 8px;\n border-radius: var(--wui-layout-sidebar-radius, 24px);\n\n background-color: var(--wui-color-surface-overlay, rgb(246 246 246 / 0.82));\n}\n\n/*\n * Banner 可见时,组件用它的当前可见高度缩短 aside;Banner 滚出后该值归零。\n * 因而圆角卡片始终完整可见,同时 sticky Sidebar 可在 Banner 消失后填满视口。\n */\naside {\n position: sticky;\n z-index: var(--wui-layer-sidebar, 50);\n top: 0;\n\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n\n max-width: 50vw;\n height: calc(100vh - var(--wui-layout-visible-banner-height));\n height: calc(100dvh - var(--wui-layout-visible-banner-height));\n max-height: calc(100vh - var(--wui-layout-visible-banner-height));\n max-height: calc(100dvh - var(--wui-layout-visible-banner-height));\n padding: 8px;\n\n transition: width var(--wui-duration-layout, 200ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n\n .aside-panel {\n display: flex;\n flex: 1;\n flex-direction: column;\n\n min-height: 0;\n border-radius: var(--wui-layout-sidebar-radius, 24px);\n\n background-color: var(--wui-color-surface-overlay, rgb(246 246 246 / 0.82));\n }\n\n .sidebar-toggle-area {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n }\n\n .sidebar-toggle {\n margin: 8px;\n }\n\n &.collapsed {\n .sidebar-viewport {\n overflow: hidden;\n }\n }\n}\n\n/* ===== Sidebar 拖拽调宽 handle ===== */\n\n/*\n * 命中条贴 aside 右缘(约 12px 宽),hover 或拖拽中显示 3px accent 竖线。\n * aside 有 8px padding,handle 定位在 padding 区外缘,不遮挡 aside-panel 内容。\n */\n.sidebar-resize-handle {\n touch-action: none;\n cursor: col-resize;\n\n position: absolute;\n z-index: 1;\n top: 0;\n right: -6px;\n bottom: 0;\n\n width: 12px;\n}\n\n.sidebar-resize-handle::before {\n content: '';\n\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n translate: -50%;\n\n width: 3px;\n border-radius: 999px;\n\n opacity: 0;\n background: var(--wui-color-accent, #08f);\n\n transition: opacity var(--wui-duration-feedback, 100ms) ease;\n}\n\n.sidebar-resize-handle:hover::before,\n.sidebar-resize-handle:focus-visible::before,\naside.is-resizing .sidebar-resize-handle::before {\n opacity: 1;\n}\n\n/* 拖拽中禁用宽度过渡,保证实时跟手。 */\naside.is-resizing {\n transition: none;\n}\n\n.layout-content {\n display: flex;\n flex: 1;\n flex-direction: column;\n min-width: 0;\n}\n\nheader {\n /* 将负层级 glow 限定在 Header 的局部 stacking context,slot 内容自然位于其上。 */\n isolation: isolate;\n position: sticky;\n z-index: var(--wui-layer-header, 10);\n top: 0;\n\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n/* 移动端 Toggle 属于组件自身,不随 Consumer 的 header 内边距缩进;\n 默认 8px 使其脱离视口边缘,Consumer 可用同名变量对齐自身内容左缘。 */\n.mobile-toggle {\n margin-left: var(--wui-layout-mobile-toggle-inset, 8px);\n}\n\n/*\n * Header 的装饰性背景晕染\n * ========================\n *\n * 伪元素随 header 的实际盒子尺寸和 sticky 位置变化,自然适配 header slot 的\n * 高度与位置,无需单独维护一层 DOM。\n *\n * 通过 translate + scale 将晕染区域从 header 中心向外扩展,\n * 并使用 blur 模糊边缘,实现柔和的渐变过渡效果。\n */\n:host([header-glow]) header::before {\n pointer-events: none;\n content: '';\n\n position: absolute;\n z-index: -1;\n inset: 0;\n transform: translate(20px, -50%) scale(1.05, 2);\n\n opacity: 0.95;\n background-color: var(--wui-layout-header-glow-color);\n filter: blur(10px);\n}\n\nmain {\n flex: 1;\n}\n\nfooter {\n position: sticky;\n z-index: var(--wui-layer-tabbar, 40);\n bottom: 0;\n}\n\n@media (width <= 640px) {\n aside,\n .sidebar-wrapper {\n display: none;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n aside {\n transition: none;\n }\n\n .sidebar-resize-handle::before {\n transition: none;\n }\n}\n"],"mappings":""}
@@ -1,4 +1,4 @@
1
- import e from "../../_virtual/_@oxc-project_runtime@0.140.0/helpers/esm/decorate.js";
1
+ import e from "../../_virtual/_@oxc-project_runtime@0.146.0/helpers/esm/decorate.js";
2
2
  import "../icon/index.js";
3
3
  import t from "../../icons/generated/heroicons-check-16-solid.js";
4
4
  import n from "./style.js";
@@ -1,5 +1,5 @@
1
1
  //#region src/components/option/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host{display:block}:host([disabled]){cursor:not-allowed;opacity:.4}.option-label{cursor:pointer;-webkit-user-select:none;user-select:none;box-sizing:border-box;height:32px;font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);text-overflow:ellipsis;white-space:nowrap;transition:color var(--wui-duration-feedback,.1s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1)), background-color var(--wui-duration-feedback,.1s) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1));border-radius:2147483647px;align-items:center;gap:8px;padding:0 8px;display:flex;overflow:hidden}.check{flex-shrink:0}.content-wrap{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}:host(:not([selected])) .check{visibility:hidden}::slotted([slot=prefix]),::slotted([slot=suffix]){flex-shrink:0}.option-label:focus-visible{outline:3px solid var(--wui-focus-ring,#08f6);outline-offset:2px}:host([active]) .option-label{color:var(--wui-color-on-accent,#fff);background:var(--wui-color-accent,#08f)}@media (hover:hover) and (pointer:fine){.option-label:hover{color:var(--wui-color-on-accent,#fff);background:var(--wui-color-accent,#08f)}}:host([disabled]) .option-label{cursor:not-allowed}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host{display:block}:host([disabled]){cursor:not-allowed;opacity:.4}.option-label{cursor:default;-webkit-user-select:none;user-select:none;box-sizing:border-box;height:32px;font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);text-overflow:ellipsis;white-space:nowrap;border-radius:2147483647px;align-items:center;gap:8px;padding:0 8px;display:flex;overflow:hidden}.check{display:var(--wui-option-check-display,block);flex-shrink:0}.content-wrap{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}:host(:not([selected])) .check{visibility:hidden}::slotted([slot=prefix]),::slotted([slot=suffix]){flex-shrink:0}.option-label:focus-visible{outline:var(--wui-focus-ring-width,3px) solid var(--wui-color-focus-ring,#08f6);outline-offset:2px}:host([active]) .option-label{color:var(--wui-color-on-accent,#fff);background:var(--wui-color-accent,#08f)}@media (hover:hover) and (pointer:fine){.option-label:hover{color:var(--wui-color-on-accent,#fff);background:var(--wui-color-accent,#08f)}}:host([disabled]) .option-label{cursor:not-allowed}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/option/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.option-label {\n cursor: pointer;\n user-select: none;\n\n overflow: hidden;\n display: flex;\n gap: 8px;\n align-items: center;\n\n box-sizing: border-box;\n height: 32px;\n padding: 0 8px;\n border-radius: calc(infinity * 1px);\n\n font-size: var(--wui-font-size, 14px);\n color: var(--wui-color-text, #1b1b1b);\n text-overflow: ellipsis;\n white-space: nowrap;\n\n transition:\n color var(--wui-duration-feedback, 100ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n background-color var(--wui-duration-feedback, 100ms) var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n}\n\n.check {\n flex-shrink: 0;\n}\n\n.content-wrap {\n overflow: hidden;\n flex: 1;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n:host(:not([selected])) .check {\n visibility: hidden;\n}\n\n::slotted([slot='prefix']),\n::slotted([slot='suffix']) {\n flex-shrink: 0;\n}\n\n.option-label:focus-visible {\n outline: 3px solid var(--wui-focus-ring, rgb(0 136 255 / 0.4));\n outline-offset: 2px;\n}\n\n:host([active]) .option-label {\n color: var(--wui-color-on-accent, #fff);\n background: var(--wui-color-accent, #08f);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .option-label:hover {\n color: var(--wui-color-on-accent, #fff);\n background: var(--wui-color-accent, #08f);\n }\n}\n\n:host([disabled]) .option-label {\n cursor: not-allowed;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"style.js","names":[],"sources":["../../../src/components/option/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.option-label {\n cursor: default;\n user-select: none;\n\n overflow: hidden;\n display: flex;\n gap: 8px;\n align-items: center;\n\n box-sizing: border-box;\n height: 32px;\n padding: 0 8px;\n border-radius: calc(infinity * 1px);\n\n font-size: var(--wui-font-size, 14px);\n color: var(--wui-color-text, #1b1b1b);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.check {\n display: var(--wui-option-check-display, block);\n flex-shrink: 0;\n}\n\n.content-wrap {\n overflow: hidden;\n flex: 1;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n:host(:not([selected])) .check {\n visibility: hidden;\n}\n\n::slotted([slot='prefix']),\n::slotted([slot='suffix']) {\n flex-shrink: 0;\n}\n\n.option-label:focus-visible {\n outline: var(--wui-focus-ring-width, 3px) solid var(--wui-color-focus-ring, rgb(0 136 255 / 0.4));\n outline-offset: 2px;\n}\n\n:host([active]) .option-label {\n color: var(--wui-color-on-accent, #fff);\n background: var(--wui-color-accent, #08f);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .option-label:hover {\n color: var(--wui-color-on-accent, #fff);\n background: var(--wui-color-accent, #08f);\n }\n}\n\n:host([disabled]) .option-label {\n cursor: not-allowed;\n}\n"],"mappings":""}
@@ -24,8 +24,8 @@ export declare class WebUiPopover extends LitElement {
24
24
  private readonly _panel;
25
25
  get isOpen(): boolean;
26
26
  connectedCallback(): void;
27
- disconnectedCallback(): void;
28
27
  firstUpdated(): void;
28
+ disconnectedCallback(): void;
29
29
  protected updated(changed: Map<string, unknown>): void;
30
30
  show(): void;
31
31
  close(): void;
@@ -37,6 +37,7 @@ export declare class WebUiPopover extends LitElement {
37
37
  private _closeOverlay;
38
38
  private _reconfigureOverlay;
39
39
  private _dispatchChange;
40
+ private _syncTriggerAria;
40
41
  private _focusPanel;
41
42
  private _returnFocus;
42
43
  private _queryTrigger;
@@ -1,4 +1,4 @@
1
- import e from "../../_virtual/_@oxc-project_runtime@0.140.0/helpers/esm/decorate.js";
1
+ import e from "../../_virtual/_@oxc-project_runtime@0.146.0/helpers/esm/decorate.js";
2
2
  import t from "../../assets/glass.js";
3
3
  import n from "../../assets/overlay-motion.js";
4
4
  import { normalizeLiteral as r, normalizeNumber as i } from "../../shared/normalize/index.js";
@@ -98,17 +98,19 @@ var m = [
98
98
  connectedCallback() {
99
99
  super.connectedCallback(), document.addEventListener("click", this._onClickOutside), document.addEventListener("keydown", this._onKeydown), this.addEventListener("focusout", this._onFocusOut), this._syncTriggerListeners();
100
100
  }
101
+ firstUpdated() {
102
+ this.shadowRoot?.querySelector("slot[name=\"trigger\"]")?.addEventListener("slotchange", () => this.requestUpdate()), this.open && (requestAnimationFrame(() => this._openOverlay(this._shouldOpenInstantly)), this._shouldOpenInstantly = !0);
103
+ }
101
104
  disconnectedCallback() {
102
105
  super.disconnectedCallback(), document.removeEventListener("click", this._onClickOutside), document.removeEventListener("keydown", this._onKeydown), this.removeEventListener("focusout", this._onFocusOut), this.removeEventListener("pointerenter", this._onPointerEnter), this.removeEventListener("pointerleave", this._onPointerLeave), clearTimeout(this._showTimer), clearTimeout(this._hideTimer), this._panel.dispose();
103
106
  }
104
- firstUpdated() {
105
- this.open && (requestAnimationFrame(() => this._openOverlay(this._shouldOpenInstantly)), this._shouldOpenInstantly = !0);
106
- }
107
107
  updated(e) {
108
- if (e.has("portal") || e.has("overlayContainer") ? requestAnimationFrame(() => this._reconfigureOverlay()) : (e.has("placement") || e.has("offset")) && requestAnimationFrame(() => this._panel.updatePosition()), e.has("open")) if (this.open) {
109
- let e = this._shouldOpenInstantly;
110
- this._shouldOpenInstantly = !0, requestAnimationFrame(() => this._openOverlay(e)), this._userOpenChange.consume() && this._dispatchChange(!0), this._focusPanel();
111
- } else this._returnFocus(), this._closeOverlay(), this._userOpenChange.consume() && this._dispatchChange(!1);
108
+ if (this._syncTriggerAria(), e.has("portal") || e.has("overlayContainer") ? requestAnimationFrame(() => this._reconfigureOverlay()) : (e.has("placement") || e.has("offset")) && requestAnimationFrame(() => this._panel.updatePosition()), e.has("open")) {
109
+ if (this.open) {
110
+ let e = this._shouldOpenInstantly;
111
+ this._shouldOpenInstantly = !0, requestAnimationFrame(() => this._openOverlay(e)), this._userOpenChange.consume() && this._dispatchChange(!0), this._focusPanel();
112
+ } else this._returnFocus(), this._closeOverlay(), this._userOpenChange.consume() && this._dispatchChange(!1);
113
+ }
112
114
  e.has("trigger") && (this.removeEventListener("pointerenter", this._onPointerEnter), this.removeEventListener("pointerleave", this._onPointerLeave), clearTimeout(this._showTimer), clearTimeout(this._hideTimer), this._syncTriggerListeners());
113
115
  }
114
116
  show() {
@@ -152,6 +154,10 @@ var m = [
152
154
  composed: !0
153
155
  }));
154
156
  }
157
+ _syncTriggerAria() {
158
+ let e = this._queryTrigger();
159
+ e && (e.setAttribute("aria-expanded", String(this.open)), e.setAttribute("aria-controls", this._panelId));
160
+ }
155
161
  _focusPanel() {
156
162
  requestAnimationFrame(() => {
157
163
  let e = this._panel.getPanel()?.querySelector("[autofocus]");
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/popover/index.ts"],"sourcesContent":["import type { Placement } from '@floating-ui/dom'\nimport { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport glass from '@/assets/glass.css?inline'\nimport overlayMotion from '@/assets/overlay-motion.css?inline'\nimport { UserChangeController } from '@/shared/events/user-change'\nimport { normalizeLiteral, normalizeNumber } from '@/shared/normalize'\nimport { defineAnchoredPanel } from '@/shared/overlay/anchored-panel'\nimport { defineOverlayPortal } from '@/shared/overlay/portal'\nimport type { OverlayContainer, OverlayPortal } from '@/shared/overlay/portal'\n\nimport style from './style.css?inline'\n\nconst ALLOWED_PLACEMENTS = [\n 'top',\n 'top-start',\n 'top-end',\n 'bottom',\n 'bottom-start',\n 'bottom-end',\n 'left',\n 'left-start',\n 'left-end',\n 'right',\n 'right-start',\n 'right-end'\n] as const\n\nconst ALLOWED_TRIGGERS = ['click', 'hover', 'manual'] as const\n\nlet popoverIdCounter = 0\n\n@customElement('web-ui-popover')\nexport class WebUiPopover extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(overlayMotion), unsafeCSS(style)]\n\n @property({ type: Boolean, reflect: true }) open = false\n @property({ type: Boolean, reflect: true }) disabled = false\n\n @property({ type: String, reflect: true })\n get placement(): Placement {\n return this._placement\n }\n set placement(v: string) {\n const old = this._placement\n this._placement = normalizeLiteral(v, ALLOWED_PLACEMENTS, 'bottom')\n this.requestUpdate('placement', old)\n }\n private _placement: Placement = 'bottom'\n\n @property({ type: Number })\n get offset(): number {\n return this._offset\n }\n set offset(v: number) {\n const old = this._offset\n this._offset = normalizeNumber(v, 0, 100, 8)\n this.requestUpdate('offset', old)\n }\n private _offset = 8\n\n @property({ type: String, reflect: true })\n get trigger(): 'click' | 'hover' | 'manual' {\n return this._trigger\n }\n set trigger(v: string) {\n const old = this._trigger\n this._trigger = normalizeLiteral(v, ALLOWED_TRIGGERS, 'click')\n this.requestUpdate('trigger', old)\n }\n private _trigger: 'click' | 'hover' | 'manual' = 'click'\n\n @property({ type: Boolean, reflect: true }) portal = false\n @property({ attribute: false }) overlayContainer?: OverlayContainer\n\n private _showTimer?: ReturnType<typeof setTimeout>\n private _hideTimer?: ReturnType<typeof setTimeout>\n private readonly _userOpenChange = new UserChangeController()\n private _shouldOpenInstantly = true\n\n private _panelId = `wui-popover-panel-${++popoverIdCounter}`\n private readonly _panel = defineAnchoredPanel().make({\n getAnchor: () => this.shadowRoot?.querySelector<HTMLElement>('.popover-trigger') ?? null,\n getLocalPanel: () => this.shadowRoot?.querySelector<HTMLElement>('.popover-panel') ?? null,\n getPositioning: () => ({\n placement: this.placement,\n offset: this.offset,\n strategy: this.portal ? 'fixed' : 'absolute'\n }),\n isPortal: () => this.portal,\n createPortal: () => this._createPortal()\n })\n\n // 当前是否打开\n get isOpen(): boolean {\n return this.open\n }\n\n override connectedCallback() {\n super.connectedCallback()\n document.addEventListener('click', this._onClickOutside)\n document.addEventListener('keydown', this._onKeydown)\n this.addEventListener('focusout', this._onFocusOut)\n this._syncTriggerListeners()\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n document.removeEventListener('click', this._onClickOutside)\n document.removeEventListener('keydown', this._onKeydown)\n this.removeEventListener('focusout', this._onFocusOut)\n this.removeEventListener('pointerenter', this._onPointerEnter)\n this.removeEventListener('pointerleave', this._onPointerLeave)\n clearTimeout(this._showTimer)\n clearTimeout(this._hideTimer)\n this._panel.dispose()\n }\n\n override firstUpdated() {\n if (this.open) {\n requestAnimationFrame(() => this._openOverlay(this._shouldOpenInstantly))\n this._shouldOpenInstantly = true\n }\n }\n\n protected override updated(changed: Map<string, unknown>) {\n if (changed.has('portal') || changed.has('overlayContainer'))\n requestAnimationFrame(() => this._reconfigureOverlay())\n else if (changed.has('placement') || changed.has('offset'))\n requestAnimationFrame(() => this._panel.updatePosition())\n\n if (changed.has('open')) {\n if (this.open) {\n const isInstant = this._shouldOpenInstantly\n this._shouldOpenInstantly = true\n requestAnimationFrame(() => this._openOverlay(isInstant))\n if (this._userOpenChange.consume()) this._dispatchChange(true)\n this._focusPanel()\n } else {\n this._returnFocus()\n void this._closeOverlay()\n if (this._userOpenChange.consume()) this._dispatchChange(false)\n }\n }\n\n if (changed.has('trigger')) {\n this.removeEventListener('pointerenter', this._onPointerEnter)\n this.removeEventListener('pointerleave', this._onPointerLeave)\n clearTimeout(this._showTimer)\n clearTimeout(this._hideTimer)\n this._syncTriggerListeners()\n }\n }\n\n // 打开 popover\n show() {\n if (this.disabled || this.open) return\n this.open = true\n }\n\n // 关闭 popover\n close() {\n if (!this.open) return\n this.open = false\n }\n\n // 切换 popover\n toggle() {\n if (this.open) this.close()\n else this.show()\n }\n\n private _isInsideShadowRoot(e: MouseEvent): boolean {\n for (const node of e.composedPath()) {\n if (node instanceof Node && node.getRootNode() === this.shadowRoot) return true\n }\n return false\n }\n\n private _syncTriggerListeners() {\n if (this.trigger === 'hover') {\n this.addEventListener('pointerenter', this._onPointerEnter)\n this.addEventListener('pointerleave', this._onPointerLeave)\n }\n }\n\n private _openOverlay(isInstant = false) {\n this._panel.open(isInstant)\n }\n\n private _createPortal(): OverlayPortal {\n const portal = defineOverlayPortal().make({\n container: this.overlayContainer,\n target: this,\n style: `${glass}\\n${overlayMotion}\\n${style}`,\n className: 'popover-panel portal wui-glass wui-floating-panel'\n })\n portal.panel.id = this._panelId\n portal.panel.setAttribute('role', 'dialog')\n portal.panel.tabIndex = -1\n portal.panel.addEventListener('pointerenter', this._onPanelPointerEnter)\n portal.panel.addEventListener('pointerleave', this._onPanelPointerLeave)\n portal.moveContent(\n Array.from(this.childNodes).filter(node => !(node instanceof HTMLElement && node.slot === 'trigger'))\n )\n return portal\n }\n\n private async _closeOverlay() {\n await this._panel.close(() => this.open)\n }\n\n private _reconfigureOverlay() {\n this._panel.reconfigure(this.open)\n }\n\n private _dispatchChange(open: boolean) {\n this.dispatchEvent(\n new CustomEvent('open-change', {\n detail: { open },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private _focusPanel() {\n requestAnimationFrame(() => {\n const panel = this._panel.getPanel()\n const autofocus = panel?.querySelector<HTMLElement>('[autofocus]')\n if (autofocus && !autofocus.matches(':disabled, [disabled]')) autofocus.focus()\n })\n }\n\n private _returnFocus() {\n const panel = this._panel.getPanel()\n if (!panel?.matches(':focus-within')) return\n const trigger = this._queryTrigger()\n trigger?.focus()\n }\n\n private _queryTrigger(): 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 _onTriggerClick = (event: MouseEvent) => {\n if (this.disabled) return\n clearTimeout(this._showTimer)\n clearTimeout(this._hideTimer)\n if (this.trigger === 'hover') return\n if (!this.open) this._shouldOpenInstantly = event.detail === 0\n this._userOpenChange.mark()\n this.toggle()\n }\n\n private _onClickOutside = (e: MouseEvent) => {\n if (!this.open) return\n if (this.trigger === 'manual' || this.trigger === 'hover') return\n if (e.target instanceof Node && this.portal && this._panel.getPanel()?.contains(e.target)) return\n if (this._isInsideShadowRoot(e)) return\n this._userOpenChange.mark()\n this.open = false\n }\n\n private _onFocusOut = () => {\n if (this.trigger === 'manual' || this.trigger === 'hover') return\n\n requestAnimationFrame(() => {\n if (this.open && !this.matches(':focus-within') && !this._panel.getPanel()?.matches(':focus-within')) {\n this._userOpenChange.mark()\n this.open = false\n }\n })\n }\n\n private _onKeydown = (e: KeyboardEvent) => {\n if (!this.open) return\n if (this.trigger === 'manual') return\n if (e.key === 'Escape') {\n this._userOpenChange.mark()\n this.open = false\n e.preventDefault()\n }\n }\n\n private _onPointerEnter = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.disabled || this.trigger !== 'hover') return\n clearTimeout(this._hideTimer)\n this._showTimer = setTimeout(() => {\n this._shouldOpenInstantly = false\n if (this.open) return\n this._userOpenChange.mark()\n this.show()\n }, 100)\n }\n\n private _onPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.disabled || this.trigger !== 'hover') return\n clearTimeout(this._showTimer)\n this._hideTimer = setTimeout(() => {\n if (!this.open) return\n this._userOpenChange.mark()\n this.close()\n }, 100)\n }\n\n private _onPanelPointerEnter = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.trigger !== 'hover') return\n clearTimeout(this._hideTimer)\n }\n\n private _onPanelPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.trigger !== 'hover') return\n this._hideTimer = setTimeout(() => {\n if (!this.open) return\n this._userOpenChange.mark()\n this.close()\n }, 100)\n }\n\n override render() {\n return html`\n <div class=\"popover-anchor\">\n <div\n class=\"popover-trigger\"\n aria-expanded=${String(this.open)}\n aria-controls=${this._panelId}\n @click=${this._onTriggerClick}\n >\n <slot name=\"trigger\"></slot>\n </div>\n <div\n id=${this._panelId}\n class=\"popover-panel wui-glass wui-floating-panel\"\n hidden\n role=\"dialog\"\n tabindex=\"-1\"\n @pointerenter=${this._onPanelPointerEnter}\n @pointerleave=${this._onPanelPointerLeave}\n >\n <slot></slot>\n </div>\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-popover': WebUiPopover\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/popover/index.ts"],"sourcesContent":["import type { Placement } from '@floating-ui/dom'\nimport { html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport glass from '@/assets/glass.css?inline'\nimport overlayMotion from '@/assets/overlay-motion.css?inline'\nimport { UserChangeController } from '@/shared/events/user-change'\nimport { normalizeLiteral, normalizeNumber } from '@/shared/normalize'\nimport { defineAnchoredPanel } from '@/shared/overlay/anchored-panel'\nimport { defineOverlayPortal } from '@/shared/overlay/portal'\nimport type { OverlayContainer, OverlayPortal } from '@/shared/overlay/portal'\n\nimport style from './style.css?inline'\n\nconst ALLOWED_PLACEMENTS = [\n 'top',\n 'top-start',\n 'top-end',\n 'bottom',\n 'bottom-start',\n 'bottom-end',\n 'left',\n 'left-start',\n 'left-end',\n 'right',\n 'right-start',\n 'right-end'\n] as const\n\nconst ALLOWED_TRIGGERS = ['click', 'hover', 'manual'] as const\n\nlet popoverIdCounter = 0\n\n@customElement('web-ui-popover')\nexport class WebUiPopover extends LitElement {\n static override styles = [unsafeCSS(glass), unsafeCSS(overlayMotion), unsafeCSS(style)]\n\n @property({ type: Boolean, reflect: true }) open = false\n @property({ type: Boolean, reflect: true }) disabled = false\n\n @property({ type: String, reflect: true })\n get placement(): Placement {\n return this._placement\n }\n set placement(v: string) {\n const old = this._placement\n this._placement = normalizeLiteral(v, ALLOWED_PLACEMENTS, 'bottom')\n this.requestUpdate('placement', old)\n }\n private _placement: Placement = 'bottom'\n\n @property({ type: Number })\n get offset(): number {\n return this._offset\n }\n set offset(v: number) {\n const old = this._offset\n this._offset = normalizeNumber(v, 0, 100, 8)\n this.requestUpdate('offset', old)\n }\n private _offset = 8\n\n @property({ type: String, reflect: true })\n get trigger(): 'click' | 'hover' | 'manual' {\n return this._trigger\n }\n set trigger(v: string) {\n const old = this._trigger\n this._trigger = normalizeLiteral(v, ALLOWED_TRIGGERS, 'click')\n this.requestUpdate('trigger', old)\n }\n private _trigger: 'click' | 'hover' | 'manual' = 'click'\n\n @property({ type: Boolean, reflect: true }) portal = false\n @property({ attribute: false }) overlayContainer?: OverlayContainer\n\n private _showTimer?: ReturnType<typeof setTimeout>\n private _hideTimer?: ReturnType<typeof setTimeout>\n private readonly _userOpenChange = new UserChangeController()\n private _shouldOpenInstantly = true\n\n private _panelId = `wui-popover-panel-${++popoverIdCounter}`\n private readonly _panel = defineAnchoredPanel().make({\n getAnchor: () => this.shadowRoot?.querySelector<HTMLElement>('.popover-trigger') ?? null,\n getLocalPanel: () => this.shadowRoot?.querySelector<HTMLElement>('.popover-panel') ?? null,\n getPositioning: () => ({\n placement: this.placement,\n offset: this.offset,\n strategy: this.portal ? 'fixed' : 'absolute'\n }),\n isPortal: () => this.portal,\n createPortal: () => this._createPortal()\n })\n\n get isOpen(): boolean {\n return this.open\n }\n\n override connectedCallback() {\n super.connectedCallback()\n document.addEventListener('click', this._onClickOutside)\n document.addEventListener('keydown', this._onKeydown)\n this.addEventListener('focusout', this._onFocusOut)\n this._syncTriggerListeners()\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 if (this.open) {\n requestAnimationFrame(() => this._openOverlay(this._shouldOpenInstantly))\n this._shouldOpenInstantly = true\n }\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback()\n document.removeEventListener('click', this._onClickOutside)\n document.removeEventListener('keydown', this._onKeydown)\n this.removeEventListener('focusout', this._onFocusOut)\n this.removeEventListener('pointerenter', this._onPointerEnter)\n this.removeEventListener('pointerleave', this._onPointerLeave)\n clearTimeout(this._showTimer)\n clearTimeout(this._hideTimer)\n this._panel.dispose()\n }\n\n protected override updated(changed: Map<string, unknown>) {\n // ARIA 回写不依赖 open 分支,任何渲染后都保持与宿主状态同步。\n this._syncTriggerAria()\n\n if (changed.has('portal') || changed.has('overlayContainer'))\n requestAnimationFrame(() => this._reconfigureOverlay())\n else if (changed.has('placement') || changed.has('offset'))\n requestAnimationFrame(() => this._panel.updatePosition())\n\n if (changed.has('open')) {\n if (this.open) {\n const isInstant = this._shouldOpenInstantly\n this._shouldOpenInstantly = true\n requestAnimationFrame(() => this._openOverlay(isInstant))\n if (this._userOpenChange.consume()) this._dispatchChange(true)\n this._focusPanel()\n } else {\n this._returnFocus()\n void this._closeOverlay()\n if (this._userOpenChange.consume()) this._dispatchChange(false)\n }\n }\n\n if (changed.has('trigger')) {\n this.removeEventListener('pointerenter', this._onPointerEnter)\n this.removeEventListener('pointerleave', this._onPointerLeave)\n clearTimeout(this._showTimer)\n clearTimeout(this._hideTimer)\n this._syncTriggerListeners()\n }\n }\n\n show() {\n if (this.disabled || this.open) return\n this.open = true\n }\n\n close() {\n if (!this.open) return\n this.open = false\n }\n\n toggle() {\n if (this.open) this.close()\n else this.show()\n }\n\n private _isInsideShadowRoot(e: MouseEvent): boolean {\n for (const node of e.composedPath()) {\n if (node instanceof Node && node.getRootNode() === this.shadowRoot) return true\n }\n return false\n }\n\n private _syncTriggerListeners() {\n if (this.trigger === 'hover') {\n this.addEventListener('pointerenter', this._onPointerEnter)\n this.addEventListener('pointerleave', this._onPointerLeave)\n }\n }\n\n private _openOverlay(isInstant = false) {\n this._panel.open(isInstant)\n }\n\n private _createPortal(): OverlayPortal {\n const portal = defineOverlayPortal().make({\n container: this.overlayContainer,\n target: this,\n style: `${glass}\\n${overlayMotion}\\n${style}`,\n className: 'popover-panel portal wui-glass wui-floating-panel'\n })\n portal.panel.id = this._panelId\n portal.panel.setAttribute('role', 'dialog')\n portal.panel.tabIndex = -1\n portal.panel.addEventListener('pointerenter', this._onPanelPointerEnter)\n portal.panel.addEventListener('pointerleave', this._onPanelPointerLeave)\n portal.moveContent(\n Array.from(this.childNodes).filter(node => !(node instanceof HTMLElement && node.slot === 'trigger'))\n )\n return portal\n }\n\n private async _closeOverlay() {\n await this._panel.close(() => this.open)\n }\n\n private _reconfigureOverlay() {\n this._panel.reconfigure(this.open)\n }\n\n private _dispatchChange(open: boolean) {\n this.dispatchEvent(\n new CustomEvent('open-change', {\n detail: { open },\n bubbles: true,\n composed: true\n })\n )\n }\n\n /*\n * trigger 包装 div 不可聚焦,AT 读不到其 aria 状态:把 aria-expanded /\n * aria-controls 同步回写到 trigger slot 的首个 assigned element(Q8a)。\n * 包装 div 上的同名属性保留(additive,兼容既有查询)。\n */\n private _syncTriggerAria() {\n const trigger = this._queryTrigger()\n if (!trigger) return\n trigger.setAttribute('aria-expanded', String(this.open))\n trigger.setAttribute('aria-controls', this._panelId)\n }\n\n private _focusPanel() {\n requestAnimationFrame(() => {\n const panel = this._panel.getPanel()\n const autofocus = panel?.querySelector<HTMLElement>('[autofocus]')\n if (autofocus && !autofocus.matches(':disabled, [disabled]')) autofocus.focus()\n })\n }\n\n private _returnFocus() {\n const panel = this._panel.getPanel()\n if (!panel?.matches(':focus-within')) return\n const trigger = this._queryTrigger()\n trigger?.focus()\n }\n\n private _queryTrigger(): 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 _onTriggerClick = (event: MouseEvent) => {\n if (this.disabled) return\n clearTimeout(this._showTimer)\n clearTimeout(this._hideTimer)\n if (this.trigger === 'hover') return\n if (!this.open) this._shouldOpenInstantly = event.detail === 0\n this._userOpenChange.mark()\n this.toggle()\n }\n\n private _onClickOutside = (e: MouseEvent) => {\n if (!this.open) return\n if (this.trigger === 'manual' || this.trigger === 'hover') return\n if (e.target instanceof Node && this.portal && this._panel.getPanel()?.contains(e.target)) return\n if (this._isInsideShadowRoot(e)) return\n this._userOpenChange.mark()\n this.open = false\n }\n\n private _onFocusOut = () => {\n if (this.trigger === 'manual' || this.trigger === 'hover') return\n\n requestAnimationFrame(() => {\n if (this.open && !this.matches(':focus-within') && !this._panel.getPanel()?.matches(':focus-within')) {\n this._userOpenChange.mark()\n this.open = false\n }\n })\n }\n\n private _onKeydown = (e: KeyboardEvent) => {\n if (!this.open) return\n if (this.trigger === 'manual') return\n if (e.key === 'Escape') {\n this._userOpenChange.mark()\n this.open = false\n e.preventDefault()\n }\n }\n\n private _onPointerEnter = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.disabled || this.trigger !== 'hover') return\n clearTimeout(this._hideTimer)\n this._showTimer = setTimeout(() => {\n this._shouldOpenInstantly = false\n if (this.open) return\n this._userOpenChange.mark()\n this.show()\n }, 100)\n }\n\n private _onPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.disabled || this.trigger !== 'hover') return\n clearTimeout(this._showTimer)\n this._hideTimer = setTimeout(() => {\n if (!this.open) return\n this._userOpenChange.mark()\n this.close()\n }, 100)\n }\n\n private _onPanelPointerEnter = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.trigger !== 'hover') return\n clearTimeout(this._hideTimer)\n }\n\n private _onPanelPointerLeave = (e: PointerEvent) => {\n if (e.pointerType === 'touch') return\n if (this.trigger !== 'hover') return\n this._hideTimer = setTimeout(() => {\n if (!this.open) return\n this._userOpenChange.mark()\n this.close()\n }, 100)\n }\n\n override render() {\n return html`\n <div class=\"popover-anchor\">\n <div\n class=\"popover-trigger\"\n aria-expanded=${String(this.open)}\n aria-controls=${this._panelId}\n @click=${this._onTriggerClick}\n >\n <slot name=\"trigger\"></slot>\n </div>\n <div\n id=${this._panelId}\n class=\"popover-panel wui-glass wui-floating-panel\"\n hidden\n role=\"dialog\"\n tabindex=\"-1\"\n @pointerenter=${this._onPanelPointerEnter}\n @pointerleave=${this._onPanelPointerLeave}\n >\n <slot></slot>\n </div>\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-popover': WebUiPopover\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  //#region src/components/popover/style.css?inline
2
- var e = "*,:before,:after{box-sizing:border-box}:host{display:inline-flex}:host([disabled]){cursor:not-allowed}.popover-trigger{display:inline-flex}.popover-anchor{display:inline-flex;position:relative}.popover-panel{--wui-glass-shadow:var(--wui-shadow-pop,0 3px 9px #00000045);z-index:var(--wui-layer-local-overlay,1);box-sizing:border-box;width:max-content;max-width:min(90vw,400px);font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);background-color:var(--wui-color-surface-overlay,#f6f6f6e0);border-radius:20px;padding:8px 12px;line-height:1.5;position:absolute;top:-9999px;left:-9999px}.popover-panel:where([hidden]){display:none}.popover-panel:focus-visible{outline:2px solid var(--wui-focus-ring,#08f6);outline-offset:2px}.popover-panel.portal{z-index:var(--wui-layer-menu,100);position:fixed}:host([portal]) .popover-panel{display:none}";
2
+ var e = "*,:before,:after{box-sizing:border-box}:host{display:inline-flex}:host([disabled]){cursor:not-allowed}.popover-trigger{display:inline-flex}.popover-anchor{display:inline-flex;position:relative}.popover-panel{--wui-internal-glass-shadow:var(--wui-shadow-panel,0 3px 9px #00000045);--wui-glass-corner-radius:20px;z-index:var(--wui-layer-inline-overlay,1);box-sizing:border-box;width:max-content;max-width:min(90vw,400px);font-size:var(--wui-font-size,14px);color:var(--wui-color-text,#1b1b1b);background-color:var(--wui-color-surface-menu,#f6f6f6d1);border-radius:20px;padding:8px 12px;line-height:1.5;position:absolute;top:-9999px;left:-9999px}.popover-panel:where([hidden]){display:none}.popover-panel:focus-visible{outline:var(--wui-focus-ring-width,3px) solid var(--wui-color-focus-ring,#08f6);outline-offset:2px}.popover-panel.portal{z-index:var(--wui-layer-menu,100);position:fixed}:host([portal]) .popover-panel{display:none}";
3
3
  //#endregion
4
4
  export { e as default };
5
5