layplux 0.0.1

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 (201) hide show
  1. package/dist/cjs/components/center-view/index.cjs +41 -0
  2. package/dist/cjs/components/corner-glow/index.cjs +31 -0
  3. package/dist/cjs/components/dropdown/index.cjs +162 -0
  4. package/dist/cjs/components/icon/index.cjs +59 -0
  5. package/dist/cjs/components/index.cjs +25 -0
  6. package/dist/cjs/components/panel-view/index.cjs +166 -0
  7. package/dist/cjs/components/popup/index.cjs +280 -0
  8. package/dist/cjs/components/title/index.cjs +76 -0
  9. package/dist/cjs/components/tooltip/index.cjs +68 -0
  10. package/dist/cjs/components/widget/index.cjs +104 -0
  11. package/dist/cjs/index.cjs +40 -0
  12. package/dist/cjs/layout/glass-overlay.cjs +31 -0
  13. package/dist/cjs/layout/layered-manager.cjs +35 -0
  14. package/dist/cjs/layout/layplux.cjs +41 -0
  15. package/dist/cjs/layout/root-pane.cjs +46 -0
  16. package/dist/cjs/layout/skeleton/bottom-area.cjs +64 -0
  17. package/dist/cjs/layout/skeleton/bottom-left-area.cjs +42 -0
  18. package/dist/cjs/layout/skeleton/bottom-right-area.cjs +38 -0
  19. package/dist/cjs/layout/skeleton/center-area.cjs +467 -0
  20. package/dist/cjs/layout/skeleton/index.cjs +24 -0
  21. package/dist/cjs/layout/skeleton/left-bottom-area.cjs +42 -0
  22. package/dist/cjs/layout/skeleton/left-top-area.cjs +42 -0
  23. package/dist/cjs/layout/skeleton/right-bottom-area.cjs +38 -0
  24. package/dist/cjs/layout/skeleton/right-top-area.cjs +38 -0
  25. package/dist/cjs/layout/skeleton/skeleton.cjs +66 -0
  26. package/dist/cjs/layout/skeleton/top-area.cjs +64 -0
  27. package/dist/cjs/locales/en-US.cjs +34 -0
  28. package/dist/cjs/locales/index.cjs +39 -0
  29. package/dist/cjs/locales/zh-CN.cjs +34 -0
  30. package/dist/cjs/managers/area.cjs +32 -0
  31. package/dist/cjs/managers/index.cjs +20 -0
  32. package/dist/cjs/managers/pane.cjs +34 -0
  33. package/dist/cjs/managers/skeleton.cjs +208 -0
  34. package/dist/cjs/managers/theme.cjs +37 -0
  35. package/dist/cjs/managers/widget-container.cjs +96 -0
  36. package/dist/cjs/managers/widget.cjs +103 -0
  37. package/dist/cjs/types/config.cjs +16 -0
  38. package/dist/cjs/types/index.cjs +18 -0
  39. package/dist/cjs/types/locale.cjs +16 -0
  40. package/dist/cjs/utils/event-bus.cjs +154 -0
  41. package/dist/cjs/utils/focus-tracker.cjs +154 -0
  42. package/dist/cjs/utils/index.cjs +31 -0
  43. package/dist/cjs/utils/unique-id.cjs +27 -0
  44. package/dist/cjs/utils/vue.cjs +37 -0
  45. package/dist/esm/components/center-view/index.mjs +21 -0
  46. package/dist/esm/components/corner-glow/index.mjs +11 -0
  47. package/dist/esm/components/dropdown/index.mjs +146 -0
  48. package/dist/esm/components/icon/index.mjs +39 -0
  49. package/dist/esm/components/index.mjs +8 -0
  50. package/dist/esm/components/panel-view/index.mjs +152 -0
  51. package/dist/esm/components/popup/index.mjs +268 -0
  52. package/dist/esm/components/title/index.mjs +56 -0
  53. package/dist/esm/components/tooltip/index.mjs +48 -0
  54. package/dist/esm/components/widget/index.mjs +84 -0
  55. package/dist/esm/index.mjs +10 -0
  56. package/dist/esm/layout/glass-overlay.mjs +11 -0
  57. package/dist/esm/layout/layered-manager.mjs +15 -0
  58. package/dist/esm/layout/layplux.mjs +21 -0
  59. package/dist/esm/layout/root-pane.mjs +26 -0
  60. package/dist/esm/layout/skeleton/bottom-area.mjs +44 -0
  61. package/dist/esm/layout/skeleton/bottom-left-area.mjs +22 -0
  62. package/dist/esm/layout/skeleton/bottom-right-area.mjs +18 -0
  63. package/dist/esm/layout/skeleton/center-area.mjs +454 -0
  64. package/dist/esm/layout/skeleton/index.mjs +4 -0
  65. package/dist/esm/layout/skeleton/left-bottom-area.mjs +22 -0
  66. package/dist/esm/layout/skeleton/left-top-area.mjs +22 -0
  67. package/dist/esm/layout/skeleton/right-bottom-area.mjs +18 -0
  68. package/dist/esm/layout/skeleton/right-top-area.mjs +18 -0
  69. package/dist/esm/layout/skeleton/skeleton.mjs +46 -0
  70. package/dist/esm/layout/skeleton/top-area.mjs +44 -0
  71. package/dist/esm/locales/en-US.mjs +14 -0
  72. package/dist/esm/locales/index.mjs +19 -0
  73. package/dist/esm/locales/zh-CN.mjs +14 -0
  74. package/dist/esm/managers/area.mjs +12 -0
  75. package/dist/esm/managers/index.mjs +3 -0
  76. package/dist/esm/managers/pane.mjs +14 -0
  77. package/dist/esm/managers/skeleton.mjs +192 -0
  78. package/dist/esm/managers/theme.mjs +17 -0
  79. package/dist/esm/managers/widget-container.mjs +76 -0
  80. package/dist/esm/managers/widget.mjs +83 -0
  81. package/dist/esm/types/config.mjs +0 -0
  82. package/dist/esm/types/index.mjs +1 -0
  83. package/dist/esm/types/locale.mjs +0 -0
  84. package/dist/esm/utils/event-bus.mjs +124 -0
  85. package/dist/esm/utils/focus-tracker.mjs +135 -0
  86. package/dist/esm/utils/index.mjs +10 -0
  87. package/dist/esm/utils/unique-id.mjs +7 -0
  88. package/dist/esm/utils/vue.mjs +17 -0
  89. package/dist/style/base/_tokens-dark.scss +51 -0
  90. package/dist/style/base/_tokens.scss +56 -0
  91. package/dist/style/components/_bottom-area.scss +30 -0
  92. package/dist/style/components/_bottom-left-area.scss +8 -0
  93. package/dist/style/components/_bottom-right-area.scss +8 -0
  94. package/dist/style/components/_center-area.scss +162 -0
  95. package/dist/style/components/_corner-glow.scss +17 -0
  96. package/dist/style/components/_dropdown.scss +91 -0
  97. package/dist/style/components/_glass-pane.scss +6 -0
  98. package/dist/style/components/_layered-manager.scss +6 -0
  99. package/dist/style/components/_left-bottom-area.scss +8 -0
  100. package/dist/style/components/_left-top-area.scss +9 -0
  101. package/dist/style/components/_pane-view.scss +79 -0
  102. package/dist/style/components/_popup.scss +19 -0
  103. package/dist/style/components/_right-bottom-area.scss +8 -0
  104. package/dist/style/components/_right-top-area.scss +8 -0
  105. package/dist/style/components/_root-pane.scss +17 -0
  106. package/dist/style/components/_skeleton.scss +38 -0
  107. package/dist/style/components/_title-view.scss +176 -0
  108. package/dist/style/components/_tooltip.scss +65 -0
  109. package/dist/style/components/_top-area.scss +25 -0
  110. package/dist/style/index.css +768 -0
  111. package/dist/style/layplux.scss +21 -0
  112. package/dist/types/components/center-view/index.d.ts +16 -0
  113. package/dist/types/components/center-view/index.d.ts.map +1 -0
  114. package/dist/types/components/corner-glow/index.d.ts +2 -0
  115. package/dist/types/components/corner-glow/index.d.ts.map +1 -0
  116. package/dist/types/components/dropdown/index.d.ts +116 -0
  117. package/dist/types/components/dropdown/index.d.ts.map +1 -0
  118. package/dist/types/components/icon/index.d.ts +22 -0
  119. package/dist/types/components/icon/index.d.ts.map +1 -0
  120. package/dist/types/components/index.d.ts +9 -0
  121. package/dist/types/components/index.d.ts.map +1 -0
  122. package/dist/types/components/panel-view/index.d.ts +22 -0
  123. package/dist/types/components/panel-view/index.d.ts.map +1 -0
  124. package/dist/types/components/popup/index.d.ts +99 -0
  125. package/dist/types/components/popup/index.d.ts.map +1 -0
  126. package/dist/types/components/title/index.d.ts +57 -0
  127. package/dist/types/components/title/index.d.ts.map +1 -0
  128. package/dist/types/components/tooltip/index.d.ts +69 -0
  129. package/dist/types/components/tooltip/index.d.ts.map +1 -0
  130. package/dist/types/components/widget/index.d.ts +15 -0
  131. package/dist/types/components/widget/index.d.ts.map +1 -0
  132. package/dist/types/index.d.ts +10 -0
  133. package/dist/types/index.d.ts.map +1 -0
  134. package/dist/types/layout/glass-overlay.d.ts +2 -0
  135. package/dist/types/layout/glass-overlay.d.ts.map +1 -0
  136. package/dist/types/layout/layered-manager.d.ts +8 -0
  137. package/dist/types/layout/layered-manager.d.ts.map +1 -0
  138. package/dist/types/layout/layplux.d.ts +25 -0
  139. package/dist/types/layout/layplux.d.ts.map +1 -0
  140. package/dist/types/layout/root-pane.d.ts +8 -0
  141. package/dist/types/layout/root-pane.d.ts.map +1 -0
  142. package/dist/types/layout/skeleton/bottom-area.d.ts +9 -0
  143. package/dist/types/layout/skeleton/bottom-area.d.ts.map +1 -0
  144. package/dist/types/layout/skeleton/bottom-left-area.d.ts +9 -0
  145. package/dist/types/layout/skeleton/bottom-left-area.d.ts.map +1 -0
  146. package/dist/types/layout/skeleton/bottom-right-area.d.ts +9 -0
  147. package/dist/types/layout/skeleton/bottom-right-area.d.ts.map +1 -0
  148. package/dist/types/layout/skeleton/center-area.d.ts +11 -0
  149. package/dist/types/layout/skeleton/center-area.d.ts.map +1 -0
  150. package/dist/types/layout/skeleton/index.d.ts +2 -0
  151. package/dist/types/layout/skeleton/index.d.ts.map +1 -0
  152. package/dist/types/layout/skeleton/left-bottom-area.d.ts +9 -0
  153. package/dist/types/layout/skeleton/left-bottom-area.d.ts.map +1 -0
  154. package/dist/types/layout/skeleton/left-top-area.d.ts +9 -0
  155. package/dist/types/layout/skeleton/left-top-area.d.ts.map +1 -0
  156. package/dist/types/layout/skeleton/right-bottom-area.d.ts +9 -0
  157. package/dist/types/layout/skeleton/right-bottom-area.d.ts.map +1 -0
  158. package/dist/types/layout/skeleton/right-top-area.d.ts +9 -0
  159. package/dist/types/layout/skeleton/right-top-area.d.ts.map +1 -0
  160. package/dist/types/layout/skeleton/skeleton.d.ts +8 -0
  161. package/dist/types/layout/skeleton/skeleton.d.ts.map +1 -0
  162. package/dist/types/layout/skeleton/top-area.d.ts +9 -0
  163. package/dist/types/layout/skeleton/top-area.d.ts.map +1 -0
  164. package/dist/types/locales/en-US.d.ts +3 -0
  165. package/dist/types/locales/en-US.d.ts.map +1 -0
  166. package/dist/types/locales/index.d.ts +7 -0
  167. package/dist/types/locales/index.d.ts.map +1 -0
  168. package/dist/types/locales/zh-CN.d.ts +3 -0
  169. package/dist/types/locales/zh-CN.d.ts.map +1 -0
  170. package/dist/types/managers/area.d.ts +10 -0
  171. package/dist/types/managers/area.d.ts.map +1 -0
  172. package/dist/types/managers/index.d.ts +5 -0
  173. package/dist/types/managers/index.d.ts.map +1 -0
  174. package/dist/types/managers/pane.d.ts +8 -0
  175. package/dist/types/managers/pane.d.ts.map +1 -0
  176. package/dist/types/managers/skeleton.d.ts +38 -0
  177. package/dist/types/managers/skeleton.d.ts.map +1 -0
  178. package/dist/types/managers/theme.d.ts +2 -0
  179. package/dist/types/managers/theme.d.ts.map +1 -0
  180. package/dist/types/managers/widget-container.d.ts +21 -0
  181. package/dist/types/managers/widget-container.d.ts.map +1 -0
  182. package/dist/types/managers/widget.d.ts +26 -0
  183. package/dist/types/managers/widget.d.ts.map +1 -0
  184. package/dist/types/types/config.d.ts +54 -0
  185. package/dist/types/types/config.d.ts.map +1 -0
  186. package/dist/types/types/index.d.ts +2 -0
  187. package/dist/types/types/index.d.ts.map +1 -0
  188. package/dist/types/types/locale.d.ts +12 -0
  189. package/dist/types/types/locale.d.ts.map +1 -0
  190. package/dist/types/utils/event-bus.d.ts +18 -0
  191. package/dist/types/utils/event-bus.d.ts.map +1 -0
  192. package/dist/types/utils/focus-tracker.d.ts +37 -0
  193. package/dist/types/utils/focus-tracker.d.ts.map +1 -0
  194. package/dist/types/utils/index.d.ts +6 -0
  195. package/dist/types/utils/index.d.ts.map +1 -0
  196. package/dist/types/utils/unique-id.d.ts +2 -0
  197. package/dist/types/utils/unique-id.d.ts.map +1 -0
  198. package/dist/types/utils/vue.d.ts +5 -0
  199. package/dist/types/utils/vue.d.ts.map +1 -0
  200. package/dist/umd/index.js +4000 -0
  201. package/package.json +46 -0
