@whitesev/pops 2.4.6 → 2.4.7
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.
- package/dist/index.amd.js +578 -571
- package/dist/index.amd.js.map +1 -1
- package/dist/index.cjs.js +578 -571
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +578 -571
- package/dist/index.esm.js.map +1 -1
- package/dist/index.iife.js +578 -571
- package/dist/index.iife.js.map +1 -1
- package/dist/index.system.js +578 -571
- package/dist/index.system.js.map +1 -1
- package/dist/index.umd.js +578 -571
- package/dist/index.umd.js.map +1 -1
- package/dist/types/src/types/PopsDOMUtilsEventType.d.ts +252 -252
- package/dist/types/src/types/animation.d.ts +19 -19
- package/dist/types/src/types/button.d.ts +187 -187
- package/dist/types/src/types/components.d.ts +210 -210
- package/dist/types/src/types/event.d.ts +63 -63
- package/dist/types/src/types/global.d.ts +25 -25
- package/dist/types/src/types/icon.d.ts +32 -32
- package/dist/types/src/types/inst.d.ts +24 -24
- package/dist/types/src/types/main.d.ts +111 -111
- package/dist/types/src/types/mask.d.ts +49 -49
- package/dist/types/src/types/position.d.ts +60 -60
- package/index.ts +3 -0
- package/package.json +4 -2
- package/src/Pops.ts +206 -0
- package/src/PopsAnimation.ts +32 -0
- package/src/PopsCSS.ts +51 -0
- package/src/PopsCore.ts +64 -0
- package/src/PopsIcon.ts +95 -0
- package/src/PopsInst.ts +21 -0
- package/src/components/alert/config.ts +62 -0
- package/src/components/alert/index.css +0 -0
- package/src/components/alert/index.ts +163 -0
- package/src/components/alert/types/index.ts +23 -0
- package/src/components/confirm/config.ts +90 -0
- package/src/components/confirm/index.css +0 -0
- package/src/components/confirm/index.ts +166 -0
- package/src/components/confirm/types/index.ts +17 -0
- package/src/components/drawer/config.ts +89 -0
- package/src/components/drawer/index.css +37 -0
- package/src/components/drawer/index.ts +237 -0
- package/src/components/drawer/types/index.ts +61 -0
- package/src/components/folder/config.ts +147 -0
- package/src/components/folder/folderIcon.ts +28 -0
- package/src/components/folder/index.css +303 -0
- package/src/components/folder/index.ts +929 -0
- package/src/components/folder/types/index.ts +97 -0
- package/src/components/iframe/config.ts +60 -0
- package/src/components/iframe/index.css +76 -0
- package/src/components/iframe/index.ts +334 -0
- package/src/components/iframe/types/index.ts +139 -0
- package/src/components/loading/config.ts +29 -0
- package/src/components/loading/index.css +66 -0
- package/src/components/loading/index.ts +99 -0
- package/src/components/loading/types/index.ts +34 -0
- package/src/components/panel/config.ts +519 -0
- package/src/components/panel/handlerComponents.ts +2900 -0
- package/src/components/panel/index.css +1222 -0
- package/src/components/panel/index.ts +207 -0
- package/src/components/panel/types/components-button.ts +68 -0
- package/src/components/panel/types/components-common.ts +50 -0
- package/src/components/panel/types/components-deepMenu.ts +84 -0
- package/src/components/panel/types/components-forms.ts +44 -0
- package/src/components/panel/types/components-input.ts +78 -0
- package/src/components/panel/types/components-own.ts +30 -0
- package/src/components/panel/types/components-select.ts +93 -0
- package/src/components/panel/types/components-selectMultiple.ts +130 -0
- package/src/components/panel/types/components-slider.ts +77 -0
- package/src/components/panel/types/components-switch.ts +56 -0
- package/src/components/panel/types/components-textarea.ts +68 -0
- package/src/components/panel/types/index.ts +177 -0
- package/src/components/prompt/config.ts +94 -0
- package/src/components/prompt/index.css +34 -0
- package/src/components/prompt/index.ts +216 -0
- package/src/components/prompt/types/index.ts +55 -0
- package/src/components/rightClickMenu/config.ts +98 -0
- package/src/components/rightClickMenu/index.css +112 -0
- package/src/components/rightClickMenu/index.ts +602 -0
- package/src/components/rightClickMenu/types/index.ts +97 -0
- package/src/components/searchSuggestion/config.ts +56 -0
- package/src/components/searchSuggestion/index.ts +856 -0
- package/src/components/searchSuggestion/types/index.ts +239 -0
- package/src/components/tooltip/config.ts +34 -0
- package/src/components/tooltip/index.css +199 -0
- package/src/components/tooltip/index.ts +604 -0
- package/src/components/tooltip/types/index.ts +117 -0
- package/src/config/CommonCSSClassName.ts +17 -0
- package/src/config/GlobalConfig.ts +63 -0
- package/src/css/animation.css +987 -0
- package/src/css/button.css +551 -0
- package/src/css/common.css +48 -0
- package/src/css/index.css +253 -0
- package/src/css/ninePalaceGridPosition.css +50 -0
- package/src/css/scrollbar.css +22 -0
- package/src/handler/PopsElementHandler.ts +304 -0
- package/src/handler/PopsHandler.ts +589 -0
- package/src/svg/arrowLeft.svg +4 -0
- package/src/svg/arrowRight.svg +4 -0
- package/src/svg/chromeFilled.svg +11 -0
- package/src/svg/circleClose.svg +8 -0
- package/src/svg/close.svg +5 -0
- package/src/svg/cpu.svg +8 -0
- package/src/svg/delete.svg +5 -0
- package/src/svg/documentCopy.svg +5 -0
- package/src/svg/edit.svg +8 -0
- package/src/svg/eleme.svg +5 -0
- package/src/svg/elemePlus.svg +5 -0
- package/src/svg/headset.svg +5 -0
- package/src/svg/hide.svg +8 -0
- package/src/svg/keyboard.svg +8 -0
- package/src/svg/loading.svg +5 -0
- package/src/svg/max.svg +5 -0
- package/src/svg/min.svg +5 -0
- package/src/svg/mise.svg +5 -0
- package/src/svg/monitor.svg +5 -0
- package/src/svg/next.svg +5 -0
- package/src/svg/picture.svg +8 -0
- package/src/svg/prev.svg +5 -0
- package/src/svg/search.svg +5 -0
- package/src/svg/share.svg +5 -0
- package/src/svg/upload.svg +5 -0
- package/src/svg/videoPause.svg +5 -0
- package/src/svg/videoPlay.svg +5 -0
- package/src/svg/view.svg +5 -0
- package/src/types/PopsDOMUtilsEventType.d.ts +252 -0
- package/src/types/animation.d.ts +19 -0
- package/src/types/button.d.ts +187 -0
- package/src/types/components.d.ts +210 -0
- package/src/types/event.d.ts +63 -0
- package/src/types/global.d.ts +25 -0
- package/src/types/icon.d.ts +32 -0
- package/src/types/inst.d.ts +24 -0
- package/src/types/main.d.ts +111 -0
- package/src/types/mask.d.ts +49 -0
- package/src/types/position.d.ts +60 -0
- package/src/utils/PopsDOMUtils.ts +2408 -0
- package/src/utils/PopsDOMUtilsEventsConfig.ts +4 -0
- package/src/utils/PopsInstanceUtils.ts +688 -0
- package/src/utils/PopsMathUtils.ts +71 -0
- package/src/utils/PopsSafeUtils.ts +22 -0
- package/src/utils/PopsUtils.ts +406 -0
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
import { OriginPrototype } from "../../PopsCore";
|
|
2
|
+
import { GlobalConfig } from "../../config/GlobalConfig";
|
|
3
|
+
import { PopsHandler } from "../../handler/PopsHandler";
|
|
4
|
+
import { popsDOMUtils } from "../../utils/PopsDOMUtils";
|
|
5
|
+
import { PopsSafeUtils } from "../../utils/PopsSafeUtils";
|
|
6
|
+
import { popsUtils } from "../../utils/PopsUtils";
|
|
7
|
+
import { rightClickMenuConfig as PopsRightClickMenuConfig } from "./config";
|
|
8
|
+
import type { PopsRightClickMenuDataDetails, PopsRightClickMenuDetails } from "./types";
|
|
9
|
+
import { PopsCSS } from "../../PopsCSS";
|
|
10
|
+
import { PopsIcon } from "../../PopsIcon";
|
|
11
|
+
import type { PopsType } from "../../types/main";
|
|
12
|
+
|
|
13
|
+
export const PopsRightClickMenu = {
|
|
14
|
+
init(details: PopsRightClickMenuDetails) {
|
|
15
|
+
const guid = popsUtils.getRandomGUID();
|
|
16
|
+
// 设置当前类型
|
|
17
|
+
const popsType: PopsType = "rightClickMenu";
|
|
18
|
+
|
|
19
|
+
let config = PopsRightClickMenuConfig();
|
|
20
|
+
config = popsUtils.assign(config, GlobalConfig.getGlobalConfig());
|
|
21
|
+
config = popsUtils.assign(config, details);
|
|
22
|
+
config = PopsHandler.handleOnly(popsType, config);
|
|
23
|
+
if (config.target == null) {
|
|
24
|
+
throw new Error("config.target 不能为空");
|
|
25
|
+
}
|
|
26
|
+
if (details.data) {
|
|
27
|
+
Reflect.set(config, "data", details.data);
|
|
28
|
+
}
|
|
29
|
+
const { $shadowContainer, $shadowRoot } = PopsHandler.handlerShadow(config);
|
|
30
|
+
PopsHandler.handleInit($shadowRoot, [
|
|
31
|
+
{
|
|
32
|
+
name: "index",
|
|
33
|
+
css: PopsCSS.index,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "anim",
|
|
37
|
+
css: PopsCSS.anim,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "common",
|
|
41
|
+
css: PopsCSS.common,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "rightClickMenu",
|
|
45
|
+
css: PopsCSS.rightClickMenu,
|
|
46
|
+
},
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
if (config.style != null) {
|
|
50
|
+
const cssNode = popsDOMUtils.createElement(
|
|
51
|
+
"style",
|
|
52
|
+
{
|
|
53
|
+
innerHTML: config.style,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
type: "text/css",
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
$shadowRoot.appendChild(cssNode);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const PopsContextMenu = {
|
|
63
|
+
/**
|
|
64
|
+
* 根元素
|
|
65
|
+
*/
|
|
66
|
+
rootElement: null as any as HTMLElement,
|
|
67
|
+
/**
|
|
68
|
+
* 全局点击检测
|
|
69
|
+
* @param event
|
|
70
|
+
*/
|
|
71
|
+
windowCheckClickEvent(event: MouseEvent | PointerEvent) {
|
|
72
|
+
if (!PopsContextMenu.rootElement) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const $click = event.target as HTMLElement;
|
|
76
|
+
if ($click.closest(`.pops-${popsType}`)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if ($click.className && $click.className === "pops-shadow-container" && $click.shadowRoot != null) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
PopsContextMenu.closeAllMenu(PopsContextMenu.rootElement);
|
|
83
|
+
},
|
|
84
|
+
/**
|
|
85
|
+
* target为shadowRoot或shadowRoot内的全局点击检测
|
|
86
|
+
* @param event
|
|
87
|
+
*/
|
|
88
|
+
shadowRootCheckClickEvent(event: MouseEvent | PointerEvent) {
|
|
89
|
+
if (!PopsContextMenu.rootElement) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const $click = event.target as HTMLElement;
|
|
93
|
+
if ($click.closest(`.pops-${popsType}`)) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
PopsContextMenu.closeAllMenu(PopsContextMenu.rootElement);
|
|
97
|
+
},
|
|
98
|
+
/**
|
|
99
|
+
* 添加全局点击检测事件
|
|
100
|
+
*/
|
|
101
|
+
addWindowCheckClickListener() {
|
|
102
|
+
popsDOMUtils.on(globalThis, "click touchstart", void 0, PopsContextMenu.windowCheckClickEvent, {
|
|
103
|
+
capture: true,
|
|
104
|
+
});
|
|
105
|
+
if (config.target instanceof Node) {
|
|
106
|
+
const $shadowRoot = config.target.getRootNode();
|
|
107
|
+
if ($shadowRoot instanceof ShadowRoot) {
|
|
108
|
+
popsDOMUtils.on($shadowRoot, "click touchstart", void 0, PopsContextMenu.shadowRootCheckClickEvent, {
|
|
109
|
+
capture: true,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
/**
|
|
115
|
+
* 移除全局点击检测事件
|
|
116
|
+
*/
|
|
117
|
+
removeWindowCheckClickListener() {
|
|
118
|
+
popsDOMUtils.off(globalThis, "click touchstart", void 0, PopsContextMenu.windowCheckClickEvent, {
|
|
119
|
+
capture: true,
|
|
120
|
+
});
|
|
121
|
+
if (config.target instanceof Node) {
|
|
122
|
+
const $shadowRoot = config.target.getRootNode();
|
|
123
|
+
if ($shadowRoot instanceof ShadowRoot) {
|
|
124
|
+
popsDOMUtils.off($shadowRoot, "click touchstart", void 0, PopsContextMenu.windowCheckClickEvent, {
|
|
125
|
+
capture: true,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
/**
|
|
131
|
+
* contextmenu事件
|
|
132
|
+
* @param event
|
|
133
|
+
* @param selectorTarget
|
|
134
|
+
*/
|
|
135
|
+
contextMenuEvent(event: PointerEvent, selectorTarget: HTMLElement) {
|
|
136
|
+
if (config.preventDefault) {
|
|
137
|
+
popsDOMUtils.preventEvent(event);
|
|
138
|
+
}
|
|
139
|
+
PopsHandler.handleOnly(popsType, config);
|
|
140
|
+
if (PopsContextMenu.rootElement) {
|
|
141
|
+
PopsContextMenu.closeAllMenu(PopsContextMenu.rootElement);
|
|
142
|
+
}
|
|
143
|
+
const rootElement = PopsContextMenu.showMenu(event, config.data, selectorTarget);
|
|
144
|
+
PopsContextMenu.rootElement = rootElement;
|
|
145
|
+
if (config.only) {
|
|
146
|
+
PopsHandler.handlePush(popsType, {
|
|
147
|
+
$shadowRoot: $shadowRoot,
|
|
148
|
+
$shadowContainer: $shadowContainer,
|
|
149
|
+
guid: guid,
|
|
150
|
+
animElement: rootElement,
|
|
151
|
+
popsElement: rootElement,
|
|
152
|
+
beforeRemoveCallBack(instCommonConfig) {
|
|
153
|
+
PopsContextMenu.closeAllMenu(instCommonConfig.popsElement);
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
/**
|
|
159
|
+
* 添加contextmenu事件
|
|
160
|
+
* @param target 目标
|
|
161
|
+
* @param selector 子元素选择器
|
|
162
|
+
*/
|
|
163
|
+
addContextMenuEvent(target: PopsRightClickMenuDetails["target"], selector?: string) {
|
|
164
|
+
popsDOMUtils.on(target!, "contextmenu", selector, PopsContextMenu.contextMenuEvent);
|
|
165
|
+
},
|
|
166
|
+
/**
|
|
167
|
+
* 移除contextmenu事件
|
|
168
|
+
* @param target 目标
|
|
169
|
+
* @param selector 子元素选择器
|
|
170
|
+
*/
|
|
171
|
+
removeContextMenuEvent(target: HTMLElement | typeof globalThis | Window, selector?: string) {
|
|
172
|
+
popsDOMUtils.off(target, "contextmenu", selector, PopsContextMenu.contextMenuEvent);
|
|
173
|
+
},
|
|
174
|
+
/**
|
|
175
|
+
* 自动判断是否存在动画,存在动画就执行关闭动画并删除
|
|
176
|
+
* @param $menu
|
|
177
|
+
*/
|
|
178
|
+
animationCloseMenu($menu: HTMLElement) {
|
|
179
|
+
/**
|
|
180
|
+
* 动画结束触发的事件
|
|
181
|
+
*/
|
|
182
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
183
|
+
const transitionEndEvent = (event: TransitionEvent) => {
|
|
184
|
+
popsDOMUtils.off($menu, popsDOMUtils.getTransitionEndNameList(), transitionEndEvent, {
|
|
185
|
+
capture: true,
|
|
186
|
+
});
|
|
187
|
+
$menu.remove();
|
|
188
|
+
};
|
|
189
|
+
popsDOMUtils.containsClassName;
|
|
190
|
+
if (popsDOMUtils.containsClassName($menu, `pops-${popsType}-anim-show`)) {
|
|
191
|
+
/* 有动画 */
|
|
192
|
+
popsDOMUtils.on($menu, popsDOMUtils.getTransitionEndNameList(), transitionEndEvent, {
|
|
193
|
+
capture: true,
|
|
194
|
+
});
|
|
195
|
+
popsDOMUtils.removeClassName($menu, `pops-${popsType}-anim-show`);
|
|
196
|
+
} else if (
|
|
197
|
+
popsDOMUtils.containsClassName($menu, `pops-${popsType}-anim-scale`) &&
|
|
198
|
+
popsDOMUtils.containsClassName($menu, `pops-${popsType}-anim-scale-open`)
|
|
199
|
+
) {
|
|
200
|
+
/* 有动画 */
|
|
201
|
+
popsDOMUtils.on($menu, popsDOMUtils.getTransitionEndNameList(), transitionEndEvent, {
|
|
202
|
+
capture: true,
|
|
203
|
+
});
|
|
204
|
+
popsDOMUtils.removeClassName($menu, `pops-${popsType}-anim-scale-open`);
|
|
205
|
+
popsDOMUtils.addClassName($menu, `pops-${popsType}-anim-scale-not-open`);
|
|
206
|
+
} else {
|
|
207
|
+
/* 无动画 */
|
|
208
|
+
$menu.remove();
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
/**
|
|
212
|
+
* 关闭所有菜单
|
|
213
|
+
* @param rootElement
|
|
214
|
+
*/
|
|
215
|
+
closeAllMenu(rootElement: HTMLElement) {
|
|
216
|
+
if (rootElement == null) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const rootElementMenuData = Reflect.get(rootElement, "__menuData__");
|
|
220
|
+
if (rootElementMenuData?.root) {
|
|
221
|
+
rootElement = rootElementMenuData.root;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const childMenuList = rootElementMenuData.child as HTMLElement[];
|
|
225
|
+
childMenuList.forEach((childMenuElement) => {
|
|
226
|
+
this.animationCloseMenu(childMenuElement);
|
|
227
|
+
});
|
|
228
|
+
this.animationCloseMenu(rootElement);
|
|
229
|
+
PopsContextMenu.rootElement = null as any;
|
|
230
|
+
},
|
|
231
|
+
/**
|
|
232
|
+
* 获取菜单容器
|
|
233
|
+
* @param isChildren 是否是rightClickMenu的某一项的子菜单
|
|
234
|
+
*/
|
|
235
|
+
createMenuContainerElement(isChildren: boolean) {
|
|
236
|
+
const $menu = popsDOMUtils.createElement("div", {
|
|
237
|
+
className: `pops-${popsType}`,
|
|
238
|
+
innerHTML: /*html*/ `<ul class="pops-${popsType}-wrapper"></ul>`,
|
|
239
|
+
});
|
|
240
|
+
const zIndex = this.getMenuZIndex();
|
|
241
|
+
if (zIndex > 10000) {
|
|
242
|
+
$menu.style.zIndex = zIndex.toString();
|
|
243
|
+
}
|
|
244
|
+
if (isChildren) {
|
|
245
|
+
$menu.setAttribute("is-children", "true");
|
|
246
|
+
}
|
|
247
|
+
/* 添加动画 */
|
|
248
|
+
if (config.isAnimation) {
|
|
249
|
+
popsDOMUtils.addClassName($menu, `pops-${popsType}-anim-grid`);
|
|
250
|
+
}
|
|
251
|
+
// 添加放大动画
|
|
252
|
+
if (config.useScaleAnimation) {
|
|
253
|
+
popsDOMUtils.addClassName($menu, `pops-${popsType}-anim-scale`);
|
|
254
|
+
popsDOMUtils.addClassName($menu, `pops-${popsType}-anim-scale-not-open`);
|
|
255
|
+
}
|
|
256
|
+
return $menu;
|
|
257
|
+
},
|
|
258
|
+
/**
|
|
259
|
+
* 动态获取配的z-index
|
|
260
|
+
*/
|
|
261
|
+
getMenuZIndex() {
|
|
262
|
+
return PopsHandler.handleZIndex(config.zIndex);
|
|
263
|
+
},
|
|
264
|
+
/**
|
|
265
|
+
* 获取left、top偏移
|
|
266
|
+
* @param menuElement 当前生成的菜单元素
|
|
267
|
+
* @param mousePosition 鼠标位置信息
|
|
268
|
+
* @param isMainMenu 是否是主菜单
|
|
269
|
+
*/
|
|
270
|
+
getOffset(
|
|
271
|
+
menuElement: HTMLElement,
|
|
272
|
+
mousePosition: { x: number; y: number },
|
|
273
|
+
parentInfo?: {
|
|
274
|
+
$menu: HTMLElement;
|
|
275
|
+
$parentItem: HTMLElement;
|
|
276
|
+
}
|
|
277
|
+
) {
|
|
278
|
+
const result = {
|
|
279
|
+
top: 0,
|
|
280
|
+
right: 0,
|
|
281
|
+
bottom: 0,
|
|
282
|
+
left: 0,
|
|
283
|
+
};
|
|
284
|
+
const menuElementWidth = popsDOMUtils.width(menuElement);
|
|
285
|
+
const menuElementHeight = popsDOMUtils.height(menuElement);
|
|
286
|
+
/**
|
|
287
|
+
* 限制的间隙距离
|
|
288
|
+
*/
|
|
289
|
+
const limitDistance = 1;
|
|
290
|
+
const maxPageLeftOffset = popsDOMUtils.width(globalThis) - limitDistance;
|
|
291
|
+
const maxPageTopOffset = popsDOMUtils.height(globalThis) - limitDistance;
|
|
292
|
+
/* left最大偏移 */
|
|
293
|
+
const maxLeftOffset = maxPageLeftOffset - menuElementWidth;
|
|
294
|
+
/* top最大偏移 */
|
|
295
|
+
const maxTopOffset = maxPageTopOffset - menuElementHeight;
|
|
296
|
+
|
|
297
|
+
const chileMenuLeftOrRightDistance = config.chileMenuLeftOrRightDistance;
|
|
298
|
+
const childMenuTopOrBottomDistance = config.childMenuTopOrBottomDistance;
|
|
299
|
+
let currentLeftOffset = mousePosition.x;
|
|
300
|
+
let currentTopOffset = mousePosition.y;
|
|
301
|
+
currentLeftOffset = currentLeftOffset < 0 ? 0 : currentLeftOffset;
|
|
302
|
+
// 不允许超出left最大值
|
|
303
|
+
if (currentLeftOffset + chileMenuLeftOrRightDistance >= maxLeftOffset) {
|
|
304
|
+
// 超过,那么子菜单将会在放在左边
|
|
305
|
+
// 偏移计算方式就是父菜单的右偏移+父菜单的宽度
|
|
306
|
+
if (parentInfo) {
|
|
307
|
+
// 子菜单
|
|
308
|
+
const mainMenuOffset = popsDOMUtils.offset(parentInfo.$menu);
|
|
309
|
+
currentLeftOffset = maxPageLeftOffset - mainMenuOffset.left - chileMenuLeftOrRightDistance + limitDistance;
|
|
310
|
+
} else {
|
|
311
|
+
// 主菜单 默认的
|
|
312
|
+
currentLeftOffset = limitDistance + chileMenuLeftOrRightDistance;
|
|
313
|
+
}
|
|
314
|
+
if (currentLeftOffset < 0) {
|
|
315
|
+
currentLeftOffset = 0;
|
|
316
|
+
} else if (currentLeftOffset > maxLeftOffset) {
|
|
317
|
+
currentLeftOffset = maxLeftOffset;
|
|
318
|
+
}
|
|
319
|
+
// 去除左偏移,变为右偏移
|
|
320
|
+
result.right = currentLeftOffset;
|
|
321
|
+
Reflect.deleteProperty(result, "left");
|
|
322
|
+
} else {
|
|
323
|
+
// 右边
|
|
324
|
+
currentLeftOffset = currentLeftOffset + chileMenuLeftOrRightDistance;
|
|
325
|
+
result.left = currentLeftOffset;
|
|
326
|
+
Reflect.deleteProperty(result, "right");
|
|
327
|
+
}
|
|
328
|
+
// 不允许超出top最大值
|
|
329
|
+
currentTopOffset = currentTopOffset < 0 ? 0 : currentTopOffset;
|
|
330
|
+
if (currentTopOffset + childMenuTopOrBottomDistance >= maxTopOffset) {
|
|
331
|
+
// 超过,那么子菜单将会在放在上面
|
|
332
|
+
if (parentInfo) {
|
|
333
|
+
// 以项的top偏移为基准
|
|
334
|
+
const parentItemOffset = popsDOMUtils.offset(parentInfo.$parentItem, false);
|
|
335
|
+
currentTopOffset =
|
|
336
|
+
maxPageTopOffset - parentItemOffset.bottom - childMenuTopOrBottomDistance + limitDistance;
|
|
337
|
+
} else {
|
|
338
|
+
currentTopOffset = limitDistance + childMenuTopOrBottomDistance;
|
|
339
|
+
}
|
|
340
|
+
if (currentTopOffset < 0) {
|
|
341
|
+
currentTopOffset = limitDistance;
|
|
342
|
+
} else if (currentTopOffset > maxTopOffset) {
|
|
343
|
+
currentTopOffset = maxTopOffset;
|
|
344
|
+
}
|
|
345
|
+
// 去除上偏移,变为下偏移
|
|
346
|
+
result.bottom = currentTopOffset;
|
|
347
|
+
Reflect.deleteProperty(result, "top");
|
|
348
|
+
} else {
|
|
349
|
+
currentTopOffset = currentTopOffset + childMenuTopOrBottomDistance;
|
|
350
|
+
result.top = currentTopOffset;
|
|
351
|
+
Reflect.deleteProperty(result, "bottom");
|
|
352
|
+
}
|
|
353
|
+
return result;
|
|
354
|
+
},
|
|
355
|
+
/**
|
|
356
|
+
* 显示菜单
|
|
357
|
+
* @param menuEvent 触发的事件
|
|
358
|
+
* @param _config_
|
|
359
|
+
* @param menuListenerRootNode 右键菜单监听的元素
|
|
360
|
+
*/
|
|
361
|
+
showMenu(menuEvent: PointerEvent, _config_: PopsRightClickMenuDataDetails[], menuListenerRootNode: HTMLElement) {
|
|
362
|
+
const menuElement = this.createMenuContainerElement(false);
|
|
363
|
+
Reflect.set(menuElement, "__menuData__", {
|
|
364
|
+
child: [],
|
|
365
|
+
});
|
|
366
|
+
// 添加子元素
|
|
367
|
+
PopsContextMenu.addMenuLiELement(menuEvent, menuElement, menuElement, _config_, menuListenerRootNode);
|
|
368
|
+
// 添加到页面
|
|
369
|
+
popsDOMUtils.append($shadowRoot, menuElement);
|
|
370
|
+
// 判断容器是否存在
|
|
371
|
+
if (!document.contains($shadowContainer)) {
|
|
372
|
+
if (typeof config.beforeAppendToPageCallBack === "function") {
|
|
373
|
+
config.beforeAppendToPageCallBack($shadowRoot, $shadowContainer);
|
|
374
|
+
}
|
|
375
|
+
popsDOMUtils.appendBody($shadowContainer);
|
|
376
|
+
}
|
|
377
|
+
this.handlerShowMenuCSS(menuElement, menuEvent);
|
|
378
|
+
return menuElement;
|
|
379
|
+
},
|
|
380
|
+
/**
|
|
381
|
+
* 显示子菜单
|
|
382
|
+
* @param menuEvent 事件
|
|
383
|
+
* @param posInfo 位置信息
|
|
384
|
+
* @param _config_
|
|
385
|
+
* @param rootElement 根菜单元素
|
|
386
|
+
* @param targetLiElement 父li项元素
|
|
387
|
+
* @param menuListenerRootNode 右键菜单监听的元素
|
|
388
|
+
*/
|
|
389
|
+
showClildMenu(
|
|
390
|
+
menuEvent: PointerEvent,
|
|
391
|
+
posInfo: {
|
|
392
|
+
clientX: number;
|
|
393
|
+
clientY: number;
|
|
394
|
+
},
|
|
395
|
+
_config_: PopsRightClickMenuDataDetails[],
|
|
396
|
+
rootElement: HTMLDivElement,
|
|
397
|
+
targetLiElement: HTMLLIElement,
|
|
398
|
+
menuListenerRootNode: HTMLElement
|
|
399
|
+
) {
|
|
400
|
+
const menuElement = this.createMenuContainerElement(true);
|
|
401
|
+
Reflect.set(menuElement, "__menuData__", {
|
|
402
|
+
parent: targetLiElement,
|
|
403
|
+
root: rootElement,
|
|
404
|
+
});
|
|
405
|
+
// 根菜单数据
|
|
406
|
+
const rootElementMenuData = Reflect.get(rootElement, "__menuData__");
|
|
407
|
+
rootElementMenuData.child.push(menuElement);
|
|
408
|
+
// 添加子元素
|
|
409
|
+
PopsContextMenu.addMenuLiELement(menuEvent, rootElement, menuElement, _config_, menuListenerRootNode);
|
|
410
|
+
// 添加到页面
|
|
411
|
+
popsDOMUtils.append($shadowRoot, menuElement);
|
|
412
|
+
const $parentMenu = targetLiElement.closest<HTMLElement>(".pops-rightClickMenu")!;
|
|
413
|
+
this.handlerShowMenuCSS(menuElement, posInfo, {
|
|
414
|
+
$menu: $parentMenu,
|
|
415
|
+
$parentItem: targetLiElement,
|
|
416
|
+
});
|
|
417
|
+
return menuElement;
|
|
418
|
+
},
|
|
419
|
+
/**
|
|
420
|
+
* 处理菜单显示的css样式(添加到页面后)
|
|
421
|
+
* @param $menu 菜单元素
|
|
422
|
+
* @param posInfo 菜单位置信息
|
|
423
|
+
* @param parentInfo 配置子菜单的父级信息
|
|
424
|
+
*/
|
|
425
|
+
handlerShowMenuCSS(
|
|
426
|
+
$menu: HTMLElement,
|
|
427
|
+
posInfo: {
|
|
428
|
+
clientX: number;
|
|
429
|
+
clientY: number;
|
|
430
|
+
},
|
|
431
|
+
parentInfo?: {
|
|
432
|
+
$menu: HTMLElement;
|
|
433
|
+
$parentItem: HTMLElement;
|
|
434
|
+
}
|
|
435
|
+
) {
|
|
436
|
+
const offset = this.getOffset(
|
|
437
|
+
$menu,
|
|
438
|
+
{
|
|
439
|
+
x: posInfo.clientX,
|
|
440
|
+
y: posInfo.clientY,
|
|
441
|
+
},
|
|
442
|
+
parentInfo
|
|
443
|
+
);
|
|
444
|
+
// 显示
|
|
445
|
+
popsDOMUtils.css($menu, {
|
|
446
|
+
...offset,
|
|
447
|
+
});
|
|
448
|
+
/* 过渡动画 */
|
|
449
|
+
if (config.isAnimation) {
|
|
450
|
+
popsDOMUtils.addClassName($menu, `pops-${popsType}-anim-show`);
|
|
451
|
+
}
|
|
452
|
+
if (config.useScaleAnimation) {
|
|
453
|
+
popsDOMUtils.removeClassName($menu, `pops-${popsType}-anim-scale-not-open`);
|
|
454
|
+
popsDOMUtils.addClassName($menu, `pops-${popsType}-anim-scale-open`);
|
|
455
|
+
}
|
|
456
|
+
},
|
|
457
|
+
/**
|
|
458
|
+
* 获取菜单项的元素
|
|
459
|
+
* @param menuEvent 事件
|
|
460
|
+
* @param rootElement 根元素
|
|
461
|
+
* @param menuElement 菜单元素
|
|
462
|
+
* @param _config_ 配置
|
|
463
|
+
* @param menuListenerRootNode 右键菜单监听的元素
|
|
464
|
+
*/
|
|
465
|
+
addMenuLiELement(
|
|
466
|
+
menuEvent: PointerEvent,
|
|
467
|
+
rootElement: HTMLDivElement,
|
|
468
|
+
menuElement: HTMLDivElement,
|
|
469
|
+
_config_: PopsRightClickMenuDataDetails[],
|
|
470
|
+
menuListenerRootNode: HTMLElement
|
|
471
|
+
) {
|
|
472
|
+
const menuEventTarget = menuEvent.target;
|
|
473
|
+
const menuULElement = menuElement.querySelector<HTMLUListElement>("ul")!;
|
|
474
|
+
_config_.forEach((item) => {
|
|
475
|
+
const menuLiElement = popsDOMUtils.parseTextToDOM<HTMLLIElement>(`<li></li>`);
|
|
476
|
+
/* 判断有无图标,有就添加进去 */
|
|
477
|
+
if (typeof item.icon === "string" && item.icon.trim() !== "") {
|
|
478
|
+
const iconSVGHTML = PopsIcon.getIcon(item.icon) ?? item.icon;
|
|
479
|
+
const iconElement = popsDOMUtils.parseTextToDOM(
|
|
480
|
+
/*html*/ `<i class="pops-${popsType}-icon" is-loading="${item.iconIsLoading ?? false}">${iconSVGHTML}</i>`
|
|
481
|
+
);
|
|
482
|
+
menuLiElement.appendChild(iconElement);
|
|
483
|
+
}
|
|
484
|
+
/* 插入文字 */
|
|
485
|
+
menuLiElement.insertAdjacentHTML("beforeend", PopsSafeUtils.getSafeHTML(`<span>${item.text}</span>`));
|
|
486
|
+
/* 如果存在子数据,显示 */
|
|
487
|
+
if (item.item && Array.isArray(item.item)) {
|
|
488
|
+
popsDOMUtils.addClassName(menuLiElement, `pops-${popsType}-item`);
|
|
489
|
+
}
|
|
490
|
+
/* 鼠标|触摸 移入事件 */
|
|
491
|
+
// 在移动端会先触发touchstart再然后mouseenter
|
|
492
|
+
let isTriggerTouchEvent = false;
|
|
493
|
+
/**
|
|
494
|
+
* 鼠标|触摸 移入事件
|
|
495
|
+
*/
|
|
496
|
+
function liElementHoverEvent(event: MouseEvent | TouchEvent) {
|
|
497
|
+
if (event.type === "touchstart") {
|
|
498
|
+
isTriggerTouchEvent = true;
|
|
499
|
+
}
|
|
500
|
+
if (isTriggerTouchEvent && event.type === "mouseenter") {
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
Array.from(menuULElement.children as any as HTMLLIElement[]).forEach((liElement) => {
|
|
504
|
+
popsDOMUtils.removeClassName(liElement, `pops-${popsType}-is-visited`);
|
|
505
|
+
const li_menuData = Reflect.get(liElement, "__menuData__");
|
|
506
|
+
if (!li_menuData) {
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
function removeElement(element: HTMLElement) {
|
|
510
|
+
element.querySelectorAll<HTMLLIElement>("ul li").forEach(($ele) => {
|
|
511
|
+
const menuData = Reflect.get($ele, "__menuData__");
|
|
512
|
+
if (menuData?.child) {
|
|
513
|
+
removeElement(menuData.child);
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
element.remove();
|
|
517
|
+
}
|
|
518
|
+
/* 遍历根元素的上的__menuData__.child,判断 */
|
|
519
|
+
removeElement(li_menuData.child);
|
|
520
|
+
});
|
|
521
|
+
/* 清理根元素上的children不存在于页面中的元素 */
|
|
522
|
+
const root_menuData = Reflect.get(rootElement, "__menuData__");
|
|
523
|
+
for (let index = 0; index < root_menuData.child.length; index++) {
|
|
524
|
+
const element = root_menuData.child[index];
|
|
525
|
+
if (!$shadowRoot.contains(element)) {
|
|
526
|
+
root_menuData.child.splice(index, 1);
|
|
527
|
+
index--;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
popsDOMUtils.addClassName(menuLiElement, `pops-${popsType}-is-visited`);
|
|
531
|
+
if (!item.item) {
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
const rect = menuLiElement.getBoundingClientRect();
|
|
535
|
+
const childMenu = PopsContextMenu.showClildMenu(
|
|
536
|
+
menuEvent,
|
|
537
|
+
{
|
|
538
|
+
clientX: rect.left + popsDOMUtils.outerWidth(menuLiElement),
|
|
539
|
+
clientY: rect.top,
|
|
540
|
+
},
|
|
541
|
+
item.item,
|
|
542
|
+
rootElement,
|
|
543
|
+
menuLiElement,
|
|
544
|
+
menuListenerRootNode
|
|
545
|
+
);
|
|
546
|
+
Reflect.set(menuLiElement, "__menuData__", {
|
|
547
|
+
child: childMenu,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* 点击事件
|
|
552
|
+
* @param clickEvent
|
|
553
|
+
*/
|
|
554
|
+
async function liElementClickEvent(clickEvent: MouseEvent | PointerEvent) {
|
|
555
|
+
if (typeof item.callback === "function") {
|
|
556
|
+
try {
|
|
557
|
+
OriginPrototype.Object.defineProperty(menuEvent, "target", {
|
|
558
|
+
get() {
|
|
559
|
+
return menuEventTarget;
|
|
560
|
+
},
|
|
561
|
+
});
|
|
562
|
+
} catch {
|
|
563
|
+
// 忽略
|
|
564
|
+
}
|
|
565
|
+
const callbackResult = await item.callback(
|
|
566
|
+
clickEvent as PointerEvent,
|
|
567
|
+
menuEvent,
|
|
568
|
+
menuLiElement,
|
|
569
|
+
menuListenerRootNode
|
|
570
|
+
);
|
|
571
|
+
if (typeof callbackResult === "boolean" && callbackResult == false) {
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
/* 取消绑定的鼠标/触摸事件,防止关闭的时候再次触发 */
|
|
576
|
+
Array.from(menuULElement.children as any as HTMLLIElement[]).forEach((liEle) => {
|
|
577
|
+
popsDOMUtils.off(liEle, "mouseenter touchstart");
|
|
578
|
+
});
|
|
579
|
+
PopsContextMenu.closeAllMenu(rootElement);
|
|
580
|
+
}
|
|
581
|
+
popsDOMUtils.on(menuLiElement, "mouseenter touchstart", liElementHoverEvent);
|
|
582
|
+
/* 项-点击事件 */
|
|
583
|
+
popsDOMUtils.on(menuLiElement, "click", liElementClickEvent);
|
|
584
|
+
menuULElement.appendChild(menuLiElement);
|
|
585
|
+
});
|
|
586
|
+
},
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
// 添加右键菜单事件
|
|
590
|
+
PopsContextMenu.addContextMenuEvent(config.target, config.targetSelector!);
|
|
591
|
+
// 添加全局点击检测
|
|
592
|
+
PopsContextMenu.addWindowCheckClickListener();
|
|
593
|
+
return {
|
|
594
|
+
guid: guid,
|
|
595
|
+
config: config,
|
|
596
|
+
removeWindowCheckClickListener: PopsContextMenu.removeWindowCheckClickListener,
|
|
597
|
+
addWindowCheckClickListener: PopsContextMenu.addWindowCheckClickListener,
|
|
598
|
+
removeContextMenuEvent: PopsContextMenu.removeContextMenuEvent,
|
|
599
|
+
addContextMenuEvent: PopsContextMenu.addContextMenuEvent,
|
|
600
|
+
};
|
|
601
|
+
},
|
|
602
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { PopsCommonConfig } from "../../../types/components";
|
|
2
|
+
import type { PopsIconType } from "../../../types/icon";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* pops.rightClickMenu的右键菜单配置
|
|
6
|
+
*/
|
|
7
|
+
export interface PopsRightClickMenuDataDetails {
|
|
8
|
+
/**
|
|
9
|
+
* svg图标,留空则是没图标
|
|
10
|
+
* @default ""
|
|
11
|
+
*/
|
|
12
|
+
icon?: PopsIconType | string;
|
|
13
|
+
/**
|
|
14
|
+
* 图标是否旋转
|
|
15
|
+
* @default false
|
|
16
|
+
*/
|
|
17
|
+
iconIsLoading?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* 文字
|
|
20
|
+
*/
|
|
21
|
+
text: string | (() => string);
|
|
22
|
+
/**
|
|
23
|
+
* 点击的回调函数
|
|
24
|
+
* @param clickEvent 点击菜单的click事件
|
|
25
|
+
* @param contextMenuEvent 触发的contextmenu事件
|
|
26
|
+
* @param liElement <li>元素
|
|
27
|
+
* @param menuListenerRootNode 右键菜单监听的元素
|
|
28
|
+
* @returns
|
|
29
|
+
* + true(默认) 关闭菜单
|
|
30
|
+
* + false 不关闭菜单
|
|
31
|
+
*
|
|
32
|
+
*/
|
|
33
|
+
callback?: (
|
|
34
|
+
clickEvent: PointerEvent,
|
|
35
|
+
contextMenuEvent: PointerEvent,
|
|
36
|
+
liElement: HTMLLIElement,
|
|
37
|
+
menuListenerRootNode: HTMLElement
|
|
38
|
+
) => boolean | void | Promise<boolean | void>;
|
|
39
|
+
/**
|
|
40
|
+
* 子项配置
|
|
41
|
+
*/
|
|
42
|
+
item?: PopsRightClickMenuDataDetails[] | null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* pops.rightClickMenu
|
|
47
|
+
*/
|
|
48
|
+
export interface PopsRightClickMenuDetails
|
|
49
|
+
extends Pick<PopsCommonConfig, "useShadowRoot" | "beforeAppendToPageCallBack" | "zIndex" | "style" | "only"> {
|
|
50
|
+
/**
|
|
51
|
+
* 目标元素
|
|
52
|
+
* @default document.documentElement
|
|
53
|
+
*/
|
|
54
|
+
target?: HTMLElement | Window | EventTarget | Node;
|
|
55
|
+
/**
|
|
56
|
+
* 目标的子元素选择器,默认为空
|
|
57
|
+
*/
|
|
58
|
+
targetSelector?: string | null;
|
|
59
|
+
/**
|
|
60
|
+
* 右键菜单数据
|
|
61
|
+
*/
|
|
62
|
+
data: PopsRightClickMenuDataDetails[];
|
|
63
|
+
/**
|
|
64
|
+
* 子菜单的左右偏移距离
|
|
65
|
+
* @default 0
|
|
66
|
+
*/
|
|
67
|
+
chileMenuLeftOrRightDistance?: number;
|
|
68
|
+
/**
|
|
69
|
+
* 子菜单的上下偏移距离
|
|
70
|
+
* @default 0
|
|
71
|
+
*/
|
|
72
|
+
childMenuTopOrBottomDistance?: number;
|
|
73
|
+
/**
|
|
74
|
+
* 自定义className,默认为空
|
|
75
|
+
* @default ""
|
|
76
|
+
*/
|
|
77
|
+
className?: string;
|
|
78
|
+
/**
|
|
79
|
+
* 是否启用动画,默认false
|
|
80
|
+
*
|
|
81
|
+
* 该动画为从上往下展开
|
|
82
|
+
* @default false
|
|
83
|
+
*/
|
|
84
|
+
isAnimation?: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* 是否使用打开动画,默认true
|
|
87
|
+
*
|
|
88
|
+
* 该动画为放大动画
|
|
89
|
+
* @default true
|
|
90
|
+
*/
|
|
91
|
+
useScaleAnimation?: boolean;
|
|
92
|
+
/**
|
|
93
|
+
* 是否阻止默认contextmenu事件
|
|
94
|
+
* @default false
|
|
95
|
+
*/
|
|
96
|
+
preventDefault?: boolean;
|
|
97
|
+
}
|