@@ -0,0 +1,4000 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vue')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'vue'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Layplux = {}, global.Vue));
5
+ })(this, (function (exports, vue) { 'use strict';
6
+
7
+ const TopArea = vue.defineComponent({
8
+ name: 'TopArea',
9
+ props: {
10
+ area: Object
11
+ },
12
+ setup(props) {
13
+ return () => {
14
+ const {
15
+ area
16
+ } = props;
17
+ const left = [];
18
+ const center = [];
19
+ const right = [];
20
+ area?.container.items.value.slice().toSorted((a, b) => {
21
+ const index1 = a.config?.index || 0;
22
+ const index2 = b.config?.index || 0;
23
+ return index1 === index2 ? 0 : index1 > index2 ? 1 : -1;
24
+ }).forEach(item => {
25
+ const content = vue.createVNode("div", {
26
+ "key": `top-area-${item.name}`
27
+ }, [item.renderContent()]);
28
+ if (item.align === 'left') {
29
+ left.push(content);
30
+ } else if (item.align === 'center') {
31
+ center.push(content);
32
+ } else {
33
+ right.push(content);
34
+ }
35
+ });
36
+ return vue.createVNode("div", {
37
+ "class": "layplux-top-area"
38
+ }, [vue.createVNode("div", {
39
+ "class": "layplux-top-area__toolbar-left"
40
+ }, [...left]), vue.createVNode("div", {
41
+ "class": "layplux-top-area__toolbar-center"
42
+ }, [...center]), vue.createVNode("div", {
43
+ "class": "layplux-top-area__toolbar-right"
44
+ }, [...right])]);
45
+ };
46
+ }
47
+ });
48
+
49
+ const BottomArea = vue.defineComponent({
50
+ name: 'BottomArea',
51
+ props: {
52
+ area: Object
53
+ },
54
+ setup(props) {
55
+ return () => {
56
+ const {
57
+ area
58
+ } = props;
59
+ const left = [];
60
+ const center = [];
61
+ const right = [];
62
+ area?.container.items.value.slice().toSorted((a, b) => {
63
+ const index1 = a.config?.index || 0;
64
+ const index2 = b.config?.index || 0;
65
+ return index1 === index2 ? 0 : index1 > index2 ? 1 : -1;
66
+ }).forEach(item => {
67
+ const content = vue.createVNode("div", {
68
+ "key": `bottom-area-${item.name}`
69
+ }, [item.renderContent()]);
70
+ if (item.align === 'left') {
71
+ left.push(content);
72
+ } else if (item.align === 'center') {
73
+ center.push(content);
74
+ } else {
75
+ right.push(content);
76
+ }
77
+ });
78
+ return vue.createVNode("div", {
79
+ "class": "layplux-bottom-area"
80
+ }, [vue.createVNode("div", {
81
+ "class": "layplux-bottom-area__left"
82
+ }, [...left]), vue.createVNode("div", {
83
+ "class": "layplux-bottom-area__center"
84
+ }, [...center]), vue.createVNode("div", {
85
+ "class": "layplux-bottom-area__right"
86
+ }, [...right])]);
87
+ };
88
+ }
89
+ });
90
+
91
+ const LeftTopArea = vue.defineComponent({
92
+ name: 'LeftTopArea',
93
+ props: {
94
+ area: Object
95
+ },
96
+ setup(props) {
97
+ return () => {
98
+ const items = props.area?.container.items.value;
99
+ if (!items || items.length === 0) return null;
100
+ return vue.createVNode("div", {
101
+ "class": "layplux-left-top-area"
102
+ }, [items.slice().toSorted((a, b) => {
103
+ const i1 = a.config?.index ?? 0;
104
+ const i2 = b.config?.index ?? 0;
105
+ return i1 === i2 ? 0 : i1 > i2 ? 1 : -1;
106
+ }).map(widget => widget.renderTitle())]);
107
+ };
108
+ }
109
+ });
110
+
111
+ const LeftBottomArea = vue.defineComponent({
112
+ name: 'LeftBottomArea',
113
+ props: {
114
+ area: Object
115
+ },
116
+ setup(props) {
117
+ return () => {
118
+ const items = props.area?.container.items.value;
119
+ if (!items || items.length === 0) return null;
120
+ return vue.createVNode("div", {
121
+ "class": "layplux-left-bottom-area"
122
+ }, [items.slice().toSorted((a, b) => {
123
+ const i1 = a.config?.index ?? 0;
124
+ const i2 = b.config?.index ?? 0;
125
+ return i1 === i2 ? 0 : i1 > i2 ? 1 : -1;
126
+ }).map(widget => widget.renderTitle())]);
127
+ };
128
+ }
129
+ });
130
+
131
+ const BottomLeftArea = vue.defineComponent({
132
+ name: 'BottomLeftArea',
133
+ props: {
134
+ area: Object
135
+ },
136
+ setup(props) {
137
+ return () => {
138
+ const items = props.area?.container.items.value;
139
+ if (!items || items.length === 0) return null;
140
+ return vue.createVNode("div", {
141
+ "class": "layplux-bottom-left-area"
142
+ }, [items.slice().toSorted((a, b) => {
143
+ const i1 = a.config?.index ?? 0;
144
+ const i2 = b.config?.index ?? 0;
145
+ return i1 === i2 ? 0 : i1 > i2 ? 1 : -1;
146
+ }).map(widget => widget.renderTitle())]);
147
+ };
148
+ }
149
+ });
150
+
151
+ const RightTopArea = vue.defineComponent({
152
+ name: 'RightTopArea',
153
+ props: {
154
+ area: Object
155
+ },
156
+ setup(props) {
157
+ return () => {
158
+ const items = props.area?.container.items.value;
159
+ if (!items || items.length === 0) return null;
160
+ return vue.createVNode("div", {
161
+ "class": "layplux-right-top-area"
162
+ }, [items.slice().toSorted((a, b) => (a.config?.index ?? 0) - (b.config?.index ?? 0)).map(widget => widget.renderTitle())]);
163
+ };
164
+ }
165
+ });
166
+
167
+ const RightBottomArea = vue.defineComponent({
168
+ name: 'RightBottomArea',
169
+ props: {
170
+ area: Object
171
+ },
172
+ setup(props) {
173
+ return () => {
174
+ const items = props.area?.container.items.value;
175
+ if (!items || items.length === 0) return null;
176
+ return vue.createVNode("div", {
177
+ "class": "layplux-right-bottom-area"
178
+ }, [items.slice().toSorted((a, b) => (a.config?.index ?? 0) - (b.config?.index ?? 0)).map(widget => widget.renderTitle())]);
179
+ };
180
+ }
181
+ });
182
+
183
+ const BottomRightArea = vue.defineComponent({
184
+ name: 'BottomRightArea',
185
+ props: {
186
+ area: Object
187
+ },
188
+ setup(props) {
189
+ return () => {
190
+ const items = props.area?.container.items.value;
191
+ if (!items || items.length === 0) return null;
192
+ return vue.createVNode("div", {
193
+ "class": "layplux-bottom-right-area"
194
+ }, [items.slice().toSorted((a, b) => (a.config?.index ?? 0) - (b.config?.index ?? 0)).map(widget => widget.renderTitle())]);
195
+ };
196
+ }
197
+ });
198
+
199
+ const CornerGlow = vue.defineComponent({
200
+ name: 'CornerGlow',
201
+ setup() {
202
+ return () => vue.createVNode("div", {
203
+ "class": "corner-glow"
204
+ }, null);
205
+ }
206
+ });
207
+
208
+ function computePosition(triggerRect, popupW, popupH, placement, offsetX, offsetY) {
209
+ const vw = window.innerWidth;
210
+ const vh = window.innerHeight;
211
+ const PADDING = 8;
212
+ let top = 0;
213
+ let left = 0;
214
+ const [main, align] = placement.split('-');
215
+
216
+ // Vertical placements
217
+ if (main === 'bottom') {
218
+ top = triggerRect.bottom + offsetY;
219
+ if (align === 'start') left = triggerRect.left + offsetX;else if (align === 'end') left = triggerRect.right - popupW + offsetX;else left = triggerRect.left + triggerRect.width / 2 - popupW / 2 + offsetX;
220
+
221
+ // Flip to top if not enough space
222
+ if (top + popupH > vh - PADDING) {
223
+ top = triggerRect.top - popupH - offsetY;
224
+ placement = align ? `top-${align}` : 'top';
225
+ }
226
+ } else if (main === 'top') {
227
+ top = triggerRect.top - popupH - offsetY;
228
+ if (align === 'start') left = triggerRect.left + offsetX;else if (align === 'end') left = triggerRect.right - popupW + offsetX;else left = triggerRect.left + triggerRect.width / 2 - popupW / 2 + offsetX;
229
+
230
+ // Flip to bottom if not enough space
231
+ if (top < PADDING) {
232
+ top = triggerRect.bottom + offsetY;
233
+ placement = align ? `bottom-${align}` : 'bottom';
234
+ }
235
+ }
236
+ // Horizontal placements
237
+ else if (main === 'right') {
238
+ left = triggerRect.right + offsetX;
239
+ if (align === 'start') top = triggerRect.top + offsetY;else if (align === 'end') top = triggerRect.bottom - popupH + offsetY;else top = triggerRect.top + triggerRect.height / 2 - popupH / 2 + offsetY;
240
+ if (left + popupW > vw - PADDING) {
241
+ left = triggerRect.left - popupW - offsetX;
242
+ placement = align ? `left-${align}` : 'left';
243
+ }
244
+ } else if (main === 'left') {
245
+ left = triggerRect.left - popupW - offsetX;
246
+ if (align === 'start') top = triggerRect.top + offsetY;else if (align === 'end') top = triggerRect.bottom - popupH + offsetY;else top = triggerRect.top + triggerRect.height / 2 - popupH / 2 + offsetY;
247
+ if (left < PADDING) {
248
+ left = triggerRect.right + offsetX;
249
+ placement = align ? `right-${align}` : 'right';
250
+ }
251
+ }
252
+
253
+ // Clamp to viewport
254
+ top = Math.max(PADDING, Math.min(top, vh - popupH - PADDING));
255
+ left = Math.max(PADDING, Math.min(left, vw - popupW - PADDING));
256
+ return {
257
+ position: {
258
+ top,
259
+ left
260
+ },
261
+ placement
262
+ };
263
+ }
264
+ const Popup = vue.defineComponent({
265
+ name: 'LaypluxPopup',
266
+ props: {
267
+ visible: Boolean,
268
+ trigger: {
269
+ type: String,
270
+ default: 'hover'
271
+ },
272
+ placement: {
273
+ type: String,
274
+ default: 'bottom'
275
+ },
276
+ offset: {
277
+ type: Object,
278
+ default: () => ({
279
+ y: 4
280
+ })
281
+ },
282
+ mouseEnterDelay: {
283
+ type: Number,
284
+ default: 100
285
+ },
286
+ mouseLeaveDelay: {
287
+ type: Number,
288
+ default: 100
289
+ },
290
+ disabled: {
291
+ type: Boolean,
292
+ default: false
293
+ },
294
+ destroyOnClose: {
295
+ type: Boolean,
296
+ default: true
297
+ },
298
+ getContainer: {
299
+ type: Function,
300
+ default: () => document.body
301
+ }
302
+ },
303
+ emits: ['update:visible'],
304
+ setup(props, {
305
+ emit,
306
+ slots
307
+ }) {
308
+ const triggerRef = vue.ref();
309
+ const popupRef = vue.ref();
310
+ const position = vue.ref({
311
+ top: 0,
312
+ left: 0
313
+ });
314
+ const currentPlacement = vue.ref(props.placement);
315
+ // Whether the popup DOM should exist
316
+ const mounted = vue.ref(false);
317
+ // Whether the popup is in its visible animation state
318
+ const animatingIn = vue.ref(false);
319
+ let enterTimer = null;
320
+ let leaveTimer = null;
321
+ let leaveAnimationTimer = null;
322
+ const clearTimers = () => {
323
+ if (enterTimer) {
324
+ clearTimeout(enterTimer);
325
+ enterTimer = null;
326
+ }
327
+ if (leaveTimer) {
328
+ clearTimeout(leaveTimer);
329
+ leaveTimer = null;
330
+ }
331
+ if (leaveAnimationTimer) {
332
+ clearTimeout(leaveAnimationTimer);
333
+ leaveAnimationTimer = null;
334
+ }
335
+ };
336
+ const updatePosition = () => {
337
+ if (!triggerRef.value || !popupRef.value) return;
338
+ const triggerRect = triggerRef.value.getBoundingClientRect();
339
+ const popupRect = popupRef.value.getBoundingClientRect();
340
+ const {
341
+ x: ox = 0,
342
+ y: oy = 0
343
+ } = props.offset;
344
+ const result = computePosition(triggerRect, popupRect.width, popupRect.height, props.placement, ox, oy);
345
+ position.value = result.position;
346
+ currentPlacement.value = result.placement;
347
+ };
348
+ const show = () => {
349
+ if (props.disabled) return;
350
+ clearTimers();
351
+ enterTimer = setTimeout(() => {
352
+ mounted.value = true;
353
+ emit('update:visible', true);
354
+ void vue.nextTick(() => {
355
+ updatePosition();
356
+ // Trigger enter animation
357
+ requestAnimationFrame(() => {
358
+ animatingIn.value = true;
359
+ });
360
+ });
361
+ }, props.mouseEnterDelay);
362
+ };
363
+ const hide = (immediate = false) => {
364
+ clearTimers();
365
+ const delay = immediate ? 0 : props.mouseLeaveDelay;
366
+ leaveTimer = setTimeout(() => {
367
+ animatingIn.value = false;
368
+
369
+ // Wait for CSS transition to finish before removing DOM
370
+ leaveAnimationTimer = setTimeout(() => {
371
+ mounted.value = false;
372
+ emit('update:visible', false);
373
+ }, 200); // Match CSS transition duration
374
+ }, delay);
375
+ };
376
+ const toggle = () => {
377
+ if (mounted.value && animatingIn.value) {
378
+ hide(true);
379
+ } else {
380
+ clearTimers();
381
+ show();
382
+ }
383
+ };
384
+
385
+ // Sync external visible changes
386
+ vue.watch(() => props.visible, v => {
387
+ if (v && !mounted.value) show();else if (!v && mounted.value) hide(true);
388
+ });
389
+
390
+ // Sync external placement changes
391
+ vue.watch(() => props.placement, p => {
392
+ currentPlacement.value = p;
393
+ });
394
+ const onResize = () => {
395
+ if (mounted.value && animatingIn.value) updatePosition();
396
+ };
397
+ vue.onMounted(() => {
398
+ window.addEventListener('resize', onResize);
399
+ window.addEventListener('scroll', onResize, true);
400
+ document.addEventListener('mousedown', onClickOutside, true);
401
+ document.addEventListener('keydown', onEsc);
402
+ });
403
+ vue.onUnmounted(() => {
404
+ clearTimers();
405
+ window.removeEventListener('resize', onResize);
406
+ window.removeEventListener('scroll', onResize, true);
407
+ document.removeEventListener('mousedown', onClickOutside, true);
408
+ document.removeEventListener('keydown', onEsc);
409
+ });
410
+
411
+ // Click outside
412
+ const onClickOutside = e => {
413
+ if (!mounted.value) return;
414
+ const target = e.target;
415
+ const trigger = triggerRef.value;
416
+ const popup = popupRef.value;
417
+ if (trigger && trigger.contains(target)) return;
418
+ if (popup && popup.contains(target)) return;
419
+ if (props.trigger === 'click' || props.trigger === 'contextmenu') {
420
+ hide(true);
421
+ }
422
+ };
423
+
424
+ // ESC key
425
+ const onEsc = e => {
426
+ if (e.key === 'Escape' && mounted.value) {
427
+ hide(true);
428
+ }
429
+ };
430
+
431
+ // Trigger event handlers
432
+ const onTriggerMouseEnter = () => {
433
+ if (props.trigger === 'hover') show();
434
+ };
435
+ const onTriggerMouseLeave = () => {
436
+ if (props.trigger === 'hover') hide();
437
+ };
438
+ const onTriggerClick = e => {
439
+ if (props.trigger === 'click') {
440
+ e.stopPropagation();
441
+ toggle();
442
+ }
443
+ };
444
+ const onTriggerFocus = () => {
445
+ if (props.trigger === 'focus') show();
446
+ };
447
+ const onTriggerBlur = () => {
448
+ if (props.trigger === 'focus') hide(true);
449
+ };
450
+ const onTriggerContextmenu = e => {
451
+ if (props.trigger === 'contextmenu') {
452
+ e.preventDefault();
453
+ show();
454
+ }
455
+ };
456
+
457
+ // Popup hover (for safe triangle)
458
+ const onPopupMouseEnter = () => {
459
+ if (leaveTimer) {
460
+ clearTimeout(leaveTimer);
461
+ leaveTimer = null;
462
+ }
463
+ };
464
+ const onPopupMouseLeave = () => {
465
+ if (props.trigger === 'hover') hide();
466
+ };
467
+ return () => {
468
+ const container = props.getContainer();
469
+ return vue.createVNode(vue.Fragment, null, [vue.createVNode("span", {
470
+ "ref": triggerRef,
471
+ "class": "layplux-popup-trigger",
472
+ "onMouseenter": onTriggerMouseEnter,
473
+ "onMouseleave": onTriggerMouseLeave,
474
+ "onClick": onTriggerClick,
475
+ "onFocus": onTriggerFocus,
476
+ "onBlur": onTriggerBlur,
477
+ "onContextmenu": onTriggerContextmenu
478
+ }, [slots.default?.()]), (mounted.value || !props.destroyOnClose) && vue.createVNode(vue.Teleport, {
479
+ "to": container
480
+ }, {
481
+ default: () => [vue.createVNode("div", {
482
+ "ref": popupRef,
483
+ "class": ['layplux-portal', 'layplux-popup', currentPlacement.value, animatingIn.value && 'layplux-popup--visible'],
484
+ "style": {
485
+ position: 'fixed',
486
+ top: `${position.value.top}px`,
487
+ left: `${position.value.left}px`,
488
+ zIndex: 'var(--layplux-popup-z-index, 2000)'
489
+ },
490
+ "onMouseenter": onPopupMouseEnter,
491
+ "onMouseleave": onPopupMouseLeave
492
+ }, [slots.content?.()])]
493
+ })]);
494
+ };
495
+ }
496
+ });
497
+
498
+ const iconProps = {
499
+ size: {
500
+ type: [Number, String],
501
+ default: 16
502
+ }
503
+ };
504
+ function createIcon(d, viewBox = '0 0 16 16') {
505
+ return vue.defineComponent({
506
+ name: 'LaypluxIcon',
507
+ props: iconProps,
508
+ setup(props) {
509
+ return () => vue.createVNode("svg", {
510
+ "xmlns": "http://www.w3.org/2000/svg",
511
+ "viewBox": viewBox,
512
+ "width": props.size,
513
+ "height": props.size,
514
+ "fill": "currentColor",
515
+ "style": {
516
+ flexShrink: 0
517
+ }
518
+ }, [vue.createVNode("path", {
519
+ "d": d
520
+ }, null)]);
521
+ }
522
+ });
523
+ }
524
+ const MoreIcon = createIcon('M16 12a2 2 0 0 1 2-2a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2m-6 0a2 2 0 0 1 2-2a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2m-6 0a2 2 0 0 1 2-2a2 2 0 0 1 2 2a2 2 0 0 1-2 2a2 2 0 0 1-2-2', '0 0 24 24');
525
+ const MinimizeIcon = createIcon('M19 13H5v-2h14z', '0 0 24 24');
526
+ const ChevronRightIcon = createIcon('M8.59 16.58L13.17 12L8.59 7.41L10 6l6 6l-6 6z', '0 0 24 24');
527
+
528
+ const DROPDOWN_CLOSE = Symbol('dropdown-close');
529
+ const DROPDOWN_ON_CLICK = Symbol('dropdown-on-click');
530
+ const Dropdown = vue.defineComponent({
531
+ name: 'LaypluxDropdown',
532
+ props: {
533
+ visible: Boolean,
534
+ trigger: {
535
+ type: String,
536
+ default: 'click'
537
+ },
538
+ placement: {
539
+ type: String,
540
+ default: 'bottom-start'
541
+ },
542
+ disabled: {
543
+ type: Boolean,
544
+ default: false
545
+ },
546
+ destroyOnClose: {
547
+ type: Boolean,
548
+ default: true
549
+ },
550
+ onClick: Function,
551
+ getContainer: {
552
+ type: Function
553
+ }
554
+ },
555
+ emits: ['update:visible'],
556
+ setup(props, {
557
+ emit,
558
+ slots
559
+ }) {
560
+ const closeDropdown = () => {
561
+ emit('update:visible', false);
562
+ };
563
+ vue.provide(DROPDOWN_CLOSE, closeDropdown);
564
+ vue.provide(DROPDOWN_ON_CLICK, props.onClick);
565
+ return () => vue.createVNode(Popup, {
566
+ "visible": props.visible,
567
+ "trigger": props.trigger,
568
+ "placement": props.placement,
569
+ "disabled": props.disabled,
570
+ "destroyOnClose": props.destroyOnClose,
571
+ "getContainer": props.getContainer,
572
+ "onUpdate:visible": v => emit('update:visible', v)
573
+ }, {
574
+ default: () => slots.default?.(),
575
+ content: () => vue.createVNode("div", {
576
+ "class": "layplux-dropdown"
577
+ }, [slots.overlay?.()])
578
+ });
579
+ }
580
+ });
581
+ const DropdownMenu = vue.defineComponent({
582
+ name: 'LaypluxDropdownMenu',
583
+ setup(_props, {
584
+ slots
585
+ }) {
586
+ return () => vue.createVNode("div", {
587
+ "class": "layplux-dropdown-menu"
588
+ }, [slots.default?.()]);
589
+ }
590
+ });
591
+ const DropdownItem = vue.defineComponent({
592
+ name: 'LaypluxDropdownItem',
593
+ props: {
594
+ eventKey: {
595
+ type: String,
596
+ required: true
597
+ },
598
+ disabled: {
599
+ type: Boolean,
600
+ default: false
601
+ },
602
+ danger: {
603
+ type: Boolean,
604
+ default: false
605
+ }
606
+ },
607
+ setup(props, {
608
+ slots
609
+ }) {
610
+ const closeDropdown = vue.inject(DROPDOWN_CLOSE);
611
+ const onItemClick = vue.inject(DROPDOWN_ON_CLICK);
612
+ const handleClick = () => {
613
+ if (props.disabled) return;
614
+ onItemClick?.(props.eventKey);
615
+ closeDropdown?.();
616
+ };
617
+ return () => vue.createVNode("div", {
618
+ "class": ['layplux-dropdown-menu__item', props.disabled && 'layplux-dropdown-menu__item--disabled', props.danger && 'layplux-dropdown-menu__item--danger'],
619
+ "onClick": handleClick
620
+ }, [slots.default?.()]);
621
+ }
622
+ });
623
+ const DropdownDivider = vue.defineComponent({
624
+ name: 'LaypluxDropdownDivider',
625
+ setup() {
626
+ return () => vue.createVNode("div", {
627
+ "class": "layplux-dropdown-menu__divider"
628
+ }, null);
629
+ }
630
+ });
631
+ const DropdownSubmenu = vue.defineComponent({
632
+ name: 'LaypluxDropdownSubmenu',
633
+ props: {
634
+ title: {
635
+ type: String
636
+ },
637
+ icon: Object,
638
+ disabled: {
639
+ type: Boolean,
640
+ default: false
641
+ },
642
+ getContainer: {
643
+ type: Function
644
+ }
645
+ },
646
+ setup(props, {
647
+ slots
648
+ }) {
649
+ const closeParent = vue.inject(DROPDOWN_CLOSE);
650
+ const onParentClick = vue.inject(DROPDOWN_ON_CLICK);
651
+ if (closeParent) {
652
+ vue.provide(DROPDOWN_CLOSE, closeParent);
653
+ }
654
+ const handleClick = key => {
655
+ onParentClick?.(key);
656
+ closeParent?.();
657
+ };
658
+ vue.provide(DROPDOWN_ON_CLICK, handleClick);
659
+ return () => vue.createVNode(Popup, {
660
+ "trigger": "hover",
661
+ "placement": "right-start",
662
+ "offset": {
663
+ x: 4,
664
+ y: 0
665
+ },
666
+ "mouseEnterDelay": 150,
667
+ "mouseLeaveDelay": 100,
668
+ "destroyOnClose": true,
669
+ "disabled": props.disabled,
670
+ "getContainer": props.getContainer
671
+ }, {
672
+ default: () => vue.createVNode("div", {
673
+ "class": ['layplux-dropdown-menu__item', 'layplux-dropdown-menu__item--submenu', props.disabled && 'layplux-dropdown-menu__item--disabled']
674
+ }, [props.icon, vue.createVNode("span", null, [props.title]), vue.createVNode(ChevronRightIcon, {
675
+ "size": 12,
676
+ "class": "layplux-dropdown-menu__submenu-arrow"
677
+ }, null)]),
678
+ content: () => vue.createVNode("div", {
679
+ "class": "layplux-dropdown"
680
+ }, [slots.default?.()])
681
+ });
682
+ }
683
+ });
684
+
685
+ function createContent(content, extraProps = {}) {
686
+ if (!content) return null;
687
+
688
+ // 1. 是 VNode -> 克隆并合并属性
689
+ if (vue.isVNode(content)) {
690
+ return vue.cloneVNode(content, extraProps);
691
+ }
692
+
693
+ // 2. 是字符串
694
+ if (typeof content === 'string') {
695
+ // 如果需要附加属性,则包裹在 span 中
696
+ if (Object.keys(extraProps).length > 0) {
697
+ return vue.h(content, extraProps, content);
698
+ }
699
+ // 否则创建纯文本节点,避免多余 DOM
700
+ return vue.h(vue.Text, null, content);
701
+ }
702
+
703
+ // 3. 否则视为组件(对象或函数)
704
+ return vue.h(content, extraProps);
705
+ }
706
+
707
+ let guid = Date.now();
708
+ function uniqueId(prefix = '') {
709
+ return `${prefix}${(guid++).toString(36).toLowerCase()}`;
710
+ }
711
+
712
+ /**
713
+ * 焦点追踪器 — 维护一个焦点栈,管理 Popup/Dropdown 等弹出层的点击外部关闭、ESC 关闭等行为。
714
+ *
715
+ * 核心概念:
716
+ * - actives 是一个栈(active/unshift),栈顶(first)是当前聚焦的 Focusable
717
+ * - modal Focusable 打开时会阻止非 modal 的上层焦点失焦
718
+ * - mount() 在 document 上监听 click,点击栈顶 Focusable 范围外时触发 blur
719
+ */
720
+ class FocusTracker {
721
+ /** 焦点栈,栈顶为当前聚焦项 */
722
+ actives = [];
723
+
724
+ /** modal 弹层注册表,用于检查是否有 modal 正在打开 */
725
+ modals = [];
726
+
727
+ /** 当前焦点栈顶 */
728
+ get first() {
729
+ return this.actives[0];
730
+ }
731
+
732
+ /** 注册一个 modal 弹层,用于 execSave 等时判断是否跳过 */
733
+ addModal(checkDown, checkOpen) {
734
+ this.modals.push({
735
+ checkDown,
736
+ checkOpen
737
+ });
738
+ }
739
+
740
+ /** 是否有 modal 弹层正在打开 */
741
+ checkModalOpen() {
742
+ return this.modals.some(item => item.checkOpen());
743
+ }
744
+
745
+ /** 触发保存操作,有 modal 时跳过 */
746
+ execSave() {
747
+ if (this.checkModalOpen()) return;
748
+ if (this.first) this.first.internalTriggerSave();
749
+ }
750
+
751
+ /** 触发 ESC — 挂起栈顶并调用其 onEsc */
752
+ execEsc() {
753
+ const {
754
+ first
755
+ } = this;
756
+ if (first) {
757
+ this.internalSuspenseItem(first);
758
+ first.internalTriggerEsc();
759
+ }
760
+ }
761
+
762
+ /**
763
+ * 挂载全局点击监听
764
+ * 点击 document 时,如果点击目标不在 first 的 range 内,则挂起 first 并触发 blur
765
+ * @returns 卸载函数
766
+ */
767
+ mount(win) {
768
+ const checkDown = e => {
769
+ const {
770
+ first
771
+ } = this;
772
+ if (first && !first.internalCheckInRange(e)) {
773
+ this.internalSuspenseItem(first);
774
+ first.internalTriggerBlur();
775
+ }
776
+ };
777
+ win.document.addEventListener('click', checkDown, true);
778
+ return () => win.document.removeEventListener('click', checkDown, true);
779
+ }
780
+
781
+ /** 创建一个 Focusable 实例并绑定到当前 tracker */
782
+ create(config) {
783
+ return new Focusable(this, config);
784
+ }
785
+
786
+ /**
787
+ * 激活一个 Focusable — 将其推到栈顶
788
+ * 如果栈顶已有其他 Focusable 且新项不是 modal,则先触发旧栈顶的 blur
789
+ */
790
+ internalActiveItem(item) {
791
+ const first = this.actives[0];
792
+ if (first === item) return;
793
+ const i = this.actives.indexOf(item);
794
+ if (i > -1) this.actives.splice(i, 1);
795
+ this.actives.unshift(item);
796
+ if (!item.isModal && first) first.internalTriggerBlur();
797
+ item.internalTriggerActive();
798
+ }
799
+
800
+ /**
801
+ * 挂起一个 Focusable — 将其从栈中移除
802
+ * 移除后如果还有剩余项,激活新的栈顶
803
+ */
804
+ internalSuspenseItem(item) {
805
+ const i = this.actives.indexOf(item);
806
+ if (i > -1) {
807
+ this.actives.splice(i, 1);
808
+ this.first?.internalTriggerActive();
809
+ }
810
+ }
811
+ }
812
+
813
+ /** Focusable 的创建配置 */
814
+
815
+ /**
816
+ * 可聚焦项 — 代表一个弹出层(Popup/Dropdown 等)的焦点状态
817
+ *
818
+ * 使用方式:
819
+ * 1. tracker.create(config) 创建 Focusable
820
+ * 2. 弹出层打开时调用 focusable.active() 推入栈顶
821
+ * 3. 弹出层关闭时调用 focusable.suspense() 或 purge() 移出栈
822
+ * 4. 需要在组件挂载后调用 setRange() 注入真实 DOM
823
+ */
824
+ class Focusable {
825
+ constructor(tracker, config) {
826
+ this.tracker = tracker;
827
+ this.config = config;
828
+ this.isModal = config.modal ?? false;
829
+ }
830
+
831
+ /** 激活当前 Focusable,推入焦点栈顶 */
832
+ active() {
833
+ this.tracker.internalActiveItem(this);
834
+ }
835
+
836
+ /** 挂起当前 Focusable,从焦点栈移除 */
837
+ suspense() {
838
+ this.tracker.internalSuspenseItem(this);
839
+ }
840
+
841
+ /** 销毁当前 Focusable(同 suspense,语义化别名) */
842
+ purge() {
843
+ this.tracker.internalSuspenseItem(this);
844
+ }
845
+
846
+ /** 挂载后把真实 DOM 注入,使 range 的 contains 判断生效 */
847
+ setRange(range) {
848
+ this.config.range = range;
849
+ }
850
+
851
+ /** 检查点击事件是否在 range 范围内 */
852
+ internalCheckInRange(e) {
853
+ const {
854
+ range
855
+ } = this.config;
856
+ if (!range) return false;
857
+ if (typeof range === 'function') return range(e);
858
+ return range.contains(e.target);
859
+ }
860
+
861
+ /** 触发失焦回调 */
862
+ internalTriggerBlur() {
863
+ this.config.onBlur?.();
864
+ }
865
+
866
+ /** 触发保存回调,返回 true 表示已处理 */
867
+ internalTriggerSave() {
868
+ if (this.config.onSave) {
869
+ this.config.onSave();
870
+ return true;
871
+ }
872
+ return false;
873
+ }
874
+
875
+ /** 触发 ESC 回调 */
876
+ internalTriggerEsc() {
877
+ this.config.onEsc?.();
878
+ }
879
+
880
+ /** 触发激活回调 */
881
+ internalTriggerActive() {
882
+ this.config.onActive?.();
883
+ }
884
+ }
885
+
886
+ function getDefaultExportFromCjs (x) {
887
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
888
+ }
889
+
890
+ var eventemitter2 = {exports: {}};
891
+
892
+ /*!
893
+ * EventEmitter2
894
+ * https://github.com/hij1nx/EventEmitter2
895
+ *
896
+ * Copyright (c) 2013 hij1nx
897
+ * Licensed under the MIT license.
898
+ */
899
+
900
+ var hasRequiredEventemitter2;
901
+
902
+ function requireEventemitter2 () {
903
+ if (hasRequiredEventemitter2) return eventemitter2.exports;
904
+ hasRequiredEventemitter2 = 1;
905
+ (function (module, exports) {
906
+ !function(undefined$1) {
907
+ var hasOwnProperty= Object.hasOwnProperty;
908
+ var isArray = Array.isArray ? Array.isArray : function _isArray(obj) {
909
+ return Object.prototype.toString.call(obj) === "[object Array]";
910
+ };
911
+ var defaultMaxListeners = 10;
912
+ var nextTickSupported= typeof process=='object' && typeof process.nextTick=='function';
913
+ var symbolsSupported= typeof Symbol==='function';
914
+ var reflectSupported= typeof Reflect === 'object';
915
+ var setImmediateSupported= typeof setImmediate === 'function';
916
+ var _setImmediate= setImmediateSupported ? setImmediate : setTimeout;
917
+ var ownKeys= symbolsSupported? (reflectSupported && typeof Reflect.ownKeys==='function'? Reflect.ownKeys : function(obj){
918
+ var arr= Object.getOwnPropertyNames(obj);
919
+ arr.push.apply(arr, Object.getOwnPropertySymbols(obj));
920
+ return arr;
921
+ }) : Object.keys;
922
+
923
+ function init() {
924
+ this._events = {};
925
+ if (this._conf) {
926
+ configure.call(this, this._conf);
927
+ }
928
+ }
929
+
930
+ function configure(conf) {
931
+ if (conf) {
932
+ this._conf = conf;
933
+
934
+ conf.delimiter && (this.delimiter = conf.delimiter);
935
+
936
+ if(conf.maxListeners!==undefined$1){
937
+ this._maxListeners= conf.maxListeners;
938
+ }
939
+
940
+ conf.wildcard && (this.wildcard = conf.wildcard);
941
+ conf.newListener && (this._newListener = conf.newListener);
942
+ conf.removeListener && (this._removeListener = conf.removeListener);
943
+ conf.verboseMemoryLeak && (this.verboseMemoryLeak = conf.verboseMemoryLeak);
944
+ conf.ignoreErrors && (this.ignoreErrors = conf.ignoreErrors);
945
+
946
+ if (this.wildcard) {
947
+ this.listenerTree = {};
948
+ }
949
+ }
950
+ }
951
+
952
+ function logPossibleMemoryLeak(count, eventName) {
953
+ var errorMsg = '(node) warning: possible EventEmitter memory ' +
954
+ 'leak detected. ' + count + ' listeners added. ' +
955
+ 'Use emitter.setMaxListeners() to increase limit.';
956
+
957
+ if(this.verboseMemoryLeak){
958
+ errorMsg += ' Event name: ' + eventName + '.';
959
+ }
960
+
961
+ if(typeof process !== 'undefined' && process.emitWarning){
962
+ var e = new Error(errorMsg);
963
+ e.name = 'MaxListenersExceededWarning';
964
+ e.emitter = this;
965
+ e.count = count;
966
+ process.emitWarning(e);
967
+ } else {
968
+ console.error(errorMsg);
969
+
970
+ if (console.trace){
971
+ console.trace();
972
+ }
973
+ }
974
+ }
975
+
976
+ var toArray = function (a, b, c) {
977
+ var n = arguments.length;
978
+ switch (n) {
979
+ case 0:
980
+ return [];
981
+ case 1:
982
+ return [a];
983
+ case 2:
984
+ return [a, b];
985
+ case 3:
986
+ return [a, b, c];
987
+ default:
988
+ var arr = new Array(n);
989
+ while (n--) {
990
+ arr[n] = arguments[n];
991
+ }
992
+ return arr;
993
+ }
994
+ };
995
+
996
+ function toObject(keys, values) {
997
+ var obj = {};
998
+ var key;
999
+ var len = keys.length;
1000
+ var valuesCount = 0;
1001
+ for (var i = 0; i < len; i++) {
1002
+ key = keys[i];
1003
+ obj[key] = i < valuesCount ? values[i] : undefined$1;
1004
+ }
1005
+ return obj;
1006
+ }
1007
+
1008
+ function TargetObserver(emitter, target, options) {
1009
+ this._emitter = emitter;
1010
+ this._target = target;
1011
+ this._listeners = {};
1012
+ this._listenersCount = 0;
1013
+
1014
+ var on, off;
1015
+
1016
+ if (options.on || options.off) {
1017
+ on = options.on;
1018
+ off = options.off;
1019
+ }
1020
+
1021
+ if (target.addEventListener) {
1022
+ on = target.addEventListener;
1023
+ off = target.removeEventListener;
1024
+ } else if (target.addListener) {
1025
+ on = target.addListener;
1026
+ off = target.removeListener;
1027
+ } else if (target.on) {
1028
+ on = target.on;
1029
+ off = target.off;
1030
+ }
1031
+
1032
+ if (!on && !off) {
1033
+ throw Error('target does not implement any known event API');
1034
+ }
1035
+
1036
+ if (typeof on !== 'function') {
1037
+ throw TypeError('on method must be a function');
1038
+ }
1039
+
1040
+ if (typeof off !== 'function') {
1041
+ throw TypeError('off method must be a function');
1042
+ }
1043
+
1044
+ this._on = on;
1045
+ this._off = off;
1046
+
1047
+ var _observers= emitter._observers;
1048
+ if(_observers){
1049
+ _observers.push(this);
1050
+ }else {
1051
+ emitter._observers= [this];
1052
+ }
1053
+ }
1054
+
1055
+ Object.assign(TargetObserver.prototype, {
1056
+ subscribe: function(event, localEvent, reducer){
1057
+ var observer= this;
1058
+ var target= this._target;
1059
+ var emitter= this._emitter;
1060
+ var listeners= this._listeners;
1061
+ var handler= function(){
1062
+ var args= toArray.apply(null, arguments);
1063
+ var eventObj= {
1064
+ data: args,
1065
+ name: localEvent,
1066
+ original: event
1067
+ };
1068
+ if(reducer){
1069
+ var result= reducer.call(target, eventObj);
1070
+ if(result!==false){
1071
+ emitter.emit.apply(emitter, [eventObj.name].concat(args));
1072
+ }
1073
+ return;
1074
+ }
1075
+ emitter.emit.apply(emitter, [localEvent].concat(args));
1076
+ };
1077
+
1078
+
1079
+ if(listeners[event]){
1080
+ throw Error('Event \'' + event + '\' is already listening');
1081
+ }
1082
+
1083
+ this._listenersCount++;
1084
+
1085
+ if(emitter._newListener && emitter._removeListener && !observer._onNewListener){
1086
+
1087
+ this._onNewListener = function (_event) {
1088
+ if (_event === localEvent && listeners[event] === null) {
1089
+ listeners[event] = handler;
1090
+ observer._on.call(target, event, handler);
1091
+ }
1092
+ };
1093
+
1094
+ emitter.on('newListener', this._onNewListener);
1095
+
1096
+ this._onRemoveListener= function(_event){
1097
+ if(_event === localEvent && !emitter.hasListeners(_event) && listeners[event]){
1098
+ listeners[event]= null;
1099
+ observer._off.call(target, event, handler);
1100
+ }
1101
+ };
1102
+
1103
+ listeners[event]= null;
1104
+
1105
+ emitter.on('removeListener', this._onRemoveListener);
1106
+ }else {
1107
+ listeners[event]= handler;
1108
+ observer._on.call(target, event, handler);
1109
+ }
1110
+ },
1111
+
1112
+ unsubscribe: function(event){
1113
+ var observer= this;
1114
+ var listeners= this._listeners;
1115
+ var emitter= this._emitter;
1116
+ var handler;
1117
+ var events;
1118
+ var off= this._off;
1119
+ var target= this._target;
1120
+ var i;
1121
+
1122
+ if(event && typeof event!=='string'){
1123
+ throw TypeError('event must be a string');
1124
+ }
1125
+
1126
+ function clearRefs(){
1127
+ if(observer._onNewListener){
1128
+ emitter.off('newListener', observer._onNewListener);
1129
+ emitter.off('removeListener', observer._onRemoveListener);
1130
+ observer._onNewListener= null;
1131
+ observer._onRemoveListener= null;
1132
+ }
1133
+ var index= findTargetIndex.call(emitter, observer);
1134
+ emitter._observers.splice(index, 1);
1135
+ }
1136
+
1137
+ if(event){
1138
+ handler= listeners[event];
1139
+ if(!handler) return;
1140
+ off.call(target, event, handler);
1141
+ delete listeners[event];
1142
+ if(!--this._listenersCount){
1143
+ clearRefs();
1144
+ }
1145
+ }else {
1146
+ events= ownKeys(listeners);
1147
+ i= events.length;
1148
+ while(i-->0){
1149
+ event= events[i];
1150
+ off.call(target, event, listeners[event]);
1151
+ }
1152
+ this._listeners= {};
1153
+ this._listenersCount= 0;
1154
+ clearRefs();
1155
+ }
1156
+ }
1157
+ });
1158
+
1159
+ function resolveOptions(options, schema, reducers, allowUnknown) {
1160
+ var computedOptions = Object.assign({}, schema);
1161
+
1162
+ if (!options) return computedOptions;
1163
+
1164
+ if (typeof options !== 'object') {
1165
+ throw TypeError('options must be an object')
1166
+ }
1167
+
1168
+ var keys = Object.keys(options);
1169
+ var length = keys.length;
1170
+ var option, value;
1171
+ var reducer;
1172
+
1173
+ function reject(reason) {
1174
+ throw Error('Invalid "' + option + '" option value' + (reason ? '. Reason: ' + reason : ''))
1175
+ }
1176
+
1177
+ for (var i = 0; i < length; i++) {
1178
+ option = keys[i];
1179
+ if (!hasOwnProperty.call(schema, option)) {
1180
+ throw Error('Unknown "' + option + '" option');
1181
+ }
1182
+ value = options[option];
1183
+ if (value !== undefined$1) {
1184
+ reducer = reducers[option];
1185
+ computedOptions[option] = reducer ? reducer(value, reject) : value;
1186
+ }
1187
+ }
1188
+ return computedOptions;
1189
+ }
1190
+
1191
+ function constructorReducer(value, reject) {
1192
+ if (typeof value !== 'function' || !value.hasOwnProperty('prototype')) {
1193
+ reject('value must be a constructor');
1194
+ }
1195
+ return value;
1196
+ }
1197
+
1198
+ function makeTypeReducer(types) {
1199
+ var message= 'value must be type of ' + types.join('|');
1200
+ var len= types.length;
1201
+ var firstType= types[0];
1202
+ var secondType= types[1];
1203
+
1204
+ if (len === 1) {
1205
+ return function (v, reject) {
1206
+ if (typeof v === firstType) {
1207
+ return v;
1208
+ }
1209
+ reject(message);
1210
+ }
1211
+ }
1212
+
1213
+ if (len === 2) {
1214
+ return function (v, reject) {
1215
+ var kind= typeof v;
1216
+ if (kind === firstType || kind === secondType) return v;
1217
+ reject(message);
1218
+ }
1219
+ }
1220
+
1221
+ return function (v, reject) {
1222
+ var kind = typeof v;
1223
+ var i = len;
1224
+ while (i-- > 0) {
1225
+ if (kind === types[i]) return v;
1226
+ }
1227
+ reject(message);
1228
+ }
1229
+ }
1230
+
1231
+ var functionReducer= makeTypeReducer(['function']);
1232
+
1233
+ var objectFunctionReducer= makeTypeReducer(['object', 'function']);
1234
+
1235
+ function makeCancelablePromise(Promise, executor, options) {
1236
+ var isCancelable;
1237
+ var callbacks;
1238
+ var timer= 0;
1239
+ var subscriptionClosed;
1240
+
1241
+ var promise = new Promise(function (resolve, reject, onCancel) {
1242
+ options= resolveOptions(options, {
1243
+ timeout: 0,
1244
+ overload: false
1245
+ }, {
1246
+ timeout: function(value, reject){
1247
+ value*= 1;
1248
+ if (typeof value !== 'number' || value < 0 || !Number.isFinite(value)) {
1249
+ reject('timeout must be a positive number');
1250
+ }
1251
+ return value;
1252
+ }
1253
+ });
1254
+
1255
+ isCancelable = !options.overload && typeof Promise.prototype.cancel === 'function' && typeof onCancel === 'function';
1256
+
1257
+ function cleanup() {
1258
+ if (callbacks) {
1259
+ callbacks = null;
1260
+ }
1261
+ if (timer) {
1262
+ clearTimeout(timer);
1263
+ timer = 0;
1264
+ }
1265
+ }
1266
+
1267
+ var _resolve= function(value){
1268
+ cleanup();
1269
+ resolve(value);
1270
+ };
1271
+
1272
+ var _reject= function(err){
1273
+ cleanup();
1274
+ reject(err);
1275
+ };
1276
+
1277
+ if (isCancelable) {
1278
+ executor(_resolve, _reject, onCancel);
1279
+ } else {
1280
+ callbacks = [function(reason){
1281
+ _reject(reason || Error('canceled'));
1282
+ }];
1283
+ executor(_resolve, _reject, function (cb) {
1284
+ if (subscriptionClosed) {
1285
+ throw Error('Unable to subscribe on cancel event asynchronously')
1286
+ }
1287
+ if (typeof cb !== 'function') {
1288
+ throw TypeError('onCancel callback must be a function');
1289
+ }
1290
+ callbacks.push(cb);
1291
+ });
1292
+ subscriptionClosed= true;
1293
+ }
1294
+
1295
+ if (options.timeout > 0) {
1296
+ timer= setTimeout(function(){
1297
+ var reason= Error('timeout');
1298
+ reason.code = 'ETIMEDOUT';
1299
+ timer= 0;
1300
+ promise.cancel(reason);
1301
+ reject(reason);
1302
+ }, options.timeout);
1303
+ }
1304
+ });
1305
+
1306
+ if (!isCancelable) {
1307
+ promise.cancel = function (reason) {
1308
+ if (!callbacks) {
1309
+ return;
1310
+ }
1311
+ var length = callbacks.length;
1312
+ for (var i = 1; i < length; i++) {
1313
+ callbacks[i](reason);
1314
+ }
1315
+ // internal callback to reject the promise
1316
+ callbacks[0](reason);
1317
+ callbacks = null;
1318
+ };
1319
+ }
1320
+
1321
+ return promise;
1322
+ }
1323
+
1324
+ function findTargetIndex(observer) {
1325
+ var observers = this._observers;
1326
+ if(!observers){
1327
+ return -1;
1328
+ }
1329
+ var len = observers.length;
1330
+ for (var i = 0; i < len; i++) {
1331
+ if (observers[i]._target === observer) return i;
1332
+ }
1333
+ return -1;
1334
+ }
1335
+
1336
+ // Attention, function return type now is array, always !
1337
+ // It has zero elements if no any matches found and one or more
1338
+ // elements (leafs) if there are matches
1339
+ //
1340
+ function searchListenerTree(handlers, type, tree, i, typeLength) {
1341
+ if (!tree) {
1342
+ return null;
1343
+ }
1344
+
1345
+ if (i === 0) {
1346
+ var kind = typeof type;
1347
+ if (kind === 'string') {
1348
+ var ns, n, l = 0, j = 0, delimiter = this.delimiter, dl = delimiter.length;
1349
+ if ((n = type.indexOf(delimiter)) !== -1) {
1350
+ ns = new Array(5);
1351
+ do {
1352
+ ns[l++] = type.slice(j, n);
1353
+ j = n + dl;
1354
+ } while ((n = type.indexOf(delimiter, j)) !== -1);
1355
+
1356
+ ns[l++] = type.slice(j);
1357
+ type = ns;
1358
+ typeLength = l;
1359
+ } else {
1360
+ type = [type];
1361
+ typeLength = 1;
1362
+ }
1363
+ } else if (kind === 'object') {
1364
+ typeLength = type.length;
1365
+ } else {
1366
+ type = [type];
1367
+ typeLength = 1;
1368
+ }
1369
+ }
1370
+
1371
+ var listeners= null, branch, xTree, xxTree, isolatedBranch, endReached, currentType = type[i],
1372
+ nextType = type[i + 1], branches, _listeners;
1373
+
1374
+ if (i === typeLength) {
1375
+ //
1376
+ // If at the end of the event(s) list and the tree has listeners
1377
+ // invoke those listeners.
1378
+ //
1379
+
1380
+ if(tree._listeners) {
1381
+ if (typeof tree._listeners === 'function') {
1382
+ handlers && handlers.push(tree._listeners);
1383
+ listeners = [tree];
1384
+ } else {
1385
+ handlers && handlers.push.apply(handlers, tree._listeners);
1386
+ listeners = [tree];
1387
+ }
1388
+ }
1389
+ } else {
1390
+
1391
+ if (currentType === '*') {
1392
+ //
1393
+ // If the event emitted is '*' at this part
1394
+ // or there is a concrete match at this patch
1395
+ //
1396
+ branches = ownKeys(tree);
1397
+ n = branches.length;
1398
+ while (n-- > 0) {
1399
+ branch = branches[n];
1400
+ if (branch !== '_listeners') {
1401
+ _listeners = searchListenerTree(handlers, type, tree[branch], i + 1, typeLength);
1402
+ if (_listeners) {
1403
+ if (listeners) {
1404
+ listeners.push.apply(listeners, _listeners);
1405
+ } else {
1406
+ listeners = _listeners;
1407
+ }
1408
+ }
1409
+ }
1410
+ }
1411
+ return listeners;
1412
+ } else if (currentType === '**') {
1413
+ endReached = (i + 1 === typeLength || (i + 2 === typeLength && nextType === '*'));
1414
+ if (endReached && tree._listeners) {
1415
+ // The next element has a _listeners, add it to the handlers.
1416
+ listeners = searchListenerTree(handlers, type, tree, typeLength, typeLength);
1417
+ }
1418
+
1419
+ branches = ownKeys(tree);
1420
+ n = branches.length;
1421
+ while (n-- > 0) {
1422
+ branch = branches[n];
1423
+ if (branch !== '_listeners') {
1424
+ if (branch === '*' || branch === '**') {
1425
+ if (tree[branch]._listeners && !endReached) {
1426
+ _listeners = searchListenerTree(handlers, type, tree[branch], typeLength, typeLength);
1427
+ if (_listeners) {
1428
+ if (listeners) {
1429
+ listeners.push.apply(listeners, _listeners);
1430
+ } else {
1431
+ listeners = _listeners;
1432
+ }
1433
+ }
1434
+ }
1435
+ _listeners = searchListenerTree(handlers, type, tree[branch], i, typeLength);
1436
+ } else if (branch === nextType) {
1437
+ _listeners = searchListenerTree(handlers, type, tree[branch], i + 2, typeLength);
1438
+ } else {
1439
+ // No match on this one, shift into the tree but not in the type array.
1440
+ _listeners = searchListenerTree(handlers, type, tree[branch], i, typeLength);
1441
+ }
1442
+ if (_listeners) {
1443
+ if (listeners) {
1444
+ listeners.push.apply(listeners, _listeners);
1445
+ } else {
1446
+ listeners = _listeners;
1447
+ }
1448
+ }
1449
+ }
1450
+ }
1451
+ return listeners;
1452
+ } else if (tree[currentType]) {
1453
+ listeners = searchListenerTree(handlers, type, tree[currentType], i + 1, typeLength);
1454
+ }
1455
+ }
1456
+
1457
+ xTree = tree['*'];
1458
+ if (xTree) {
1459
+ //
1460
+ // If the listener tree will allow any match for this part,
1461
+ // then recursively explore all branches of the tree
1462
+ //
1463
+ searchListenerTree(handlers, type, xTree, i + 1, typeLength);
1464
+ }
1465
+
1466
+ xxTree = tree['**'];
1467
+ if (xxTree) {
1468
+ if (i < typeLength) {
1469
+ if (xxTree._listeners) {
1470
+ // If we have a listener on a '**', it will catch all, so add its handler.
1471
+ searchListenerTree(handlers, type, xxTree, typeLength, typeLength);
1472
+ }
1473
+
1474
+ // Build arrays of matching next branches and others.
1475
+ branches= ownKeys(xxTree);
1476
+ n= branches.length;
1477
+ while(n-->0){
1478
+ branch= branches[n];
1479
+ if (branch !== '_listeners') {
1480
+ if (branch === nextType) {
1481
+ // We know the next element will match, so jump twice.
1482
+ searchListenerTree(handlers, type, xxTree[branch], i + 2, typeLength);
1483
+ } else if (branch === currentType) {
1484
+ // Current node matches, move into the tree.
1485
+ searchListenerTree(handlers, type, xxTree[branch], i + 1, typeLength);
1486
+ } else {
1487
+ isolatedBranch = {};
1488
+ isolatedBranch[branch] = xxTree[branch];
1489
+ searchListenerTree(handlers, type, {'**': isolatedBranch}, i + 1, typeLength);
1490
+ }
1491
+ }
1492
+ }
1493
+ } else if (xxTree._listeners) {
1494
+ // We have reached the end and still on a '**'
1495
+ searchListenerTree(handlers, type, xxTree, typeLength, typeLength);
1496
+ } else if (xxTree['*'] && xxTree['*']._listeners) {
1497
+ searchListenerTree(handlers, type, xxTree['*'], typeLength, typeLength);
1498
+ }
1499
+ }
1500
+
1501
+ return listeners;
1502
+ }
1503
+
1504
+ function growListenerTree(type, listener, prepend) {
1505
+ var len = 0, j = 0, i, delimiter = this.delimiter, dl= delimiter.length, ns;
1506
+
1507
+ if(typeof type==='string') {
1508
+ if ((i = type.indexOf(delimiter)) !== -1) {
1509
+ ns = new Array(5);
1510
+ do {
1511
+ ns[len++] = type.slice(j, i);
1512
+ j = i + dl;
1513
+ } while ((i = type.indexOf(delimiter, j)) !== -1);
1514
+
1515
+ ns[len++] = type.slice(j);
1516
+ }else {
1517
+ ns= [type];
1518
+ len= 1;
1519
+ }
1520
+ }else {
1521
+ ns= type;
1522
+ len= type.length;
1523
+ }
1524
+
1525
+ //
1526
+ // Looks for two consecutive '**', if so, don't add the event at all.
1527
+ //
1528
+ if (len > 1) {
1529
+ for (i = 0; i + 1 < len; i++) {
1530
+ if (ns[i] === '**' && ns[i + 1] === '**') {
1531
+ return;
1532
+ }
1533
+ }
1534
+ }
1535
+
1536
+
1537
+
1538
+ var tree = this.listenerTree, name;
1539
+
1540
+ for (i = 0; i < len; i++) {
1541
+ name = ns[i];
1542
+
1543
+ tree = tree[name] || (tree[name] = {});
1544
+
1545
+ if (i === len - 1) {
1546
+ if (!tree._listeners) {
1547
+ tree._listeners = listener;
1548
+ } else {
1549
+ if (typeof tree._listeners === 'function') {
1550
+ tree._listeners = [tree._listeners];
1551
+ }
1552
+
1553
+ if (prepend) {
1554
+ tree._listeners.unshift(listener);
1555
+ } else {
1556
+ tree._listeners.push(listener);
1557
+ }
1558
+
1559
+ if (
1560
+ !tree._listeners.warned &&
1561
+ this._maxListeners > 0 &&
1562
+ tree._listeners.length > this._maxListeners
1563
+ ) {
1564
+ tree._listeners.warned = true;
1565
+ logPossibleMemoryLeak.call(this, tree._listeners.length, name);
1566
+ }
1567
+ }
1568
+ return true;
1569
+ }
1570
+ }
1571
+
1572
+ return true;
1573
+ }
1574
+
1575
+ function collectTreeEvents(tree, events, root, asArray){
1576
+ var branches= ownKeys(tree);
1577
+ var i= branches.length;
1578
+ var branch, branchName, path;
1579
+ var hasListeners= tree['_listeners'];
1580
+ var isArrayPath;
1581
+
1582
+ while(i-->0){
1583
+ branchName= branches[i];
1584
+
1585
+ branch= tree[branchName];
1586
+
1587
+ if(branchName==='_listeners'){
1588
+ path= root;
1589
+ }else {
1590
+ path = root ? root.concat(branchName) : [branchName];
1591
+ }
1592
+
1593
+ isArrayPath= asArray || typeof branchName==='symbol';
1594
+
1595
+ hasListeners && events.push(isArrayPath? path : path.join(this.delimiter));
1596
+
1597
+ if(typeof branch==='object'){
1598
+ collectTreeEvents.call(this, branch, events, path, isArrayPath);
1599
+ }
1600
+ }
1601
+
1602
+ return events;
1603
+ }
1604
+
1605
+ function recursivelyGarbageCollect(root) {
1606
+ var keys = ownKeys(root);
1607
+ var i= keys.length;
1608
+ var obj, key, flag;
1609
+ while(i-->0){
1610
+ key = keys[i];
1611
+ obj = root[key];
1612
+
1613
+ if(obj){
1614
+ flag= true;
1615
+ if(key !== '_listeners' && !recursivelyGarbageCollect(obj)){
1616
+ delete root[key];
1617
+ }
1618
+ }
1619
+ }
1620
+
1621
+ return flag;
1622
+ }
1623
+
1624
+ function Listener(emitter, event, listener){
1625
+ this.emitter= emitter;
1626
+ this.event= event;
1627
+ this.listener= listener;
1628
+ }
1629
+
1630
+ Listener.prototype.off= function(){
1631
+ this.emitter.off(this.event, this.listener);
1632
+ return this;
1633
+ };
1634
+
1635
+ function setupListener(event, listener, options){
1636
+ if (options === true) {
1637
+ promisify = true;
1638
+ } else if (options === false) {
1639
+ async = true;
1640
+ } else {
1641
+ if (!options || typeof options !== 'object') {
1642
+ throw TypeError('options should be an object or true');
1643
+ }
1644
+ var async = options.async;
1645
+ var promisify = options.promisify;
1646
+ var nextTick = options.nextTick;
1647
+ var objectify = options.objectify;
1648
+ }
1649
+
1650
+ if (async || nextTick || promisify) {
1651
+ var _listener = listener;
1652
+ var _origin = listener._origin || listener;
1653
+
1654
+ if (nextTick && !nextTickSupported) {
1655
+ throw Error('process.nextTick is not supported');
1656
+ }
1657
+
1658
+ if (promisify === undefined$1) {
1659
+ promisify = listener.constructor.name === 'AsyncFunction';
1660
+ }
1661
+
1662
+ listener = function () {
1663
+ var args = arguments;
1664
+ var context = this;
1665
+ var event = this.event;
1666
+
1667
+ return promisify ? (nextTick ? Promise.resolve() : new Promise(function (resolve) {
1668
+ _setImmediate(resolve);
1669
+ }).then(function () {
1670
+ context.event = event;
1671
+ return _listener.apply(context, args)
1672
+ })) : (nextTick ? process.nextTick : _setImmediate)(function () {
1673
+ context.event = event;
1674
+ _listener.apply(context, args);
1675
+ });
1676
+ };
1677
+
1678
+ listener._async = true;
1679
+ listener._origin = _origin;
1680
+ }
1681
+
1682
+ return [listener, objectify? new Listener(this, event, listener): this];
1683
+ }
1684
+
1685
+ function EventEmitter(conf) {
1686
+ this._events = {};
1687
+ this._newListener = false;
1688
+ this._removeListener = false;
1689
+ this.verboseMemoryLeak = false;
1690
+ configure.call(this, conf);
1691
+ }
1692
+
1693
+ EventEmitter.EventEmitter2 = EventEmitter; // backwards compatibility for exporting EventEmitter property
1694
+
1695
+ EventEmitter.prototype.listenTo= function(target, events, options){
1696
+ if(typeof target!=='object'){
1697
+ throw TypeError('target musts be an object');
1698
+ }
1699
+
1700
+ var emitter= this;
1701
+
1702
+ options = resolveOptions(options, {
1703
+ on: undefined$1,
1704
+ off: undefined$1,
1705
+ reducers: undefined$1
1706
+ }, {
1707
+ on: functionReducer,
1708
+ off: functionReducer,
1709
+ reducers: objectFunctionReducer
1710
+ });
1711
+
1712
+ function listen(events){
1713
+ if(typeof events!=='object'){
1714
+ throw TypeError('events must be an object');
1715
+ }
1716
+
1717
+ var reducers= options.reducers;
1718
+ var index= findTargetIndex.call(emitter, target);
1719
+ var observer;
1720
+
1721
+ if(index===-1){
1722
+ observer= new TargetObserver(emitter, target, options);
1723
+ }else {
1724
+ observer= emitter._observers[index];
1725
+ }
1726
+
1727
+ var keys= ownKeys(events);
1728
+ var len= keys.length;
1729
+ var event;
1730
+ var isSingleReducer= typeof reducers==='function';
1731
+
1732
+ for(var i=0; i<len; i++){
1733
+ event= keys[i];
1734
+ observer.subscribe(
1735
+ event,
1736
+ events[event] || event,
1737
+ isSingleReducer ? reducers : reducers && reducers[event]
1738
+ );
1739
+ }
1740
+ }
1741
+
1742
+ isArray(events)?
1743
+ listen(toObject(events)) :
1744
+ (typeof events==='string'? listen(toObject(events.split(/\s+/))): listen(events));
1745
+
1746
+ return this;
1747
+ };
1748
+
1749
+ EventEmitter.prototype.stopListeningTo = function (target, event) {
1750
+ var observers = this._observers;
1751
+
1752
+ if(!observers){
1753
+ return false;
1754
+ }
1755
+
1756
+ var i = observers.length;
1757
+ var observer;
1758
+ var matched= false;
1759
+
1760
+ if(target && typeof target!=='object'){
1761
+ throw TypeError('target should be an object');
1762
+ }
1763
+
1764
+ while (i-- > 0) {
1765
+ observer = observers[i];
1766
+ if (!target || observer._target === target) {
1767
+ observer.unsubscribe(event);
1768
+ matched= true;
1769
+ }
1770
+ }
1771
+
1772
+ return matched;
1773
+ };
1774
+
1775
+ // By default EventEmitters will print a warning if more than
1776
+ // 10 listeners are added to it. This is a useful default which
1777
+ // helps finding memory leaks.
1778
+ //
1779
+ // Obviously not all Emitters should be limited to 10. This function allows
1780
+ // that to be increased. Set to zero for unlimited.
1781
+
1782
+ EventEmitter.prototype.delimiter = '.';
1783
+
1784
+ EventEmitter.prototype.setMaxListeners = function(n) {
1785
+ if (n !== undefined$1) {
1786
+ this._maxListeners = n;
1787
+ if (!this._conf) this._conf = {};
1788
+ this._conf.maxListeners = n;
1789
+ }
1790
+ };
1791
+
1792
+ EventEmitter.prototype.getMaxListeners = function() {
1793
+ return this._maxListeners;
1794
+ };
1795
+
1796
+ EventEmitter.prototype.event = '';
1797
+
1798
+ EventEmitter.prototype.once = function(event, fn, options) {
1799
+ return this._once(event, fn, false, options);
1800
+ };
1801
+
1802
+ EventEmitter.prototype.prependOnceListener = function(event, fn, options) {
1803
+ return this._once(event, fn, true, options);
1804
+ };
1805
+
1806
+ EventEmitter.prototype._once = function(event, fn, prepend, options) {
1807
+ return this._many(event, 1, fn, prepend, options);
1808
+ };
1809
+
1810
+ EventEmitter.prototype.many = function(event, ttl, fn, options) {
1811
+ return this._many(event, ttl, fn, false, options);
1812
+ };
1813
+
1814
+ EventEmitter.prototype.prependMany = function(event, ttl, fn, options) {
1815
+ return this._many(event, ttl, fn, true, options);
1816
+ };
1817
+
1818
+ EventEmitter.prototype._many = function(event, ttl, fn, prepend, options) {
1819
+ var self = this;
1820
+
1821
+ if (typeof fn !== 'function') {
1822
+ throw new Error('many only accepts instances of Function');
1823
+ }
1824
+
1825
+ function listener() {
1826
+ if (--ttl === 0) {
1827
+ self.off(event, listener);
1828
+ }
1829
+ return fn.apply(this, arguments);
1830
+ }
1831
+
1832
+ listener._origin = fn;
1833
+
1834
+ return this._on(event, listener, prepend, options);
1835
+ };
1836
+
1837
+ EventEmitter.prototype.emit = function() {
1838
+ if (!this._events && !this._all) {
1839
+ return false;
1840
+ }
1841
+
1842
+ this._events || init.call(this);
1843
+
1844
+ var type = arguments[0], ns, wildcard= this.wildcard;
1845
+ var args,l,i,j, containsSymbol;
1846
+
1847
+ if (type === 'newListener' && !this._newListener) {
1848
+ if (!this._events.newListener) {
1849
+ return false;
1850
+ }
1851
+ }
1852
+
1853
+ if (wildcard) {
1854
+ ns= type;
1855
+ if(type!=='newListener' && type!=='removeListener'){
1856
+ if (typeof type === 'object') {
1857
+ l = type.length;
1858
+ if (symbolsSupported) {
1859
+ for (i = 0; i < l; i++) {
1860
+ if (typeof type[i] === 'symbol') {
1861
+ containsSymbol = true;
1862
+ break;
1863
+ }
1864
+ }
1865
+ }
1866
+ if (!containsSymbol) {
1867
+ type = type.join(this.delimiter);
1868
+ }
1869
+ }
1870
+ }
1871
+ }
1872
+
1873
+ var al = arguments.length;
1874
+ var handler;
1875
+
1876
+ if (this._all && this._all.length) {
1877
+ handler = this._all.slice();
1878
+
1879
+ for (i = 0, l = handler.length; i < l; i++) {
1880
+ this.event = type;
1881
+ switch (al) {
1882
+ case 1:
1883
+ handler[i].call(this, type);
1884
+ break;
1885
+ case 2:
1886
+ handler[i].call(this, type, arguments[1]);
1887
+ break;
1888
+ case 3:
1889
+ handler[i].call(this, type, arguments[1], arguments[2]);
1890
+ break;
1891
+ default:
1892
+ handler[i].apply(this, arguments);
1893
+ }
1894
+ }
1895
+ }
1896
+
1897
+ if (wildcard) {
1898
+ handler = [];
1899
+ searchListenerTree.call(this, handler, ns, this.listenerTree, 0, l);
1900
+ } else {
1901
+ handler = this._events[type];
1902
+ if (typeof handler === 'function') {
1903
+ this.event = type;
1904
+ switch (al) {
1905
+ case 1:
1906
+ handler.call(this);
1907
+ break;
1908
+ case 2:
1909
+ handler.call(this, arguments[1]);
1910
+ break;
1911
+ case 3:
1912
+ handler.call(this, arguments[1], arguments[2]);
1913
+ break;
1914
+ default:
1915
+ args = new Array(al - 1);
1916
+ for (j = 1; j < al; j++) args[j - 1] = arguments[j];
1917
+ handler.apply(this, args);
1918
+ }
1919
+ return true;
1920
+ } else if (handler) {
1921
+ // need to make copy of handlers because list can change in the middle
1922
+ // of emit call
1923
+ handler = handler.slice();
1924
+ }
1925
+ }
1926
+
1927
+ if (handler && handler.length) {
1928
+ if (al > 3) {
1929
+ args = new Array(al - 1);
1930
+ for (j = 1; j < al; j++) args[j - 1] = arguments[j];
1931
+ }
1932
+ for (i = 0, l = handler.length; i < l; i++) {
1933
+ this.event = type;
1934
+ switch (al) {
1935
+ case 1:
1936
+ handler[i].call(this);
1937
+ break;
1938
+ case 2:
1939
+ handler[i].call(this, arguments[1]);
1940
+ break;
1941
+ case 3:
1942
+ handler[i].call(this, arguments[1], arguments[2]);
1943
+ break;
1944
+ default:
1945
+ handler[i].apply(this, args);
1946
+ }
1947
+ }
1948
+ return true;
1949
+ } else if (!this.ignoreErrors && !this._all && type === 'error') {
1950
+ if (arguments[1] instanceof Error) {
1951
+ throw arguments[1]; // Unhandled 'error' event
1952
+ } else {
1953
+ throw new Error("Uncaught, unspecified 'error' event.");
1954
+ }
1955
+ }
1956
+
1957
+ return !!this._all;
1958
+ };
1959
+
1960
+ EventEmitter.prototype.emitAsync = function() {
1961
+ if (!this._events && !this._all) {
1962
+ return false;
1963
+ }
1964
+
1965
+ this._events || init.call(this);
1966
+
1967
+ var type = arguments[0], wildcard= this.wildcard, ns, containsSymbol;
1968
+ var args,l,i,j;
1969
+
1970
+ if (type === 'newListener' && !this._newListener) {
1971
+ if (!this._events.newListener) { return Promise.resolve([false]); }
1972
+ }
1973
+
1974
+ if (wildcard) {
1975
+ ns= type;
1976
+ if(type!=='newListener' && type!=='removeListener'){
1977
+ if (typeof type === 'object') {
1978
+ l = type.length;
1979
+ if (symbolsSupported) {
1980
+ for (i = 0; i < l; i++) {
1981
+ if (typeof type[i] === 'symbol') {
1982
+ containsSymbol = true;
1983
+ break;
1984
+ }
1985
+ }
1986
+ }
1987
+ if (!containsSymbol) {
1988
+ type = type.join(this.delimiter);
1989
+ }
1990
+ }
1991
+ }
1992
+ }
1993
+
1994
+ var promises= [];
1995
+
1996
+ var al = arguments.length;
1997
+ var handler;
1998
+
1999
+ if (this._all) {
2000
+ for (i = 0, l = this._all.length; i < l; i++) {
2001
+ this.event = type;
2002
+ switch (al) {
2003
+ case 1:
2004
+ promises.push(this._all[i].call(this, type));
2005
+ break;
2006
+ case 2:
2007
+ promises.push(this._all[i].call(this, type, arguments[1]));
2008
+ break;
2009
+ case 3:
2010
+ promises.push(this._all[i].call(this, type, arguments[1], arguments[2]));
2011
+ break;
2012
+ default:
2013
+ promises.push(this._all[i].apply(this, arguments));
2014
+ }
2015
+ }
2016
+ }
2017
+
2018
+ if (wildcard) {
2019
+ handler = [];
2020
+ searchListenerTree.call(this, handler, ns, this.listenerTree, 0);
2021
+ } else {
2022
+ handler = this._events[type];
2023
+ }
2024
+
2025
+ if (typeof handler === 'function') {
2026
+ this.event = type;
2027
+ switch (al) {
2028
+ case 1:
2029
+ promises.push(handler.call(this));
2030
+ break;
2031
+ case 2:
2032
+ promises.push(handler.call(this, arguments[1]));
2033
+ break;
2034
+ case 3:
2035
+ promises.push(handler.call(this, arguments[1], arguments[2]));
2036
+ break;
2037
+ default:
2038
+ args = new Array(al - 1);
2039
+ for (j = 1; j < al; j++) args[j - 1] = arguments[j];
2040
+ promises.push(handler.apply(this, args));
2041
+ }
2042
+ } else if (handler && handler.length) {
2043
+ handler = handler.slice();
2044
+ if (al > 3) {
2045
+ args = new Array(al - 1);
2046
+ for (j = 1; j < al; j++) args[j - 1] = arguments[j];
2047
+ }
2048
+ for (i = 0, l = handler.length; i < l; i++) {
2049
+ this.event = type;
2050
+ switch (al) {
2051
+ case 1:
2052
+ promises.push(handler[i].call(this));
2053
+ break;
2054
+ case 2:
2055
+ promises.push(handler[i].call(this, arguments[1]));
2056
+ break;
2057
+ case 3:
2058
+ promises.push(handler[i].call(this, arguments[1], arguments[2]));
2059
+ break;
2060
+ default:
2061
+ promises.push(handler[i].apply(this, args));
2062
+ }
2063
+ }
2064
+ } else if (!this.ignoreErrors && !this._all && type === 'error') {
2065
+ if (arguments[1] instanceof Error) {
2066
+ return Promise.reject(arguments[1]); // Unhandled 'error' event
2067
+ } else {
2068
+ return Promise.reject("Uncaught, unspecified 'error' event.");
2069
+ }
2070
+ }
2071
+
2072
+ return Promise.all(promises);
2073
+ };
2074
+
2075
+ EventEmitter.prototype.on = function(type, listener, options) {
2076
+ return this._on(type, listener, false, options);
2077
+ };
2078
+
2079
+ EventEmitter.prototype.prependListener = function(type, listener, options) {
2080
+ return this._on(type, listener, true, options);
2081
+ };
2082
+
2083
+ EventEmitter.prototype.onAny = function(fn) {
2084
+ return this._onAny(fn, false);
2085
+ };
2086
+
2087
+ EventEmitter.prototype.prependAny = function(fn) {
2088
+ return this._onAny(fn, true);
2089
+ };
2090
+
2091
+ EventEmitter.prototype.addListener = EventEmitter.prototype.on;
2092
+
2093
+ EventEmitter.prototype._onAny = function(fn, prepend){
2094
+ if (typeof fn !== 'function') {
2095
+ throw new Error('onAny only accepts instances of Function');
2096
+ }
2097
+
2098
+ if (!this._all) {
2099
+ this._all = [];
2100
+ }
2101
+
2102
+ // Add the function to the event listener collection.
2103
+ if(prepend){
2104
+ this._all.unshift(fn);
2105
+ }else {
2106
+ this._all.push(fn);
2107
+ }
2108
+
2109
+ return this;
2110
+ };
2111
+
2112
+ EventEmitter.prototype._on = function(type, listener, prepend, options) {
2113
+ if (typeof type === 'function') {
2114
+ this._onAny(type, listener);
2115
+ return this;
2116
+ }
2117
+
2118
+ if (typeof listener !== 'function') {
2119
+ throw new Error('on only accepts instances of Function');
2120
+ }
2121
+ this._events || init.call(this);
2122
+
2123
+ var returnValue= this, temp;
2124
+
2125
+ if (options !== undefined$1) {
2126
+ temp = setupListener.call(this, type, listener, options);
2127
+ listener = temp[0];
2128
+ returnValue = temp[1];
2129
+ }
2130
+
2131
+ // To avoid recursion in the case that type == "newListeners"! Before
2132
+ // adding it to the listeners, first emit "newListeners".
2133
+ if (this._newListener) {
2134
+ this.emit('newListener', type, listener);
2135
+ }
2136
+
2137
+ if (this.wildcard) {
2138
+ growListenerTree.call(this, type, listener, prepend);
2139
+ return returnValue;
2140
+ }
2141
+
2142
+ if (!this._events[type]) {
2143
+ // Optimize the case of one listener. Don't need the extra array object.
2144
+ this._events[type] = listener;
2145
+ } else {
2146
+ if (typeof this._events[type] === 'function') {
2147
+ // Change to array.
2148
+ this._events[type] = [this._events[type]];
2149
+ }
2150
+
2151
+ // If we've already got an array, just add
2152
+ if(prepend){
2153
+ this._events[type].unshift(listener);
2154
+ }else {
2155
+ this._events[type].push(listener);
2156
+ }
2157
+
2158
+ // Check for listener leak
2159
+ if (
2160
+ !this._events[type].warned &&
2161
+ this._maxListeners > 0 &&
2162
+ this._events[type].length > this._maxListeners
2163
+ ) {
2164
+ this._events[type].warned = true;
2165
+ logPossibleMemoryLeak.call(this, this._events[type].length, type);
2166
+ }
2167
+ }
2168
+
2169
+ return returnValue;
2170
+ };
2171
+
2172
+ EventEmitter.prototype.off = function(type, listener) {
2173
+ if (typeof listener !== 'function') {
2174
+ throw new Error('removeListener only takes instances of Function');
2175
+ }
2176
+
2177
+ var handlers,leafs=[];
2178
+
2179
+ if(this.wildcard) {
2180
+ var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
2181
+ leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0);
2182
+ if(!leafs) return this;
2183
+ } else {
2184
+ // does not use listeners(), so no side effect of creating _events[type]
2185
+ if (!this._events[type]) return this;
2186
+ handlers = this._events[type];
2187
+ leafs.push({_listeners:handlers});
2188
+ }
2189
+
2190
+ for (var iLeaf=0; iLeaf<leafs.length; iLeaf++) {
2191
+ var leaf = leafs[iLeaf];
2192
+ handlers = leaf._listeners;
2193
+ if (isArray(handlers)) {
2194
+
2195
+ var position = -1;
2196
+
2197
+ for (var i = 0, length = handlers.length; i < length; i++) {
2198
+ if (handlers[i] === listener ||
2199
+ (handlers[i].listener && handlers[i].listener === listener) ||
2200
+ (handlers[i]._origin && handlers[i]._origin === listener)) {
2201
+ position = i;
2202
+ break;
2203
+ }
2204
+ }
2205
+
2206
+ if (position < 0) {
2207
+ continue;
2208
+ }
2209
+
2210
+ if(this.wildcard) {
2211
+ leaf._listeners.splice(position, 1);
2212
+ }
2213
+ else {
2214
+ this._events[type].splice(position, 1);
2215
+ }
2216
+
2217
+ if (handlers.length === 0) {
2218
+ if(this.wildcard) {
2219
+ delete leaf._listeners;
2220
+ }
2221
+ else {
2222
+ delete this._events[type];
2223
+ }
2224
+ }
2225
+ if (this._removeListener)
2226
+ this.emit("removeListener", type, listener);
2227
+
2228
+ return this;
2229
+ }
2230
+ else if (handlers === listener ||
2231
+ (handlers.listener && handlers.listener === listener) ||
2232
+ (handlers._origin && handlers._origin === listener)) {
2233
+ if(this.wildcard) {
2234
+ delete leaf._listeners;
2235
+ }
2236
+ else {
2237
+ delete this._events[type];
2238
+ }
2239
+ if (this._removeListener)
2240
+ this.emit("removeListener", type, listener);
2241
+ }
2242
+ }
2243
+
2244
+ this.listenerTree && recursivelyGarbageCollect(this.listenerTree);
2245
+
2246
+ return this;
2247
+ };
2248
+
2249
+ EventEmitter.prototype.offAny = function(fn) {
2250
+ var i = 0, l = 0, fns;
2251
+ if (fn && this._all && this._all.length > 0) {
2252
+ fns = this._all;
2253
+ for(i = 0, l = fns.length; i < l; i++) {
2254
+ if(fn === fns[i]) {
2255
+ fns.splice(i, 1);
2256
+ if (this._removeListener)
2257
+ this.emit("removeListenerAny", fn);
2258
+ return this;
2259
+ }
2260
+ }
2261
+ } else {
2262
+ fns = this._all;
2263
+ if (this._removeListener) {
2264
+ for(i = 0, l = fns.length; i < l; i++)
2265
+ this.emit("removeListenerAny", fns[i]);
2266
+ }
2267
+ this._all = [];
2268
+ }
2269
+ return this;
2270
+ };
2271
+
2272
+ EventEmitter.prototype.removeListener = EventEmitter.prototype.off;
2273
+
2274
+ EventEmitter.prototype.removeAllListeners = function (type) {
2275
+ if (type === undefined$1) {
2276
+ !this._events || init.call(this);
2277
+ return this;
2278
+ }
2279
+
2280
+ if (this.wildcard) {
2281
+ var leafs = searchListenerTree.call(this, null, type, this.listenerTree, 0), leaf, i;
2282
+ if (!leafs) return this;
2283
+ for (i = 0; i < leafs.length; i++) {
2284
+ leaf = leafs[i];
2285
+ leaf._listeners = null;
2286
+ }
2287
+ this.listenerTree && recursivelyGarbageCollect(this.listenerTree);
2288
+ } else if (this._events) {
2289
+ this._events[type] = null;
2290
+ }
2291
+ return this;
2292
+ };
2293
+
2294
+ EventEmitter.prototype.listeners = function (type) {
2295
+ var _events = this._events;
2296
+ var keys, listeners, allListeners;
2297
+ var i;
2298
+ var listenerTree;
2299
+
2300
+ if (type === undefined$1) {
2301
+ if (this.wildcard) {
2302
+ throw Error('event name required for wildcard emitter');
2303
+ }
2304
+
2305
+ if (!_events) {
2306
+ return [];
2307
+ }
2308
+
2309
+ keys = ownKeys(_events);
2310
+ i = keys.length;
2311
+ allListeners = [];
2312
+ while (i-- > 0) {
2313
+ listeners = _events[keys[i]];
2314
+ if (typeof listeners === 'function') {
2315
+ allListeners.push(listeners);
2316
+ } else {
2317
+ allListeners.push.apply(allListeners, listeners);
2318
+ }
2319
+ }
2320
+ return allListeners;
2321
+ } else {
2322
+ if (this.wildcard) {
2323
+ listenerTree= this.listenerTree;
2324
+ if(!listenerTree) return [];
2325
+ var handlers = [];
2326
+ var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
2327
+ searchListenerTree.call(this, handlers, ns, listenerTree, 0);
2328
+ return handlers;
2329
+ }
2330
+
2331
+ if (!_events) {
2332
+ return [];
2333
+ }
2334
+
2335
+ listeners = _events[type];
2336
+
2337
+ if (!listeners) {
2338
+ return [];
2339
+ }
2340
+ return typeof listeners === 'function' ? [listeners] : listeners;
2341
+ }
2342
+ };
2343
+
2344
+ EventEmitter.prototype.eventNames = function(nsAsArray){
2345
+ var _events= this._events;
2346
+ return this.wildcard? collectTreeEvents.call(this, this.listenerTree, [], null, nsAsArray) : (_events? ownKeys(_events) : []);
2347
+ };
2348
+
2349
+ EventEmitter.prototype.listenerCount = function(type) {
2350
+ return this.listeners(type).length;
2351
+ };
2352
+
2353
+ EventEmitter.prototype.hasListeners = function (type) {
2354
+ if (this.wildcard) {
2355
+ var handlers = [];
2356
+ var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
2357
+ searchListenerTree.call(this, handlers, ns, this.listenerTree, 0);
2358
+ return handlers.length > 0;
2359
+ }
2360
+
2361
+ var _events = this._events;
2362
+ var _all = this._all;
2363
+
2364
+ return !!(_all && _all.length || _events && (type === undefined$1 ? ownKeys(_events).length : _events[type]));
2365
+ };
2366
+
2367
+ EventEmitter.prototype.listenersAny = function() {
2368
+
2369
+ if(this._all) {
2370
+ return this._all;
2371
+ }
2372
+ else {
2373
+ return [];
2374
+ }
2375
+
2376
+ };
2377
+
2378
+ EventEmitter.prototype.waitFor = function (event, options) {
2379
+ var self = this;
2380
+ var type = typeof options;
2381
+ if (type === 'number') {
2382
+ options = {timeout: options};
2383
+ } else if (type === 'function') {
2384
+ options = {filter: options};
2385
+ }
2386
+
2387
+ options= resolveOptions(options, {
2388
+ timeout: 0,
2389
+ filter: undefined$1,
2390
+ handleError: false,
2391
+ Promise: Promise,
2392
+ overload: false
2393
+ }, {
2394
+ filter: functionReducer,
2395
+ Promise: constructorReducer
2396
+ });
2397
+
2398
+ return makeCancelablePromise(options.Promise, function (resolve, reject, onCancel) {
2399
+ function listener() {
2400
+ var filter= options.filter;
2401
+ if (filter && !filter.apply(self, arguments)) {
2402
+ return;
2403
+ }
2404
+ self.off(event, listener);
2405
+ if (options.handleError) {
2406
+ var err = arguments[0];
2407
+ err ? reject(err) : resolve(toArray.apply(null, arguments).slice(1));
2408
+ } else {
2409
+ resolve(toArray.apply(null, arguments));
2410
+ }
2411
+ }
2412
+
2413
+ onCancel(function(){
2414
+ self.off(event, listener);
2415
+ });
2416
+
2417
+ self._on(event, listener, false);
2418
+ }, {
2419
+ timeout: options.timeout,
2420
+ overload: options.overload
2421
+ })
2422
+ };
2423
+
2424
+ function once(emitter, name, options) {
2425
+ options= resolveOptions(options, {
2426
+ Promise: Promise,
2427
+ timeout: 0,
2428
+ overload: false
2429
+ }, {
2430
+ Promise: constructorReducer
2431
+ });
2432
+
2433
+ var _Promise= options.Promise;
2434
+
2435
+ return makeCancelablePromise(_Promise, function(resolve, reject, onCancel){
2436
+ var handler;
2437
+ if (typeof emitter.addEventListener === 'function') {
2438
+ handler= function () {
2439
+ resolve(toArray.apply(null, arguments));
2440
+ };
2441
+
2442
+ onCancel(function(){
2443
+ emitter.removeEventListener(name, handler);
2444
+ });
2445
+
2446
+ emitter.addEventListener(
2447
+ name,
2448
+ handler,
2449
+ {once: true}
2450
+ );
2451
+ return;
2452
+ }
2453
+
2454
+ var eventListener = function(){
2455
+ errorListener && emitter.removeListener('error', errorListener);
2456
+ resolve(toArray.apply(null, arguments));
2457
+ };
2458
+
2459
+ var errorListener;
2460
+
2461
+ if (name !== 'error') {
2462
+ errorListener = function (err){
2463
+ emitter.removeListener(name, eventListener);
2464
+ reject(err);
2465
+ };
2466
+
2467
+ emitter.once('error', errorListener);
2468
+ }
2469
+
2470
+ onCancel(function(){
2471
+ errorListener && emitter.removeListener('error', errorListener);
2472
+ emitter.removeListener(name, eventListener);
2473
+ });
2474
+
2475
+ emitter.once(name, eventListener);
2476
+ }, {
2477
+ timeout: options.timeout,
2478
+ overload: options.overload
2479
+ });
2480
+ }
2481
+
2482
+ var prototype= EventEmitter.prototype;
2483
+
2484
+ Object.defineProperties(EventEmitter, {
2485
+ defaultMaxListeners: {
2486
+ get: function () {
2487
+ return prototype._maxListeners;
2488
+ },
2489
+ set: function (n) {
2490
+ if (typeof n !== 'number' || n < 0 || Number.isNaN(n)) {
2491
+ throw TypeError('n must be a non-negative number')
2492
+ }
2493
+ prototype._maxListeners = n;
2494
+ },
2495
+ enumerable: true
2496
+ },
2497
+ once: {
2498
+ value: once,
2499
+ writable: true,
2500
+ configurable: true
2501
+ }
2502
+ });
2503
+
2504
+ Object.defineProperties(prototype, {
2505
+ _maxListeners: {
2506
+ value: defaultMaxListeners,
2507
+ writable: true,
2508
+ configurable: true
2509
+ },
2510
+ _observers: {value: null, writable: true, configurable: true}
2511
+ });
2512
+
2513
+ {
2514
+ // CommonJS
2515
+ module.exports = EventEmitter;
2516
+ }
2517
+ }();
2518
+ } (eventemitter2));
2519
+ return eventemitter2.exports;
2520
+ }
2521
+
2522
+ var eventemitter2Exports = requireEventemitter2();
2523
+ var EventEmitter2 = /*@__PURE__*/getDefaultExportFromCjs(eventemitter2Exports);
2524
+
2525
+ // =================================================================
2526
+ // event-bus.ts — 基于 EventEmitter2 的插件事件总线
2527
+ //
2528
+ // 利用 EventEmitter2 的三个核心特性:
2529
+ // 1. wildcard: true → 支持 'terminal:*' 订阅整个命名空间
2530
+ // 2. delimiter: ':' → 'namespace:event' 格式的原生支持
2531
+ // 3. listener.off() → 订阅返回 Listener 对象,无需手动传 handler 引用
2532
+ // =================================================================
2533
+
2534
+
2535
+ // ── 全局总线单例(所有插件共享,跨插件通信用)──────────────────────
2536
+ //
2537
+ // wildcard + delimiter 让命名空间隔离变成原生能力:
2538
+ // - 插件 A 订阅 'terminal:*' 可以收到所有 terminal 前缀的事件
2539
+ // - 全局订阅 '**' 可以监听所有事件(调试用)
2540
+ // - maxListeners 设大一点,避免大量插件时出现警告
2541
+
2542
+ const globalEmitter = new EventEmitter2({
2543
+ wildcard: true,
2544
+ // 开启通配符
2545
+ delimiter: ':',
2546
+ // 命名空间分隔符,与原版 createModuleEventBus 保持一致
2547
+ newListener: false,
2548
+ // 不触发 newListener 事件,减少不必要开销
2549
+ maxListeners: 200,
2550
+ // 对标原版 createModuleEventBus(pluginName, 200) 的容量参数
2551
+ verboseMemoryLeak: true // 超出 maxListeners 时打印详细的内存泄漏警告
2552
+ });
2553
+ // ── 插件私有事件总线工厂函数 ──────────────────────────────────────
2554
+ //
2555
+ // 每个插件获得一个独立的 emitter 实例(私有事件不污染全局),
2556
+ // 同时持有 globalEmitter 引用用于跨插件通信。
2557
+ //
2558
+ // 命名规则:
2559
+ // ctx.event.emit('data-loaded') → 实际发出 'terminal:data-loaded'(自动加前缀)
2560
+ // ctx.event.on('data-loaded', fn) → 订阅 'terminal:data-loaded'
2561
+ // ctx.event.onGlobal('layout:*', fn) → 订阅全局总线上所有 layout 事件(wildcard)
2562
+ // ctx.event.emitGlobal('layout:ready')→ 向全局总线发出事件,所有插件都能收到
2563
+
2564
+ function createPluginEventBus(namespace) {
2565
+ // 每个插件自己的私有 emitter(同样开启 wildcard)
2566
+ const privateEmitter = new EventEmitter2({
2567
+ wildcard: true,
2568
+ delimiter: ':',
2569
+ newListener: false,
2570
+ maxListeners: 200,
2571
+ verboseMemoryLeak: true
2572
+ });
2573
+ const prefixed = event => `${namespace}:${event}`;
2574
+ return {
2575
+ // ── 私有事件(自动加 namespace 前缀)──────────────────────────
2576
+
2577
+ emit(event, payload) {
2578
+ privateEmitter.emit(prefixed(event), payload);
2579
+ },
2580
+ /**
2581
+ * 订阅私有事件,返回取消订阅函数。
2582
+ * 利用 EventEmitter2 的 Listener 对象的 .off() 方法,
2583
+ * 无需调用方保存 handler 引用。
2584
+ */
2585
+ on(event, handler) {
2586
+ const listener = privateEmitter.on(prefixed(event), handler, {
2587
+ objectify: true
2588
+ } // 返回 Listener 对象而非 emitter 本身
2589
+ );
2590
+ return () => listener.off();
2591
+ },
2592
+ off(event, handler) {
2593
+ privateEmitter.off(prefixed(event), handler);
2594
+ },
2595
+ /**
2596
+ * 订阅一次后自动取消
2597
+ */
2598
+ once(event, handler) {
2599
+ const listener = privateEmitter.once(prefixed(event), handler, {
2600
+ objectify: true
2601
+ });
2602
+ return () => listener.off();
2603
+ },
2604
+ // ── 全局事件(跨插件通信,走 globalEmitter)────────────────────
2605
+
2606
+ emitGlobal(event, payload) {
2607
+ globalEmitter.emit(event, payload);
2608
+ },
2609
+ /**
2610
+ * 订阅全局事件,支持通配符:
2611
+ * onGlobal('layout:*', fn) → 订阅所有 layout 事件
2612
+ * onGlobal('layout:panel-**', fn)→ 订阅所有 layout:panel 开头的事件
2613
+ * onGlobal('**', fn) → 订阅所有全局事件(慎用)
2614
+ */
2615
+ onGlobal(event, handler) {
2616
+ const listener = globalEmitter.on(event, handler, {
2617
+ objectify: true
2618
+ });
2619
+ return () => listener.off();
2620
+ },
2621
+ offGlobal(event, handler) {
2622
+ globalEmitter.off(event, handler);
2623
+ },
2624
+ onGlobalOnce(event, handler) {
2625
+ const listener = globalEmitter.once(event, handler, {
2626
+ objectify: true
2627
+ });
2628
+ return () => listener.off();
2629
+ },
2630
+ /**
2631
+ * 等待某个全局事件触发,返回 Promise(EventEmitter2 原生支持)
2632
+ * 适合插件 setup 中等待其他插件就绪的场景:
2633
+ * await ctx.event.waitForGlobal('explorer:ready', 5000)
2634
+ */
2635
+ waitForGlobal(event, timeoutMs) {
2636
+ return new Promise((resolve, reject) => {
2637
+ const timer = timeoutMs ? setTimeout(() => {
2638
+ globalEmitter.off(event, onEvent);
2639
+ reject(new Error(`[EventBus] Timeout waiting for "${event}" after ${timeoutMs}ms`));
2640
+ }, timeoutMs) : null;
2641
+ function onEvent(payload) {
2642
+ if (timer) clearTimeout(timer);
2643
+ resolve(payload);
2644
+ }
2645
+ globalEmitter.once(event, onEvent);
2646
+ });
2647
+ },
2648
+ // ── 清理(插件 destroy 时调用)─────────────────────────────────
2649
+
2650
+ /**
2651
+ * 移除该插件私有 emitter 上的所有监听器。
2652
+ * 全局监听器需要单独 offGlobal(插件应在 teardown 中手动清理)。
2653
+ */
2654
+ removeAllListeners() {
2655
+ privateEmitter.removeAllListeners();
2656
+ }
2657
+ };
2658
+ }
2659
+
2660
+ const zhCN = {
2661
+ panel: {
2662
+ viewMode: '视图模式',
2663
+ dockPinned: '停靠固定',
2664
+ dockUnpinned: '停靠不固定',
2665
+ undock: '取消停靠',
2666
+ help: '帮助',
2667
+ more: '更多',
2668
+ minimize: '最小化'
2669
+ }
2670
+ };
2671
+
2672
+ const enUS = {
2673
+ panel: {
2674
+ viewMode: 'View Mode',
2675
+ dockPinned: 'Dock Pinned',
2676
+ dockUnpinned: 'Dock Unpinned',
2677
+ undock: 'Undock',
2678
+ help: 'Help',
2679
+ more: 'More',
2680
+ minimize: 'Minimize'
2681
+ }
2682
+ };
2683
+
2684
+ const builtInLocales = {
2685
+ 'zh-CN': zhCN,
2686
+ 'en-US': enUS
2687
+ };
2688
+ function getBuiltInLocale(name) {
2689
+ const locale = builtInLocales[name];
2690
+ if (!locale) {
2691
+ console.warn(`[Layplux] Unknown locale "${name}", falling back to zh-CN`);
2692
+ return zhCN;
2693
+ }
2694
+ return locale;
2695
+ }
2696
+
2697
+ function _isSlot$2(s) {
2698
+ return typeof s === 'function' || Object.prototype.toString.call(s) === '[object Object]' && !vue.isVNode(s);
2699
+ }
2700
+ const viewModeKeys = new Set(['DockPinned', 'DockUnpinned', 'Undock']);
2701
+ function findItem(items, key) {
2702
+ if (!items) return;
2703
+ for (const item of items) {
2704
+ if (item.key === key) return item;
2705
+ if (item.children?.length) {
2706
+ const found = findItem(item.children, key);
2707
+ if (found) return found;
2708
+ }
2709
+ }
2710
+ }
2711
+ const PanelView = vue.defineComponent({
2712
+ name: 'PanelView',
2713
+ props: {
2714
+ anchor: String,
2715
+ title: String,
2716
+ widget: Object,
2717
+ menuItems: Array
2718
+ },
2719
+ setup(props, {
2720
+ slots
2721
+ }) {
2722
+ const panelRef = vue.ref();
2723
+ const defaultLocale = vue.ref(getBuiltInLocale('zh-CN'));
2724
+ const locale = vue.inject('layplux-locale', defaultLocale);
2725
+ const handleClick = key => {
2726
+ const widget = props.widget;
2727
+ widget?.event?.emitGlobal(`panel:${widget.name}:menu-click`, {
2728
+ widget,
2729
+ key
2730
+ });
2731
+ const widgetProps = widget?.config.props;
2732
+ const panelItems = widgetProps?.panelMenuItems;
2733
+ const panelItem = findItem(panelItems, key);
2734
+ if (panelItem?.onClick) {
2735
+ panelItem.onClick(key, widget);
2736
+ return;
2737
+ }
2738
+ if (viewModeKeys.has(key)) {
2739
+ widget?.pane.setViewMode(key);
2740
+ } else if (key === 'help') {
2741
+ widgetProps?.onHelpClick?.();
2742
+ }
2743
+ };
2744
+ function handlePanelClick() {
2745
+ props.widget?.focusable.active();
2746
+ }
2747
+ function renderItems(items, currentMode) {
2748
+ return items.map(item => {
2749
+ if (item.type === 'divider') {
2750
+ return vue.createVNode(DropdownDivider, {
2751
+ "key": item.key ?? 'divider'
2752
+ }, null);
2753
+ }
2754
+ const k = item.key ?? '';
2755
+ if (item.children?.length) {
2756
+ let _slot;
2757
+ return vue.createVNode(DropdownSubmenu, {
2758
+ "key": k,
2759
+ "title": item.label,
2760
+ "icon": item.icon,
2761
+ "getContainer": () => panelRef.value
2762
+ }, _isSlot$2(_slot = renderItems(item.children, currentMode)) ? _slot : {
2763
+ default: () => [_slot]
2764
+ });
2765
+ }
2766
+ const disabled = currentMode !== undefined && viewModeKeys.has(k) && currentMode === k;
2767
+ return vue.createVNode(DropdownItem, {
2768
+ "key": k,
2769
+ "eventKey": k,
2770
+ "disabled": disabled
2771
+ }, {
2772
+ default: () => [item.icon, vue.createTextVNode(" "), item.label]
2773
+ });
2774
+ });
2775
+ }
2776
+ return () => {
2777
+ const widget = props.widget;
2778
+ const currentMode = widget?.pane.viewMode.value;
2779
+ const widgetProps = widget?.config.props;
2780
+ const hasCustomItems = props.menuItems && props.menuItems.length > 0;
2781
+ const panelMenuItems = widgetProps?.panelMenuItems;
2782
+ const hasPanelMenuItems = panelMenuItems && panelMenuItems.length > 0;
2783
+ const showHelp = widgetProps?.showHelp !== false;
2784
+ const loc = locale.value.panel;
2785
+ const finalInnerItems = [{
2786
+ key: 'viewMode',
2787
+ label: loc.viewMode,
2788
+ children: [{
2789
+ key: 'DockPinned',
2790
+ label: loc.dockPinned
2791
+ }, {
2792
+ key: 'DockUnpinned',
2793
+ label: loc.dockUnpinned
2794
+ }, {
2795
+ key: 'Undock',
2796
+ label: loc.undock
2797
+ }]
2798
+ }, {
2799
+ type: 'divider'
2800
+ }, ...(showHelp ? [{
2801
+ key: 'help',
2802
+ label: loc.help
2803
+ }] : [])];
2804
+ const panelTitleExtra = widgetProps?.panelTitleExtra;
2805
+ const panelActionsExtra = widgetProps?.panelActionsExtra;
2806
+ return vue.createVNode("div", {
2807
+ "ref": panelRef,
2808
+ "id": widget?.id,
2809
+ "class": "layplux-panel",
2810
+ "onClick": handlePanelClick
2811
+ }, [vue.createVNode("div", {
2812
+ "class": "layplux-panel__header"
2813
+ }, [vue.createVNode("span", {
2814
+ "class": "layplux-panel__title"
2815
+ }, [props.title ?? widget?.name]), panelTitleExtra && createContent(panelTitleExtra), vue.createVNode("div", {
2816
+ "class": "layplux-panel__actions"
2817
+ }, [panelActionsExtra && createContent(panelActionsExtra), slots.actionsExtra?.(), vue.createVNode(Dropdown, {
2818
+ "trigger": "click",
2819
+ "placement": "bottom-start",
2820
+ "onClick": handleClick,
2821
+ "getContainer": () => panelRef.value
2822
+ }, {
2823
+ default: () => vue.createVNode("button", {
2824
+ "class": "layplux-panel__action-btn",
2825
+ "title": loc.more
2826
+ }, [vue.createVNode(MoreIcon, {
2827
+ "size": 16
2828
+ }, null)]),
2829
+ overlay: () => vue.createVNode(DropdownMenu, null, {
2830
+ default: () => [hasPanelMenuItems && renderItems(panelMenuItems), hasPanelMenuItems && hasCustomItems && vue.createVNode(DropdownDivider, null, null), hasCustomItems && renderItems(props.menuItems), (hasPanelMenuItems || hasCustomItems) && vue.createVNode(DropdownDivider, null, null), renderItems(finalInnerItems, currentMode)]
2831
+ })
2832
+ }), vue.createVNode("button", {
2833
+ "class": "layplux-panel__action-btn",
2834
+ "title": loc.minimize,
2835
+ "onClick": () => {
2836
+ widget?.event?.emitGlobal(`panel:${widget.name}:minimize`, {
2837
+ widget
2838
+ });
2839
+ widget?.container?.deactivate();
2840
+ }
2841
+ }, [vue.createVNode(MinimizeIcon, {
2842
+ "size": 16
2843
+ }, null)])])]), vue.createVNode("div", {
2844
+ "id": props.anchor,
2845
+ "class": "layplux-panel__body"
2846
+ }, null)]);
2847
+ };
2848
+ }
2849
+ });
2850
+
2851
+ const TitleView = vue.defineComponent({
2852
+ name: 'TitleView',
2853
+ inheritAttrs: false,
2854
+ props: {
2855
+ icon: [String, Object, Function],
2856
+ title: [String, Object, Function],
2857
+ mode: {
2858
+ type: String,
2859
+ default: 'icon-only'
2860
+ },
2861
+ /** 交互状态:idle / active / disabled / error。idle 时 hover 由 CSS :hover 处理 */
2862
+ state: {
2863
+ type: String,
2864
+ default: 'idle'
2865
+ },
2866
+ /** 聚焦/选中态,独立于 state,可与任何状态叠加 */
2867
+ focused: {
2868
+ type: Boolean,
2869
+ default: false
2870
+ },
2871
+ size: {
2872
+ type: String,
2873
+ default: 'middle'
2874
+ },
2875
+ className: {
2876
+ type: String,
2877
+ default: ''
2878
+ },
2879
+ onClick: Function
2880
+ },
2881
+ setup(props) {
2882
+ return () => {
2883
+ const {
2884
+ icon,
2885
+ title,
2886
+ mode,
2887
+ state,
2888
+ size,
2889
+ focused,
2890
+ className,
2891
+ onClick
2892
+ } = props;
2893
+ const iconNode = icon ? createContent(icon) : null;
2894
+ const titleNode = title ? createContent(title) : null;
2895
+ const classes = ['title-view', `title-view--${mode}`, `title-view--${state}`, `title-view--${size}`, focused && 'title-view--focused', className].filter(Boolean).join(' ');
2896
+ return vue.createVNode("span", {
2897
+ "class": classes,
2898
+ "onClick": onClick
2899
+ }, [vue.createVNode("span", {
2900
+ "class": "title-view__icon"
2901
+ }, [iconNode]), vue.createVNode("span", {
2902
+ "class": "title-view__label"
2903
+ }, [titleNode])]);
2904
+ };
2905
+ }
2906
+ });
2907
+
2908
+ /*
2909
+ * @Author: shuwen 1243889238@qq.com
2910
+ * @Date: 2026-06-08 16:12:13
2911
+ * @LastEditors: shuwen 1243889238@qq.com
2912
+ * @LastEditTime: 2026-06-09 16:58:03
2913
+ * @FilePath: /Layplux/packages/layplux/src/components/tooltip/index.tsx
2914
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
2915
+ */
2916
+ const Tooltip = vue.defineComponent({
2917
+ name: 'LaypluxTooltip',
2918
+ props: {
2919
+ title: [String, Object, Function],
2920
+ trigger: {
2921
+ type: String,
2922
+ default: 'hover'
2923
+ },
2924
+ placement: {
2925
+ type: String,
2926
+ default: 'top'
2927
+ },
2928
+ mouseEnterDelay: {
2929
+ type: Number,
2930
+ default: 100
2931
+ },
2932
+ mouseLeaveDelay: {
2933
+ type: Number,
2934
+ default: 100
2935
+ },
2936
+ visible: Boolean,
2937
+ disabled: {
2938
+ type: Boolean,
2939
+ default: false
2940
+ },
2941
+ getContainer: {
2942
+ type: Function,
2943
+ default: () => document.body
2944
+ }
2945
+ },
2946
+ emits: ['update:visible'],
2947
+ setup(props, {
2948
+ emit,
2949
+ slots
2950
+ }) {
2951
+ return () => vue.createVNode(Popup, {
2952
+ "visible": props.visible,
2953
+ "trigger": props.trigger,
2954
+ "placement": props.placement,
2955
+ "disabled": props.disabled,
2956
+ "mouseEnterDelay": props.mouseEnterDelay,
2957
+ "mouseLeaveDelay": props.mouseLeaveDelay,
2958
+ "destroyOnClose": true,
2959
+ "getContainer": props.getContainer,
2960
+ "onUpdate:visible": v => emit('update:visible', v)
2961
+ }, {
2962
+ default: () => slots.default?.(),
2963
+ content: () => {
2964
+ const hasContent = slots.content;
2965
+ const titleNode = hasContent ? slots.content?.() : createContent(props.title);
2966
+ return vue.createVNode("div", {
2967
+ "class": "layplux-tooltip"
2968
+ }, [vue.createVNode("div", {
2969
+ "class": "layplux-tooltip__arrow"
2970
+ }, null), vue.createVNode("div", {
2971
+ "class": "layplux-tooltip__inner"
2972
+ }, [titleNode])]);
2973
+ }
2974
+ });
2975
+ }
2976
+ });
2977
+
2978
+ const WidgetView = vue.defineComponent({
2979
+ name: 'WidgetView',
2980
+ inheritAttrs: false,
2981
+ props: {
2982
+ widget: Object
2983
+ },
2984
+ setup(props) {
2985
+ const hasError = vue.ref(false);
2986
+ const errorMessage = vue.ref('');
2987
+ vue.onErrorCaptured(err => {
2988
+ hasError.value = true;
2989
+ errorMessage.value = err.message;
2990
+ console.error(`[Layplux] Widget "${props.widget?.name}" crashed:`, err);
2991
+ return false;
2992
+ });
2993
+ return () => {
2994
+ const {
2995
+ widget
2996
+ } = props;
2997
+ if (hasError.value) {
2998
+ const fallback = widget?.config.props?.errorFallback;
2999
+ if (fallback) {
3000
+ return vue.h(fallback, {
3001
+ error: errorMessage.value,
3002
+ widget
3003
+ });
3004
+ }
3005
+ return vue.createVNode("div", {
3006
+ "class": "layplux-widget-error"
3007
+ }, [vue.createVNode("span", null, [vue.createTextVNode("\u7EC4\u4EF6 \""), widget?.name, vue.createTextVNode("\" \u53D1\u751F\u9519\u8BEF")]), vue.createVNode("pre", null, [errorMessage.value])]);
3008
+ }
3009
+ return vue.createVNode(vue.Fragment, null, [widget?.renderBody()]);
3010
+ };
3011
+ }
3012
+ });
3013
+ const WidgetTitleView = vue.defineComponent({
3014
+ name: 'WidgetTitleView',
3015
+ inheritAttrs: false,
3016
+ props: {
3017
+ widget: Object
3018
+ },
3019
+ setup(props) {
3020
+ const tooltipVisible = vue.ref(false);
3021
+ const handleClick = () => {
3022
+ tooltipVisible.value = false;
3023
+ props.widget?.container?.toggleActive(props.widget?.name);
3024
+ };
3025
+ return () => {
3026
+ const {
3027
+ widget
3028
+ } = props;
3029
+ const tooltipTitle = widget?.config.props?.title ?? widget?.name ?? '';
3030
+ return vue.createVNode("div", {
3031
+ "class": "widget-title-view"
3032
+ }, [vue.createVNode(Tooltip, {
3033
+ "visible": tooltipVisible.value,
3034
+ "onUpdate:visible": v => {
3035
+ tooltipVisible.value = v;
3036
+ },
3037
+ "title": tooltipTitle,
3038
+ "placement": "right",
3039
+ "mouseEnterDelay": 500,
3040
+ "getContainer": () => document.querySelector('.layplux-root') || document.body
3041
+ }, {
3042
+ default: () => [vue.createVNode(TitleView, {
3043
+ "onClick": handleClick,
3044
+ "focused": widget?.focused.value,
3045
+ "state": widget?.active.value ? 'active' : 'idle',
3046
+ "icon": widget?.config.props?.icon,
3047
+ "title": widget?.config.props?.title
3048
+ }, null)]
3049
+ })]);
3050
+ };
3051
+ }
3052
+ });
3053
+
3054
+ function _isSlot$1(s) {
3055
+ return typeof s === 'function' || Object.prototype.toString.call(s) === '[object Object]' && !vue.isVNode(s);
3056
+ }
3057
+ vue.defineComponent({
3058
+ name: 'CenterView',
3059
+ props: {
3060
+ widget: Object,
3061
+ anchor: {
3062
+ type: String,
3063
+ required: true
3064
+ }
3065
+ },
3066
+ setup(props) {
3067
+ return () => {
3068
+ let _slot;
3069
+ if (!props.widget) return null;
3070
+ return vue.createVNode(vue.Teleport, {
3071
+ "defer": true,
3072
+ "to": props.anchor
3073
+ }, _isSlot$1(_slot = props.widget.renderContent()) ? _slot : {
3074
+ default: () => [_slot]
3075
+ });
3076
+ };
3077
+ }
3078
+ });
3079
+
3080
+ function _isSlot(s) {
3081
+ return typeof s === 'function' || Object.prototype.toString.call(s) === '[object Object]' && !vue.isVNode(s);
3082
+ }
3083
+ const CenterArea = vue.defineComponent({
3084
+ name: 'CenterArea',
3085
+ props: {
3086
+ skeleton: Object,
3087
+ centerArea: Object
3088
+ },
3089
+ setup(props) {
3090
+ // ─── FocusTracker 全局挂载 ────────────────────────────────────────────
3091
+ // 监听 document click,点击面板外自动触发 onBlur(DockUnpinned 自动收起)
3092
+ let unmountFocusTracker = null;
3093
+ vue.onMounted(() => {
3094
+ unmountFocusTracker = props.skeleton?.focusTracker.mount(window) ?? null;
3095
+ });
3096
+ vue.onUnmounted(() => {
3097
+ unmountFocusTracker?.();
3098
+ });
3099
+
3100
+ // ─── 面板尺寸状态 ─────────────────────────────────────────────────────
3101
+ const leftWidth = vue.ref(340);
3102
+ const rightWidth = vue.ref(340);
3103
+ const bottomHeight = vue.ref(300);
3104
+
3105
+ // 上下 / 左右内部分割比例 (0~1)
3106
+ const leftSplitRatio = vue.ref(0.5);
3107
+ const rightSplitRatio = vue.ref(0.5);
3108
+ const bottomSplitRatio = vue.ref(0.5);
3109
+
3110
+ // ─── 通用拖拽 ─────────────────────────────────────────────────────────
3111
+ function startDrag(e, axis, onMove) {
3112
+ e.preventDefault();
3113
+ const startPos = axis === 'x' ? e.clientX : e.clientY;
3114
+ const onMouseMove = ev => onMove((axis === 'x' ? ev.clientX : ev.clientY) - startPos);
3115
+ const onMouseUp = () => {
3116
+ window.removeEventListener('mousemove', onMouseMove);
3117
+ window.removeEventListener('mouseup', onMouseUp);
3118
+ };
3119
+ window.addEventListener('mousemove', onMouseMove);
3120
+ window.addEventListener('mouseup', onMouseUp);
3121
+ }
3122
+
3123
+ // 左侧整体宽度
3124
+ function dragLeftWidth(e) {
3125
+ const base = leftWidth.value;
3126
+ startDrag(e, 'x', d => {
3127
+ leftWidth.value = Math.max(160, Math.min(600, base + d));
3128
+ });
3129
+ }
3130
+ // 右侧整体宽度(向左拖拽变宽,delta 取反)
3131
+ function dragRightWidth(e) {
3132
+ const base = rightWidth.value;
3133
+ startDrag(e, 'x', d => {
3134
+ rightWidth.value = Math.max(160, Math.min(600, base - d));
3135
+ });
3136
+ }
3137
+ // 底部整体高度(向上拖拽变高,delta 取反)
3138
+ function dragBottomHeight(e) {
3139
+ const base = bottomHeight.value;
3140
+ startDrag(e, 'y', d => {
3141
+ bottomHeight.value = Math.max(80, Math.min(600, base - d));
3142
+ });
3143
+ }
3144
+ // 左侧内部上下分割
3145
+ function dragLeftSplit(e, totalHeight) {
3146
+ const base = leftSplitRatio.value;
3147
+ startDrag(e, 'y', d => {
3148
+ leftSplitRatio.value = Math.max(0.15, Math.min(0.85, base + d / totalHeight));
3149
+ });
3150
+ }
3151
+ // 右侧内部上下分割
3152
+ function dragRightSplit(e, totalHeight) {
3153
+ const base = rightSplitRatio.value;
3154
+ startDrag(e, 'y', d => {
3155
+ rightSplitRatio.value = Math.max(0.15, Math.min(0.85, base + d / totalHeight));
3156
+ });
3157
+ }
3158
+ // 底部内部左右分割
3159
+ function dragBottomSplit(e, totalWidth) {
3160
+ const base = bottomSplitRatio.value;
3161
+ startDrag(e, 'x', d => {
3162
+ bottomSplitRatio.value = Math.max(0.15, Math.min(0.85, base + d / totalWidth));
3163
+ });
3164
+ }
3165
+
3166
+ // ─── 辅助 ─────────────────────────────────────────────────────────────
3167
+ function getActiveWidget(activeId) {
3168
+ if (!activeId) return null;
3169
+ return props.skeleton?.widgets.find(w => w.name === activeId) ?? null;
3170
+ }
3171
+ function isDocked(activeId) {
3172
+ const mode = getActiveWidget(activeId)?.pane.viewMode.value;
3173
+ return mode === 'DockPinned' || mode === 'DockUnpinned';
3174
+ }
3175
+
3176
+ // ─── 各侧 active widget ───────────────────────────────────────────────
3177
+ const leftTopWidget = vue.computed(() => getActiveWidget(props.skeleton?.leftTopArea.container.activeId.value ?? null));
3178
+ const leftBottomWidget = vue.computed(() => getActiveWidget(props.skeleton?.leftBottomArea.container.activeId.value ?? null));
3179
+ const rightTopWidget = vue.computed(() => getActiveWidget(props.skeleton?.rightTopArea.container.activeId.value ?? null));
3180
+ const rightBottomWidget = vue.computed(() => getActiveWidget(props.skeleton?.rightBottomArea.container.activeId.value ?? null));
3181
+ const bottomLeftWidget = vue.computed(() => getActiveWidget(props.skeleton?.bottomLeftArea.container.activeId.value ?? null));
3182
+ const bottomRightWidget = vue.computed(() => getActiveWidget(props.skeleton?.bottomRightArea.container.activeId.value ?? null));
3183
+
3184
+ // ─── 各面板 docked 可见性 ─────────────────────────────────────────────
3185
+ const isLeftTopVisible = vue.computed(() => isDocked(props.skeleton?.leftTopArea.container.activeId.value ?? null));
3186
+ const isLeftBottomVisible = vue.computed(() => isDocked(props.skeleton?.leftBottomArea.container.activeId.value ?? null));
3187
+ const isRightTopVisible = vue.computed(() => isDocked(props.skeleton?.rightTopArea.container.activeId.value ?? null));
3188
+ const isRightBottomVisible = vue.computed(() => isDocked(props.skeleton?.rightBottomArea.container.activeId.value ?? null));
3189
+ const isBottomLeftVisible = vue.computed(() => isDocked(props.skeleton?.bottomLeftArea.container.activeId.value ?? null));
3190
+ const isBottomRightVisible = vue.computed(() => isDocked(props.skeleton?.bottomRightArea.container.activeId.value ?? null));
3191
+
3192
+ // 整侧可见(有任意一个 docked 就显示侧栏容器)
3193
+ const isLeftVisible = vue.computed(() => isLeftTopVisible.value || isLeftBottomVisible.value);
3194
+ const isRightVisible = vue.computed(() => isRightTopVisible.value || isRightBottomVisible.value);
3195
+ const isBottomVisible = vue.computed(() => isBottomLeftVisible.value || isBottomRightVisible.value);
3196
+
3197
+ // ─── Undocked widget(每侧独立,从 focusedId 里找) ───────────────────
3198
+ function makeUndockedWidget(side) {
3199
+ return vue.computed(() => {
3200
+ const sk = props.skeleton;
3201
+ const w = getActiveWidget(sk?.focusedId.value ?? null);
3202
+ if (!w || w.pane.viewMode.value !== 'Undock') return null;
3203
+ const areaMap = {
3204
+ left: [sk?.leftTopArea, sk?.leftBottomArea],
3205
+ right: [sk?.rightTopArea, sk?.rightBottomArea],
3206
+ bottom: [sk?.bottomLeftArea, sk?.bottomRightArea]
3207
+ };
3208
+ const belongs = areaMap[side].some(a => a?.container.items.value.some(i => i.name === w.name));
3209
+ return belongs ? w : null;
3210
+ });
3211
+ }
3212
+ const leftUndockedWidget = makeUndockedWidget('left');
3213
+ const rightUndockedWidget = makeUndockedWidget('right');
3214
+ const bottomUndockedWidget = makeUndockedWidget('bottom');
3215
+ const isLeftUndockedVisible = vue.computed(() => leftUndockedWidget.value !== null);
3216
+ const isRightUndockedVisible = vue.computed(() => rightUndockedWidget.value !== null);
3217
+ const isBottomUndockedVisible = vue.computed(() => bottomUndockedWidget.value !== null);
3218
+
3219
+ // ─── Teleport 目标 map ────────────────────────────────────────────────
3220
+ const teleportTargets = vue.computed(() => {
3221
+ const sk = props.skeleton;
3222
+ const map = {};
3223
+ if (!sk) return map;
3224
+
3225
+ // widgetName -> 所属侧的 undocked 锚点(仅表达归属,不代表一定能传送过去)
3226
+ const sideIndex = new Map();
3227
+ sk.leftTopArea.container.items.value.forEach(w => sideIndex.set(w.name, '#left-undocked-area'));
3228
+ sk.leftBottomArea.container.items.value.forEach(w => sideIndex.set(w.name, '#left-undocked-area'));
3229
+ sk.rightTopArea.container.items.value.forEach(w => sideIndex.set(w.name, '#right-undocked-area'));
3230
+ sk.rightBottomArea.container.items.value.forEach(w => sideIndex.set(w.name, '#right-undocked-area'));
3231
+ sk.bottomLeftArea.container.items.value.forEach(w => sideIndex.set(w.name, '#bottom-undocked-area'));
3232
+ sk.bottomRightArea.container.items.value.forEach(w => sideIndex.set(w.name, '#bottom-undocked-area'));
3233
+
3234
+ // 每个 undocked 锚点当前唯一获得传送权的 widgetName
3235
+ // 规则:focusedId 优先;若 focusedId 不属于该侧则该侧无 undocked 显示
3236
+ const focusedName = sk.focusedId.value;
3237
+ const undockWinner = {
3238
+ '#left-undocked-area': null,
3239
+ '#right-undocked-area': null,
3240
+ '#bottom-undocked-area': null
3241
+ };
3242
+ if (focusedName) {
3243
+ const focusedWidget = sk.widgets.find(w => w.name === focusedName);
3244
+ if (focusedWidget?.pane.viewMode.value === 'Undock') {
3245
+ const anchor = sideIndex.get(focusedName);
3246
+ if (anchor) undockWinner[anchor] = focusedName;
3247
+ }
3248
+ }
3249
+
3250
+ // activeId -> docked 锚点
3251
+ const dockTargets = {
3252
+ [sk.leftTopArea.container.activeId.value ?? '']: '#left-top-area',
3253
+ [sk.leftBottomArea.container.activeId.value ?? '']: '#left-bottom-area',
3254
+ [sk.rightTopArea.container.activeId.value ?? '']: '#right-top-area',
3255
+ [sk.rightBottomArea.container.activeId.value ?? '']: '#right-bottom-area',
3256
+ [sk.bottomLeftArea.container.activeId.value ?? '']: '#bottom-left-area',
3257
+ [sk.bottomRightArea.container.activeId.value ?? '']: '#bottom-right-area'
3258
+ };
3259
+ delete dockTargets[''];
3260
+ sk.widgets.filter(w => w.type === 'panel').forEach(w => {
3261
+ if (w.pane.viewMode.value === 'Undock') {
3262
+ const anchor = sideIndex.get(w.name) ?? '#widget-offscreen';
3263
+ // 只有赢得该锚点的 widget 才能传送过去,其余保活在 offscreen
3264
+ map[w.name] = undockWinner[anchor] === w.name ? anchor : '#widget-offscreen';
3265
+ } else {
3266
+ map[w.name] = dockTargets[w.name] ?? '#widget-offscreen';
3267
+ }
3268
+ });
3269
+ return map;
3270
+ });
3271
+
3272
+ // ─── Center widget Teleport 目标 ──────────────────────────────────────
3273
+ const centerWidgetNames = vue.computed(() => {
3274
+ const names = new Set();
3275
+ props.centerArea?.container.items.value.forEach(w => names.add(w.name));
3276
+ return names;
3277
+ });
3278
+ const centerTargets = vue.computed(() => {
3279
+ const activeId = props.centerArea?.container.activeId.value ?? null;
3280
+ const map = {};
3281
+ props.centerArea?.container.items.value.forEach(w => {
3282
+ map[w.name] = w.name === activeId ? '#center-area' : '#center-offscreen';
3283
+ });
3284
+ return map;
3285
+ });
3286
+
3287
+ // ─── 内部分割高度 / 宽度(CSS calc 字符串) ───────────────────────────
3288
+ const leftTopHeight = vue.computed(() => `calc((100% - 4px) * ${leftSplitRatio.value})`);
3289
+ const leftBottomHeight = vue.computed(() => `calc((100% - 4px) * ${1 - leftSplitRatio.value})`);
3290
+ const rightTopHeight = vue.computed(() => `calc((100% - 4px) * ${rightSplitRatio.value})`);
3291
+ const rightBottomHeight = vue.computed(() => `calc((100% - 4px) * ${1 - rightSplitRatio.value})`);
3292
+ const bottomLeftWidth = vue.computed(() => `calc((100% - 4px) * ${bottomSplitRatio.value})`);
3293
+ const bottomRightWidth = vue.computed(() => `calc((100% - 4px) * ${1 - bottomSplitRatio.value})`);
3294
+ return () => {
3295
+ if (!props.skeleton) return null;
3296
+ const sk = props.skeleton;
3297
+ const leftBoth = isLeftTopVisible.value && isLeftBottomVisible.value;
3298
+ const rightBoth = isRightTopVisible.value && isRightBottomVisible.value;
3299
+ const bottomBoth = isBottomLeftVisible.value && isBottomRightVisible.value;
3300
+ return vue.createVNode("div", {
3301
+ "class": "layplux-center-area"
3302
+ }, [vue.createVNode("div", {
3303
+ "id": "widget-offscreen",
3304
+ "style": "display:none;"
3305
+ }, null), vue.createVNode("div", {
3306
+ "id": "center-offscreen",
3307
+ "style": "display:none;"
3308
+ }, null), sk.widgets.filter(w => w.type === 'panel' && !centerWidgetNames.value.has(w.name)).map(w => {
3309
+ let _slot;
3310
+ return vue.createVNode(vue.Teleport, {
3311
+ "defer": true,
3312
+ "key": w.name,
3313
+ "to": teleportTargets.value[w.name] ?? '#widget-offscreen'
3314
+ }, _isSlot(_slot = w.renderContent()) ? _slot : {
3315
+ default: () => [_slot]
3316
+ });
3317
+ }), props.centerArea?.container.items.value.map(w => {
3318
+ let _slot2;
3319
+ return vue.createVNode(vue.Teleport, {
3320
+ "defer": true,
3321
+ "key": w.name,
3322
+ "to": centerTargets.value[w.name] ?? '#center-offscreen'
3323
+ }, _isSlot(_slot2 = w.renderContent()) ? _slot2 : {
3324
+ default: () => [_slot2]
3325
+ });
3326
+ }), vue.withDirectives(vue.createVNode("div", {
3327
+ "class": "layplux-panel--undocked layplux-panel--undocked-left",
3328
+ "style": {
3329
+ width: `${leftWidth.value}px`
3330
+ }
3331
+ }, [vue.createVNode(PanelView, {
3332
+ "anchor": "left-undocked-area",
3333
+ "widget": leftUndockedWidget.value ?? undefined
3334
+ }, null), vue.createVNode("div", {
3335
+ "class": "layplux-resize-handle layplux-resize-handle--x layplux-resize-handle--edge-right",
3336
+ "onMousedown": dragLeftWidth
3337
+ }, null)]), [[vue.vShow, isLeftUndockedVisible.value]]), vue.withDirectives(vue.createVNode("div", {
3338
+ "class": "layplux-panel--undocked layplux-panel--undocked-right",
3339
+ "style": {
3340
+ width: `${rightWidth.value}px`
3341
+ }
3342
+ }, [vue.createVNode("div", {
3343
+ "class": "layplux-resize-handle layplux-resize-handle--x layplux-resize-handle--edge-left",
3344
+ "onMousedown": dragRightWidth
3345
+ }, null), vue.createVNode(PanelView, {
3346
+ "anchor": "right-undocked-area",
3347
+ "widget": rightUndockedWidget.value ?? undefined
3348
+ }, null)]), [[vue.vShow, isRightUndockedVisible.value]]), vue.withDirectives(vue.createVNode("div", {
3349
+ "class": "layplux-panel--undocked layplux-panel--undocked-bottom",
3350
+ "style": {
3351
+ height: `${bottomHeight.value}px`
3352
+ }
3353
+ }, [vue.createVNode("div", {
3354
+ "class": "layplux-resize-handle layplux-resize-handle--y layplux-resize-handle--edge-top",
3355
+ "onMousedown": dragBottomHeight
3356
+ }, null), vue.createVNode(PanelView, {
3357
+ "anchor": "bottom-undocked-area",
3358
+ "widget": bottomUndockedWidget.value ?? undefined
3359
+ }, null)]), [[vue.vShow, isBottomUndockedVisible.value]]), vue.createVNode("div", {
3360
+ "class": "layplux-center-area__main"
3361
+ }, [vue.withDirectives(vue.createVNode("div", {
3362
+ "class": "layplux-center-area__left",
3363
+ "style": {
3364
+ width: `${leftWidth.value}px`
3365
+ }
3366
+ }, [vue.createVNode("div", {
3367
+ "class": "layplux-center-area__docked-panels"
3368
+ }, [vue.withDirectives(vue.createVNode(PanelView, {
3369
+ "anchor": "left-top-area",
3370
+ "widget": leftTopWidget.value ?? undefined,
3371
+ "style": leftBoth ? {
3372
+ height: leftTopHeight.value,
3373
+ flex: 'none'
3374
+ } : {}
3375
+ }, null), [[vue.vShow, isLeftTopVisible.value]]), leftBoth && vue.createVNode("div", {
3376
+ "class": "layplux-resize-handle layplux-resize-handle--y",
3377
+ "onMousedown": e => dragLeftSplit(e, e.currentTarget.closest('.layplux-center-area__docked-panels').clientHeight)
3378
+ }, null), vue.withDirectives(vue.createVNode(PanelView, {
3379
+ "anchor": "left-bottom-area",
3380
+ "widget": leftBottomWidget.value ?? undefined,
3381
+ "style": leftBoth ? {
3382
+ height: leftBottomHeight.value,
3383
+ flex: 'none'
3384
+ } : {}
3385
+ }, null), [[vue.vShow, isLeftBottomVisible.value]])])]), [[vue.vShow, isLeftVisible.value]]), isLeftVisible.value && !isLeftUndockedVisible.value && vue.createVNode("div", {
3386
+ "class": "layplux-resize-handle layplux-resize-handle--x",
3387
+ "onMousedown": dragLeftWidth
3388
+ }, null), vue.createVNode("div", {
3389
+ "id": "center-area",
3390
+ "class": "layplux-center-area__editor"
3391
+ }, null), isRightVisible.value && !isRightUndockedVisible.value && vue.createVNode("div", {
3392
+ "class": "layplux-resize-handle layplux-resize-handle--x",
3393
+ "onMousedown": dragRightWidth
3394
+ }, null), vue.withDirectives(vue.createVNode("div", {
3395
+ "class": "layplux-center-area__right",
3396
+ "style": {
3397
+ width: `${rightWidth.value}px`
3398
+ }
3399
+ }, [vue.createVNode("div", {
3400
+ "class": "layplux-center-area__docked-panels"
3401
+ }, [vue.withDirectives(vue.createVNode(PanelView, {
3402
+ "anchor": "right-top-area",
3403
+ "widget": rightTopWidget.value ?? undefined,
3404
+ "style": rightBoth ? {
3405
+ height: rightTopHeight.value,
3406
+ flex: 'none'
3407
+ } : {}
3408
+ }, null), [[vue.vShow, isRightTopVisible.value]]), rightBoth && vue.createVNode("div", {
3409
+ "class": "layplux-resize-handle layplux-resize-handle--y",
3410
+ "onMousedown": e => dragRightSplit(e, e.currentTarget.closest('.layplux-center-area__docked-panels').clientHeight)
3411
+ }, null), vue.withDirectives(vue.createVNode(PanelView, {
3412
+ "anchor": "right-bottom-area",
3413
+ "widget": rightBottomWidget.value ?? undefined,
3414
+ "style": rightBoth ? {
3415
+ height: rightBottomHeight.value,
3416
+ flex: 'none'
3417
+ } : {}
3418
+ }, null), [[vue.vShow, isRightBottomVisible.value]])])]), [[vue.vShow, isRightVisible.value]])]), isBottomVisible.value && !isBottomUndockedVisible.value && vue.createVNode("div", {
3419
+ "class": "layplux-resize-handle layplux-resize-handle--y layplux-resize-handle--bottom-edge",
3420
+ "onMousedown": dragBottomHeight
3421
+ }, null), vue.withDirectives(vue.createVNode("div", {
3422
+ "class": "layplux-center-area__bottom",
3423
+ "style": {
3424
+ height: `${bottomHeight.value}px`
3425
+ }
3426
+ }, [vue.withDirectives(vue.createVNode(PanelView, {
3427
+ "anchor": "bottom-left-area",
3428
+ "widget": bottomLeftWidget.value ?? undefined,
3429
+ "style": bottomBoth ? {
3430
+ width: bottomLeftWidth.value,
3431
+ flex: 'none'
3432
+ } : {}
3433
+ }, null), [[vue.vShow, isBottomLeftVisible.value]]), bottomBoth && vue.createVNode("div", {
3434
+ "class": "layplux-resize-handle layplux-resize-handle--x",
3435
+ "onMousedown": e => dragBottomSplit(e, e.currentTarget.closest('.layplux-center-area__bottom').clientWidth)
3436
+ }, null), vue.withDirectives(vue.createVNode(PanelView, {
3437
+ "anchor": "bottom-right-area",
3438
+ "widget": bottomRightWidget.value ?? undefined,
3439
+ "style": bottomBoth ? {
3440
+ width: bottomRightWidth.value,
3441
+ flex: 'none'
3442
+ } : {}
3443
+ }, null), [[vue.vShow, isBottomRightVisible.value]])]), [[vue.vShow, isBottomVisible.value]])]);
3444
+ };
3445
+ }
3446
+ });
3447
+
3448
+ const Skeleton = vue.defineComponent({
3449
+ name: 'Skeleton',
3450
+ props: {
3451
+ skeleton: Object
3452
+ },
3453
+ setup(props) {
3454
+ return () => vue.createVNode("div", {
3455
+ "class": "layplux-skeleton"
3456
+ }, [vue.createVNode(TopArea, {
3457
+ "area": props.skeleton?.topArea
3458
+ }, null), vue.createVNode("div", {
3459
+ "class": "layplux-skeleton__body"
3460
+ }, [vue.createVNode("div", {
3461
+ "class": "layplux-skeleton__stripe"
3462
+ }, [vue.createVNode("div", {
3463
+ "class": "layplux-skeleton__stripe-top"
3464
+ }, [vue.createVNode(LeftTopArea, {
3465
+ "area": props.skeleton?.leftTopArea
3466
+ }, null), vue.createVNode("div", {
3467
+ "class": "layplux-skeleton__stripe-separator"
3468
+ }, null), vue.createVNode(LeftBottomArea, {
3469
+ "area": props.skeleton?.leftBottomArea
3470
+ }, null)]), vue.createVNode(BottomLeftArea, {
3471
+ "area": props.skeleton?.bottomLeftArea
3472
+ }, null)]), vue.createVNode("div", {
3473
+ "class": "layplux-skeleton__center"
3474
+ }, [vue.createVNode(CenterArea, {
3475
+ "skeleton": props.skeleton,
3476
+ "centerArea": props.skeleton?.centerArea
3477
+ }, null)]), vue.createVNode("div", {
3478
+ "class": "layplux-skeleton__stripe"
3479
+ }, [vue.createVNode("div", {
3480
+ "class": "layplux-skeleton__stripe-top"
3481
+ }, [vue.createVNode(RightTopArea, {
3482
+ "area": props.skeleton?.rightTopArea
3483
+ }, null), vue.createVNode("div", {
3484
+ "class": "layplux-skeleton__stripe-separator"
3485
+ }, null), vue.createVNode(RightBottomArea, {
3486
+ "area": props.skeleton?.rightBottomArea
3487
+ }, null)]), vue.createVNode(BottomRightArea, {
3488
+ "area": props.skeleton?.bottomRightArea
3489
+ }, null)])]), vue.createVNode(BottomArea, {
3490
+ "area": props.skeleton?.bottomArea
3491
+ }, null)]);
3492
+ }
3493
+ });
3494
+
3495
+ /**
3496
+ * Z 轴分层容器,把子组件分配到不同"层号",层号大的显示在上方。
3497
+ * 预设了五个层:DEFAULT(0)、PALETTE(100)、MODAL(200)、POPUP(300)、DRAG(400)。
3498
+ * 在此基础上拓展了自定义层号,用于管理弹出窗口(completion popup、快速文档)和拖拽反馈,
3499
+ * 从而避免每次弹窗都创建独立的 OS 窗口,大幅降低渲染开销
3500
+ */
3501
+ const LayeredManager = vue.defineComponent({
3502
+ name: 'LayeredManager',
3503
+ props: {
3504
+ skeleton: Object
3505
+ },
3506
+ setup(props) {
3507
+ return () => vue.createVNode("div", {
3508
+ "class": "layered-manager"
3509
+ }, [vue.createVNode(Skeleton, {
3510
+ "skeleton": props.skeleton
3511
+ }, null)]);
3512
+ }
3513
+ });
3514
+
3515
+ /**
3516
+ * 玻璃面板(GlassOverlay)是Layplux中的一个重要组件,它位于整个界面的最顶层,覆盖在所有其他内容之上。
3517
+ * 这个组件的主要作用是提供一个透明的层,用于捕获用户的交互事件,例如鼠标点击、拖动等。
3518
+ * 通过玻璃面板,Layplux能够实现一些特殊的交互效果,比如拖放操作、全局事件监听等。
3519
+ * 玻璃面板就像一层透明的保护膜,既能保护底层内容,又能提供丰富的交互功能,使得用户界面更加灵活和响应式。
3520
+ */
3521
+ const GlassOverlay = vue.defineComponent({
3522
+ name: 'GlassOverlay',
3523
+ setup() {
3524
+ return () => vue.createVNode("div", null, null);
3525
+ }
3526
+ });
3527
+
3528
+ const RootPane = vue.defineComponent({
3529
+ name: 'RootPane',
3530
+ props: {
3531
+ skeleton: Object
3532
+ },
3533
+ setup(props) {
3534
+ vue.provide('layplux-locale', props.skeleton?.locale);
3535
+ const rootClass = vue.computed(() => {
3536
+ const dark = props.skeleton?.isDark();
3537
+ return ['layplux-root', dark ? 'dark' : ''].filter(Boolean);
3538
+ });
3539
+ return () => vue.createVNode("div", {
3540
+ "class": rootClass.value,
3541
+ "data-theme": props.skeleton?.themeName?.value
3542
+ }, [vue.createVNode(CornerGlow, null, null), vue.createVNode(LayeredManager, {
3543
+ "skeleton": props.skeleton
3544
+ }, null), vue.createVNode(GlassOverlay, null, null)]);
3545
+ }
3546
+ });
3547
+
3548
+ const Layplux = vue.defineComponent({
3549
+ name: 'Layplux',
3550
+ props: {
3551
+ skeleton: Object
3552
+ },
3553
+ setup(props) {
3554
+ return () => vue.createVNode(RootPane, {
3555
+ "skeleton": props.skeleton
3556
+ }, {
3557
+ default: () => [vue.createTextVNode("Layplux")]
3558
+ });
3559
+ }
3560
+ });
3561
+ var layplux = Object.assign(Layplux, {
3562
+ install: app => {
3563
+ app.component('Layplux', Layplux);
3564
+ return app;
3565
+ }
3566
+ });
3567
+
3568
+ /**
3569
+ * `useArea` 只需要 skeleton 的 `createContainer` 能力,
3570
+ * 不依赖完整的 ISkeleton(避免创建时的循环依赖)。
3571
+ */
3572
+ function useArea(skeleton, name, handle) {
3573
+ const container = skeleton.createContainer(name, handle);
3574
+ function add(config) {
3575
+ const item = container.add(config);
3576
+ return item;
3577
+ }
3578
+ return {
3579
+ add,
3580
+ container
3581
+ };
3582
+ }
3583
+
3584
+ /**
3585
+ * 没个widget都会对应自己的pane的状态
3586
+ */
3587
+
3588
+ function usePane(defaultViewMode = 'DockPinned') {
3589
+ const viewMode = vue.ref(defaultViewMode);
3590
+ function setViewMode(mode) {
3591
+ viewMode.value = mode;
3592
+ }
3593
+ return {
3594
+ viewMode,
3595
+ setViewMode
3596
+ };
3597
+ }
3598
+
3599
+ function useWidget(config, container, skeleton) {
3600
+ const {
3601
+ name,
3602
+ props,
3603
+ type
3604
+ } = config;
3605
+ const active = vue.computed(() => container?.activeId.value === name);
3606
+ const focused = vue.computed(() => skeleton?.focusedId.value === name);
3607
+ const id = uniqueId(type);
3608
+ const align = props?.align ?? 'left';
3609
+ const pane = usePane();
3610
+
3611
+ // ─── Focusable 注册 ──────────────────────────────────────────────────────
3612
+ // range 初始为 () => false,PanelView 挂载后通过 focusable.setRange(el) 注入真实 DOM
3613
+ const focusable = skeleton.focusTracker.create({
3614
+ range: e => {
3615
+ const target = e.target;
3616
+ if (!target) {
3617
+ return false;
3618
+ }
3619
+ // 当点击的是panel时,激活
3620
+ const el = document.getElementById(id);
3621
+ if (el?.contains(target)) {
3622
+ return true;
3623
+ }
3624
+ // 当class中包含layplux-resize-handle则不失去焦点
3625
+ if (target.classList.contains('layplux-resize-handle')) {
3626
+ return true;
3627
+ }
3628
+ return false;
3629
+ },
3630
+ onActive: () => {
3631
+ widget.container?.activate(name);
3632
+ skeleton.event?.emitGlobal(`widget:${name}:focus`, {
3633
+ widget
3634
+ });
3635
+ },
3636
+ onBlur: () => {
3637
+ // 焦点离开 → 清除 focusedId
3638
+ skeleton.blur();
3639
+ skeleton.event?.emitGlobal(`widget:${name}:blur`, {
3640
+ widget
3641
+ });
3642
+ // DockUnpinned:失焦自动收起
3643
+ if (pane.viewMode.value === 'DockUnpinned' || pane.viewMode.value === 'Undock') {
3644
+ container?.deactivate();
3645
+ }
3646
+ }
3647
+ });
3648
+ function renderBody() {
3649
+ const {
3650
+ content,
3651
+ contentProps
3652
+ } = config;
3653
+ return createContent(content, {
3654
+ ...contentProps,
3655
+ config,
3656
+ event: widget.event
3657
+ });
3658
+ }
3659
+ function renderContent() {
3660
+ return vue.h(WidgetView, {
3661
+ key: id,
3662
+ widget
3663
+ });
3664
+ }
3665
+ function renderTitle() {
3666
+ return vue.h(WidgetTitleView, {
3667
+ key: id,
3668
+ widget
3669
+ });
3670
+ }
3671
+ const widget = {
3672
+ id,
3673
+ type,
3674
+ isWidget: true,
3675
+ name,
3676
+ align,
3677
+ config,
3678
+ active,
3679
+ focused,
3680
+ container,
3681
+ pane,
3682
+ focusable,
3683
+ event: skeleton.event,
3684
+ renderBody,
3685
+ renderContent,
3686
+ renderTitle
3687
+ };
3688
+ props?.onInit?.(widget);
3689
+
3690
+ // Emit view-mode-changed events
3691
+ if (skeleton?.event) {
3692
+ vue.watch(() => pane.viewMode.value, mode => {
3693
+ skeleton.event.emitGlobal(`widget:${name}:view-mode-changed`, {
3694
+ widget,
3695
+ mode
3696
+ });
3697
+ });
3698
+ }
3699
+ return widget;
3700
+ }
3701
+ function isWidget(obj) {
3702
+ return obj && obj.isWidget;
3703
+ }
3704
+
3705
+ /**
3706
+ * handle 函数签名:把原始 item(config 或 widget)转换成 widget 实例。
3707
+ * 第二个参数是所属 container 的引用,方便在创建 widget 时回引。
3708
+ */
3709
+
3710
+ /**
3711
+ * widget container 用于管理 widget 的添加、删除、获取等操作
3712
+ * T 为 widget 的类型
3713
+ * G 为 widgetconfig 的配置类型
3714
+ */
3715
+ function useWidgetContainer(handle, skeleton) {
3716
+ const maps = {};
3717
+ const items = vue.ref([]);
3718
+ const activeId = vue.ref(null); // ✅ 单一数据源
3719
+
3720
+ const self = {
3721
+ items,
3722
+ activeId,
3723
+ add,
3724
+ get,
3725
+ getAt,
3726
+ indexOf,
3727
+ remove,
3728
+ activate,
3729
+ deactivate,
3730
+ toggleActive
3731
+ };
3732
+ function add(item) {
3733
+ // 将config转换为widget,将创建widget的能力交给外部,并把 container 自身传出去
3734
+ const nItem = handle(item, self);
3735
+ const origin = get(nItem.name);
3736
+ if (origin === nItem) return origin;
3737
+ const i = origin ? items.value.indexOf(origin) : -1;
3738
+ if (i > -1) {
3739
+ items.value.splice(i, 1, nItem);
3740
+ } else {
3741
+ items.value.push(nItem);
3742
+ }
3743
+ maps[nItem.name] = nItem;
3744
+ return nItem;
3745
+ }
3746
+ function get(name) {
3747
+ return maps[name] || null;
3748
+ }
3749
+ function getAt(index) {
3750
+ return items.value[index] || null;
3751
+ }
3752
+ function indexOf(item) {
3753
+ return items.value.indexOf(item);
3754
+ }
3755
+ function remove(name) {
3756
+ const item = maps[name];
3757
+ if (!item) return null;
3758
+ const i = items.value.indexOf(item);
3759
+ if (i > -1) items.value.splice(i, 1);
3760
+ delete maps[name];
3761
+ skeleton.event.emitGlobal('skeleton:widget-removed', {
3762
+ name
3763
+ });
3764
+ return item;
3765
+ }
3766
+ function activate(id) {
3767
+ if (!maps[id]) return;
3768
+ activeId.value = id;
3769
+ skeleton.focus(id);
3770
+ maps[id].focusable.active(); // 面板激活 → 同步焦点栈
3771
+ skeleton.event.emitGlobal(`widget:${id}:activated`, {
3772
+ widget: maps[id]
3773
+ });
3774
+ }
3775
+ function deactivate() {
3776
+ const current = activeId.value;
3777
+ activeId.value = null;
3778
+ skeleton.blur();
3779
+ if (current && maps[current]) {
3780
+ maps[current].focusable.suspense(); // 面板收起 → 从焦点栈移除
3781
+ skeleton.event.emitGlobal(`widget:${current}:deactivated`, {
3782
+ widget: maps[current]
3783
+ });
3784
+ }
3785
+ }
3786
+ function toggleActive(id) {
3787
+ if (activeId.value === id) {
3788
+ deactivate();
3789
+ } else {
3790
+ activate(id);
3791
+ }
3792
+ }
3793
+ return self;
3794
+ }
3795
+
3796
+ /** 为指定 theme 注入 CSS 变量样式,重复注册会替换 */
3797
+ function injectThemeCSS(name, vars) {
3798
+ const styleId = `layplux-theme-${name}`;
3799
+ let styleEl = document.getElementById(styleId);
3800
+ if (!styleEl) {
3801
+ styleEl = document.createElement('style');
3802
+ styleEl.id = styleId;
3803
+ document.head.appendChild(styleEl);
3804
+ }
3805
+ const varLines = Object.entries(vars).map(([key, value]) => ` ${key}: ${value};`).join('\n');
3806
+ styleEl.textContent = `.layplux-root[data-theme='${name}'] {\n${varLines}\n}\n`;
3807
+ }
3808
+
3809
+ function useSkeleton() {
3810
+ const widgets = [];
3811
+ const self = {};
3812
+ const containers = new Map();
3813
+ const focusTracker = new FocusTracker();
3814
+ const event = createPluginEventBus('skeleton');
3815
+
3816
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
3817
+ const locale = vue.ref(getBuiltInLocale('zh-CN'));
3818
+ function setLocale(name) {
3819
+ locale.value = getBuiltInLocale(name);
3820
+ }
3821
+ const theme = vue.ref('system');
3822
+ const systemDark = vue.ref(typeof window !== 'undefined' ? window.matchMedia('(prefers-color-scheme: dark)').matches : false);
3823
+ function resolveTheme() {
3824
+ if (theme.value === 'system') {
3825
+ return systemDark.value ? 'dark' : 'light';
3826
+ }
3827
+ return theme.value;
3828
+ }
3829
+ function isDark() {
3830
+ return resolveTheme() === 'dark';
3831
+ }
3832
+ function setTheme(t) {
3833
+ theme.value = t;
3834
+ }
3835
+ const themeName = vue.ref('default');
3836
+ function setThemeName(name) {
3837
+ themeName.value = name;
3838
+ }
3839
+ function registerTheme(name, vars) {
3840
+ injectThemeCSS(name, vars);
3841
+ }
3842
+
3843
+ // 监听系统主题变化
3844
+ if (typeof window !== 'undefined') {
3845
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
3846
+ systemDark.value = e.matches;
3847
+ });
3848
+ }
3849
+
3850
+ // 顶部工具栏
3851
+ const topArea = useArea({
3852
+ createContainer
3853
+ }, 'topArea', (config, container) => createWidget(config, container));
3854
+
3855
+ // 底部状态栏
3856
+ const bottomArea = useArea({
3857
+ createContainer
3858
+ }, 'bottomArea', (config, container) => createWidget(config, container));
3859
+
3860
+ // 左侧顶部主区域
3861
+ const leftTopArea = useArea({
3862
+ createContainer
3863
+ }, 'leftTopArea', (config, container) => createWidget(config, container));
3864
+
3865
+ // 左侧底部快捷区域
3866
+ const leftBottomArea = useArea({
3867
+ createContainer
3868
+ }, 'leftBottomArea', (config, container) => createWidget(config, container));
3869
+
3870
+ // 右侧顶部主区域
3871
+ const rightTopArea = useArea({
3872
+ createContainer
3873
+ }, 'rightTopArea', (config, container) => createWidget(config, container));
3874
+
3875
+ // 右侧底部区域
3876
+ const rightBottomArea = useArea({
3877
+ createContainer
3878
+ }, 'rightBottomArea', (config, container) => createWidget(config, container));
3879
+
3880
+ // 右侧最底部快捷操作
3881
+ const bottomRightArea = useArea({
3882
+ createContainer
3883
+ }, 'bottomRightArea', (config, container) => createWidget(config, container));
3884
+
3885
+ // 左侧最底部快捷操作(交互型)
3886
+ const bottomLeftArea = useArea({
3887
+ createContainer
3888
+ }, 'bottomLeftArea', (config, container) => createWidget(config, container));
3889
+
3890
+ // 中心区域
3891
+ const centerArea = useArea({
3892
+ createContainer
3893
+ }, 'centerArea', (config, container) => createWidget(config, container));
3894
+ function createWidget(config, container) {
3895
+ if (isWidget(config)) {
3896
+ return config;
3897
+ }
3898
+ const widget = useWidget(config, container, self);
3899
+ widgets.push(widget);
3900
+ event.emitGlobal('skeleton:widget-added', {
3901
+ widget
3902
+ });
3903
+ return widget;
3904
+ }
3905
+ const focusedId = vue.ref(null);
3906
+ function toggleFocus(id) {
3907
+ if (focusedId.value === id) {
3908
+ blur();
3909
+ } else {
3910
+ focus(id);
3911
+ }
3912
+ }
3913
+ function focus(id) {
3914
+ focusedId.value = id;
3915
+ event.emitGlobal('skeleton:focus-changed', {
3916
+ focusedId: id
3917
+ });
3918
+ }
3919
+ function blur() {
3920
+ focusedId.value = null;
3921
+ event.emitGlobal('skeleton:focus-changed', {
3922
+ focusedId: null
3923
+ });
3924
+ }
3925
+ function add(config, extraConfig) {
3926
+ // TODO: 处理extraConfig
3927
+ if (extraConfig) {
3928
+ config = {
3929
+ ...config,
3930
+ ...extraConfig
3931
+ };
3932
+ }
3933
+ const {
3934
+ area
3935
+ } = config;
3936
+ if (area === 'topArea') {
3937
+ topArea.add(config);
3938
+ } else if (area === 'bottomArea') {
3939
+ bottomArea.add(config);
3940
+ } else if (area === 'leftTopArea') {
3941
+ leftTopArea.add(config);
3942
+ } else if (area === 'leftBottomArea') {
3943
+ leftBottomArea.add(config);
3944
+ } else if (area === 'bottomLeftArea') {
3945
+ bottomLeftArea.add(config);
3946
+ } else if (area === 'rightTopArea') {
3947
+ rightTopArea.add(config);
3948
+ } else if (area === 'rightBottomArea') {
3949
+ rightBottomArea.add(config);
3950
+ } else if (area === 'bottomRightArea') {
3951
+ bottomRightArea.add(config);
3952
+ } else if (area === 'centerArea') {
3953
+ centerArea.add(config);
3954
+ }
3955
+ }
3956
+ function createContainer(name, handle) {
3957
+ const container = useWidgetContainer(handle, self);
3958
+ containers.set(name, container);
3959
+ return container;
3960
+ }
3961
+
3962
+ // 4. 填充 self 的真正属性
3963
+ Object.assign(self, {
3964
+ widgets,
3965
+ topArea,
3966
+ bottomArea,
3967
+ leftTopArea,
3968
+ leftBottomArea,
3969
+ rightTopArea,
3970
+ rightBottomArea,
3971
+ bottomRightArea,
3972
+ bottomLeftArea,
3973
+ centerArea,
3974
+ focusedId,
3975
+ focusTracker,
3976
+ event,
3977
+ locale,
3978
+ setLocale,
3979
+ theme,
3980
+ resolveTheme,
3981
+ isDark,
3982
+ setTheme,
3983
+ themeName,
3984
+ setThemeName,
3985
+ registerTheme,
3986
+ toggleFocus,
3987
+ focus,
3988
+ blur,
3989
+ add,
3990
+ createContainer
3991
+ });
3992
+ return self;
3993
+ }
3994
+
3995
+ exports.FocusTracker = FocusTracker;
3996
+ exports.Layplux = layplux;
3997
+ exports.createPluginEventBus = createPluginEventBus;
3998
+ exports.useSkeleton = useSkeleton;
3999
+
4000
+ }));