1 | import { isRef, defineComponent, ref, computed, reactive, watch, onBeforeUnmount, provide, withDirectives, createVNode, vShow, Teleport, isVNode, nextTick, inject } from 'vue';
|
2 |
|
3 | var bind = function bind(el, binding) {
|
4 | var _binding$instance;
|
5 |
|
6 | var contextmenuKey = binding.arg;
|
7 |
|
8 | if (!contextmenuKey) {
|
9 | console.error("参数有误");
|
10 | return;
|
11 | }
|
12 |
|
13 | var contextmenuOptions = binding.value;
|
14 | var contextmenuRef = isRef(contextmenuKey) ? contextmenuKey.value : (_binding$instance = binding.instance) === null || _binding$instance === void 0 ? void 0 : _binding$instance.$refs[contextmenuKey];
|
15 |
|
16 | if (!contextmenuRef) {
|
17 | console.error("\u6CA1\u6709\u627E\u5230 ".concat(contextmenuKey, " \u5BF9\u5E94\u7684\u5B9E\u4F8B"));
|
18 | return;
|
19 | }
|
20 |
|
21 | if (typeof contextmenuRef.addReference !== "function") {
|
22 | console.error("".concat(contextmenuKey, " \u5BF9\u5E94\u7684\u5B9E\u4F8B\u4E0D\u662F VContextmenu"));
|
23 | return;
|
24 | }
|
25 |
|
26 | el.$contextmenuKey = contextmenuKey;
|
27 | contextmenuRef.addReference(el, contextmenuOptions);
|
28 | };
|
29 |
|
30 | var unbind = function unbind(el, binding) {
|
31 | var _binding$instance2;
|
32 |
|
33 | var contextmenuKey = el.$contextmenuKey;
|
34 | if (!contextmenuKey) return;
|
35 | var contextmenuRef = (_binding$instance2 = binding.instance) === null || _binding$instance2 === void 0 ? void 0 : _binding$instance2.$refs[contextmenuKey];
|
36 | contextmenuRef === null || contextmenuRef === void 0 ? void 0 : contextmenuRef.removeReference(el);
|
37 | };
|
38 |
|
39 | var rebind = function rebind(el, binding) {
|
40 | unbind(el, binding);
|
41 | bind(el, binding);
|
42 | };
|
43 |
|
44 | var contextmenuDirective = {
|
45 | mounted: bind,
|
46 | updated: rebind,
|
47 | beforeUnmount: unbind
|
48 | };
|
49 |
|
50 | var CLASSES = {
|
51 | contextmenu: "v-contextmenu",
|
52 |
|
53 | contextmenuIcon: "v-contextmenu-icon",
|
54 |
|
55 | contextmenuInner: "v-contextmenu-inner",
|
56 |
|
57 | contextmenuDivider: "v-contextmenu-divider",
|
58 |
|
59 | contextmenuItem: "v-contextmenu-item",
|
60 |
|
61 | contextmenuItemHover: "v-contextmenu-item--hover",
|
62 |
|
63 | contextmenuItemDisabled: "v-contextmenu-item--disabled",
|
64 |
|
65 | contextmenuGroup: "v-contextmenu-group",
|
66 |
|
67 | contextmenuGroupTitle: "v-contextmenu-group__title",
|
68 |
|
69 | contextmenuGroupMenus: "v-contextmenu-group__menus",
|
70 |
|
71 | contextmenuSubmenu: "v-contextmenu-submenu",
|
72 |
|
73 | contextmenuSubmenuTitle: "v-contextmenu-submenu__title",
|
74 |
|
75 | contextmenuSubmenuMenus: "v-contextmenu-submenu__menus",
|
76 |
|
77 | contextmenuSubmenuMenusTop: "v-contextmenu-submenu__menus--top",
|
78 |
|
79 | contextmenuSubmenuMenusRight: "v-contextmenu-submenu__menus--right",
|
80 |
|
81 | contextmenuSubmenuMenusBottom: "v-contextmenu-submenu__menus--bottom",
|
82 |
|
83 | contextmenuSubmenuMenusLeft: "v-contextmenu-submenu__menus--left",
|
84 |
|
85 | contextmenuSubmenuArrow: "v-contextmenu-submenu__arrow"
|
86 |
|
87 | };
|
88 |
|
89 | function _isSlot(s) {
|
90 | return typeof s === 'function' || Object.prototype.toString.call(s) === '[object Object]' && !isVNode(s);
|
91 | }
|
92 |
|
93 | var DEFAULT_REFERENCE_OPTIONS = {
|
94 | trigger: ["contextmenu"]
|
95 | };
|
96 | var Contextmenu = defineComponent({
|
97 | name: "VContextmenu",
|
98 | props: {
|
99 | modelValue: {
|
100 | type: Boolean,
|
101 | default: false
|
102 | },
|
103 | autoAjustPlacement: {
|
104 | type: Boolean,
|
105 | default: true
|
106 | },
|
107 | disabled: {
|
108 | type: Boolean,
|
109 | default: false
|
110 | },
|
111 | teleport: {
|
112 | type: [String, Object],
|
113 | default: function _default() {
|
114 | return "body";
|
115 | }
|
116 | }
|
117 |
|
118 |
|
119 |
|
120 |
|
121 | },
|
122 | emits: ["show", "hide", "update:modelValue"],
|
123 | setup: function setup(props, _ref) {
|
124 | var emit = _ref.emit;
|
125 | var contextmenuRef = ref(null);
|
126 | var visible = ref(props.modelValue || false);
|
127 |
|
128 | var toggle = function toggle(value) {
|
129 | visible.value = value;
|
130 | emit("update:modelValue", value);
|
131 | };
|
132 |
|
133 | var position = ref({
|
134 | top: 0,
|
135 | left: 0
|
136 | });
|
137 | var style = computed(function () {
|
138 | return {
|
139 | top: "".concat(position.value.top, "px"),
|
140 | left: "".concat(position.value.left, "px")
|
141 | };
|
142 | });
|
143 | var currentOptions = ref(null);
|
144 |
|
145 | var show = function show(evt, options) {
|
146 | var targetOptions = evt instanceof Event ? options : evt;
|
147 | var autoAjustPlacement = (targetOptions === null || targetOptions === void 0 ? void 0 : targetOptions.autoAjustPlacement) || props.autoAjustPlacement;
|
148 | var targetPosition = {
|
149 | top: (targetOptions === null || targetOptions === void 0 ? void 0 : targetOptions.top) || 0,
|
150 | left: (targetOptions === null || targetOptions === void 0 ? void 0 : targetOptions.left) || 0
|
151 | };
|
152 |
|
153 | if (evt instanceof Event) {
|
154 | var _targetOptions$top, _targetOptions$left;
|
155 |
|
156 | evt.preventDefault();
|
157 | targetPosition.top = (_targetOptions$top = targetOptions === null || targetOptions === void 0 ? void 0 : targetOptions.top) !== null && _targetOptions$top !== void 0 ? _targetOptions$top : evt.pageY;
|
158 | targetPosition.left = (_targetOptions$left = targetOptions === null || targetOptions === void 0 ? void 0 : targetOptions.left) !== null && _targetOptions$left !== void 0 ? _targetOptions$left : evt.pageX;
|
159 | }
|
160 |
|
161 | toggle(true);
|
162 | nextTick(function () {
|
163 | if (autoAjustPlacement) {
|
164 | var el = contextmenuRef.value;
|
165 | if (!el) return;
|
166 | var width = el.clientWidth;
|
167 | var height = el.clientHeight;
|
168 |
|
169 | if (height + targetPosition.top >= window.innerHeight + window.scrollY) {
|
170 | var targetTop = targetPosition.top - height;
|
171 |
|
172 | if (targetTop > window.scrollY) {
|
173 | targetPosition.top = targetTop;
|
174 | }
|
175 | }
|
176 |
|
177 | if (width + targetPosition.left >= window.innerWidth + window.scrollX) {
|
178 | var targetWidth = targetPosition.left - width;
|
179 |
|
180 | if (targetWidth > window.scrollX) {
|
181 | targetPosition.left = targetWidth;
|
182 | }
|
183 | }
|
184 | }
|
185 |
|
186 | position.value = targetPosition;
|
187 |
|
188 | emit("show");
|
189 | });
|
190 | };
|
191 |
|
192 | var hide = function hide() {
|
193 | currentOptions.value = null;
|
194 | toggle(false);
|
195 |
|
196 | emit("hide");
|
197 | };
|
198 |
|
199 | var references = reactive(new Map());
|
200 | var currentReference = ref();
|
201 | var currentReferenceOptions = computed(function () {
|
202 | return currentReference.value && references.get(currentReference.value);
|
203 | });
|
204 |
|
205 | var addReference = function addReference(el, options) {
|
206 | var triggers = function () {
|
207 | if (options !== null && options !== void 0 && options.trigger) {
|
208 | return Array.isArray(options.trigger) ? options.trigger : [options.trigger];
|
209 | }
|
210 |
|
211 | return DEFAULT_REFERENCE_OPTIONS.trigger;
|
212 | }();
|
213 |
|
214 | var handler = function handler(evt) {
|
215 | if (props.disabled) return;
|
216 | currentReference.value = el;
|
217 | show(evt, {});
|
218 | };
|
219 |
|
220 | triggers.forEach(function (eventType) {
|
221 | el.addEventListener(eventType, handler);
|
222 | });
|
223 | references.set(el, {
|
224 | triggers: triggers,
|
225 | handler: handler
|
226 | });
|
227 | };
|
228 |
|
229 | var removeReference = function removeReference(el) {
|
230 | var options = references.get(el);
|
231 | if (!options) return;
|
232 | options.triggers.forEach(function (eventType) {
|
233 | el.removeEventListener(eventType, options.handler);
|
234 | });
|
235 | references.delete(el);
|
236 | };
|
237 |
|
238 | var onBodyClick = function onBodyClick(evt) {
|
239 | if (!evt.target || !contextmenuRef.value || !currentReference.value) return;
|
240 | var notOutside = contextmenuRef.value.contains(evt.target) || currentReferenceOptions.value && currentReferenceOptions.value.triggers.includes("click") && currentReference.value.contains(evt.target);
|
241 |
|
242 | if (!notOutside) {
|
243 | toggle(false);
|
244 | }
|
245 | };
|
246 |
|
247 |
|
248 |
|
249 |
|
250 |
|
251 |
|
252 | watch(visible, function (value) {
|
253 | if (value) {
|
254 | document.addEventListener("click", onBodyClick);
|
255 | } else {
|
256 | document.removeEventListener("click", onBodyClick);
|
257 | }
|
258 | });
|
259 | onBeforeUnmount(function () {
|
260 | document.removeEventListener("click", onBodyClick);
|
261 | });
|
262 | provide("visible", visible);
|
263 | provide("autoAjustPlacement", props.autoAjustPlacement);
|
264 | provide("show", show);
|
265 | provide("hide", hide);
|
266 | return {
|
267 | visible: visible,
|
268 | style: style,
|
269 | currentReferenceOptions: currentReferenceOptions,
|
270 | currentOptions: currentOptions,
|
271 | contextmenuRef: contextmenuRef,
|
272 | addReference: addReference,
|
273 | removeReference: removeReference,
|
274 | toggle: toggle,
|
275 | show: show,
|
276 | hide: hide
|
277 | };
|
278 | },
|
279 | methods: {
|
280 | renderContent: function renderContent() {
|
281 | var _this$$slots$default, _this$$slots;
|
282 |
|
283 | return withDirectives(createVNode("div", {
|
284 | "class": CLASSES.contextmenu,
|
285 | "ref": "contextmenuRef",
|
286 | "style": this.style
|
287 | }, [createVNode("ul", {
|
288 | "class": CLASSES.contextmenuInner
|
289 | }, [(_this$$slots$default = (_this$$slots = this.$slots).default) === null || _this$$slots$default === void 0 ? void 0 : _this$$slots$default.call(_this$$slots, {
|
290 | triggerOptions: "currentReferenceOptions",
|
291 | options: "currentOptions"
|
292 | })])]), [[vShow, "visible"]]);
|
293 | }
|
294 | },
|
295 | render: function render() {
|
296 | var _slot;
|
297 |
|
298 | if (!this.visible) return null;
|
299 | return this.teleport ? createVNode(Teleport, {
|
300 | "to": this.teleport
|
301 | }, _isSlot(_slot = this.renderContent()) ? _slot : {
|
302 | default: function _default() {
|
303 | return [_slot];
|
304 | }
|
305 | }) : this.renderContent();
|
306 | }
|
307 | });
|
308 |
|
309 | function _defineProperty(obj, key, value) {
|
310 | if (key in obj) {
|
311 | Object.defineProperty(obj, key, {
|
312 | value: value,
|
313 | enumerable: true,
|
314 | configurable: true,
|
315 | writable: true
|
316 | });
|
317 | } else {
|
318 | obj[key] = value;
|
319 | }
|
320 |
|
321 | return obj;
|
322 | }
|
323 |
|
324 | var ContextmenuItem = defineComponent({
|
325 | name: "VContextmenuItem",
|
326 | props: {
|
327 | disabled: {
|
328 | type: Boolean,
|
329 | default: false
|
330 | },
|
331 | hideOnClick: {
|
332 | type: Boolean,
|
333 | default: true
|
334 | }
|
335 | },
|
336 | emits: ["click", "mouseenter", "mouseleave"],
|
337 | setup: function setup(props, _ref) {
|
338 | var emit = _ref.emit;
|
339 | var rootHide = inject("hide");
|
340 | var hover = ref(false);
|
341 | var classes = computed(function () {
|
342 | var _ref2;
|
343 |
|
344 | return _ref2 = {}, _defineProperty(_ref2, CLASSES.contextmenuItem, true), _defineProperty(_ref2, CLASSES.contextmenuItemDisabled, props.disabled), _defineProperty(_ref2, CLASSES.contextmenuItemHover, hover.value), _ref2;
|
345 | });
|
346 |
|
347 | var handleClick = function handleClick(evt) {
|
348 | if (props.disabled) return;
|
349 | emit("click", evt);
|
350 | props.hideOnClick && (rootHide === null || rootHide === void 0 ? void 0 : rootHide());
|
351 | };
|
352 |
|
353 | var handleMouseenter = function handleMouseenter(evt) {
|
354 | if (props.disabled) return;
|
355 | hover.value = true;
|
356 | emit("mouseenter", evt);
|
357 | };
|
358 |
|
359 | var handleMouseleave = function handleMouseleave(evt) {
|
360 | if (props.disabled) return;
|
361 | hover.value = false;
|
362 | emit("mouseleave", evt);
|
363 | };
|
364 |
|
365 | return {
|
366 | classes: classes,
|
367 | handleClick: handleClick,
|
368 | handleMouseenter: handleMouseenter,
|
369 | handleMouseleave: handleMouseleave
|
370 | };
|
371 | },
|
372 | render: function render() {
|
373 | var _this$$slots$default, _this$$slots;
|
374 |
|
375 | return createVNode("li", {
|
376 | "class": this.classes,
|
377 | "onClick": this.handleClick,
|
378 | "onMouseenter": this.handleMouseenter,
|
379 | "onMouseleave": this.handleMouseleave
|
380 | }, [(_this$$slots$default = (_this$$slots = this.$slots).default) === null || _this$$slots$default === void 0 ? void 0 : _this$$slots$default.call(_this$$slots)]);
|
381 | }
|
382 | });
|
383 |
|
384 | var ContextmenuDivider = defineComponent({
|
385 | name: "VContextmenuDivider",
|
386 | render: function render() {
|
387 | return createVNode("li", {
|
388 | "class": CLASSES.contextmenuDivider
|
389 | }, null);
|
390 | }
|
391 | });
|
392 |
|
393 | var ContextmenuIcon = defineComponent({
|
394 | name: "VContextmenuIcon",
|
395 | props: {
|
396 | name: {
|
397 | type: String,
|
398 | required: true
|
399 | }
|
400 | },
|
401 | render: function render() {
|
402 | return createVNode("i", {
|
403 | "class": [CLASSES.contextmenuIcon, "".concat(CLASSES.contextmenuIcon, "-").concat(this.name)]
|
404 | }, null);
|
405 | }
|
406 | });
|
407 |
|
408 | var ContextmenuSubmenu = defineComponent({
|
409 | name: "VContextmenuSubmenu",
|
410 | props: {
|
411 | title: {
|
412 | type: String,
|
413 | required: true
|
414 | },
|
415 | disabled: {
|
416 | type: Boolean,
|
417 | default: false
|
418 | }
|
419 | },
|
420 | emits: ["mouseenter", "mouseleave"],
|
421 | setup: function setup(props, _ref) {
|
422 | var emit = _ref.emit;
|
423 | var submenuRef = ref(null);
|
424 | var autoAjustPlacement = inject("autoAjustPlacement");
|
425 | var placements = ref(["top", "right"]);
|
426 | var hover = ref(false);
|
427 |
|
428 | var handleMouseenter = function handleMouseenter(evt) {
|
429 | if (props.disabled) return;
|
430 | hover.value = true;
|
431 | emit("mouseenter", evt);
|
432 | nextTick(function () {
|
433 | var targetPlacements = [];
|
434 |
|
435 | if (autoAjustPlacement) {
|
436 | var target = evt.target;
|
437 | var targetDimension = target.getBoundingClientRect();
|
438 | if (!submenuRef.value) return;
|
439 | var submenuWidth = submenuRef.value.clientWidth;
|
440 | var submenuHeight = submenuRef.value.clientHeight;
|
441 |
|
442 | if (targetDimension.right + submenuWidth >= window.innerWidth) {
|
443 | targetPlacements.push("left");
|
444 | } else {
|
445 | targetPlacements.push("right");
|
446 | }
|
447 |
|
448 | if (targetDimension.bottom + submenuHeight >= window.innerHeight) {
|
449 | targetPlacements.push("bottom");
|
450 | } else {
|
451 | targetPlacements.push("top");
|
452 | }
|
453 | }
|
454 |
|
455 | placements.value = targetPlacements;
|
456 | });
|
457 | };
|
458 |
|
459 | var handleMouseleave = function handleMouseleave(evt) {
|
460 | if (props.disabled) return;
|
461 | hover.value = false;
|
462 | emit("mouseleave", evt);
|
463 | };
|
464 |
|
465 | var titleClasses = computed(function () {
|
466 | var _ref2;
|
467 |
|
468 | return _ref2 = {}, _defineProperty(_ref2, CLASSES.contextmenuItem, true), _defineProperty(_ref2, CLASSES.contextmenuSubmenuTitle, true), _defineProperty(_ref2, CLASSES.contextmenuItemHover, hover.value), _defineProperty(_ref2, CLASSES.contextmenuItemDisabled, props.disabled), _ref2;
|
469 | });
|
470 | var menusClasses = computed(function () {
|
471 | var _ref3;
|
472 |
|
473 | return _ref3 = {}, _defineProperty(_ref3, CLASSES.contextmenu, true), _defineProperty(_ref3, CLASSES.contextmenuSubmenuMenus, true), _defineProperty(_ref3, CLASSES.contextmenuSubmenuMenusTop, placements.value.includes("top")), _defineProperty(_ref3, CLASSES.contextmenuSubmenuMenusRight, placements.value.includes("right")), _defineProperty(_ref3, CLASSES.contextmenuSubmenuMenusBottom, placements.value.includes("bottom")), _defineProperty(_ref3, CLASSES.contextmenuSubmenuMenusLeft, placements.value.includes("left")), _ref3;
|
474 | });
|
475 | return {
|
476 | hover: hover,
|
477 | submenuRef: submenuRef,
|
478 | titleClasses: titleClasses,
|
479 | menusClasses: menusClasses,
|
480 | handleMouseenter: handleMouseenter,
|
481 | handleMouseleave: handleMouseleave
|
482 | };
|
483 | },
|
484 | render: function render() {
|
485 | var _this$$slots$title, _this$$slots, _this$$slots$default, _this$$slots2;
|
486 |
|
487 | return createVNode("li", {
|
488 | "class": CLASSES.contextmenuSubmenu,
|
489 | "onMouseenter": this.handleMouseenter,
|
490 | "onMouseleave": this.handleMouseleave
|
491 | }, [createVNode("div", {
|
492 | "class": this.titleClasses
|
493 | }, [((_this$$slots$title = (_this$$slots = this.$slots).title) === null || _this$$slots$title === void 0 ? void 0 : _this$$slots$title.call(_this$$slots)) || this.title, createVNode("span", {
|
494 | "class": CLASSES.contextmenuSubmenuArrow
|
495 | }, [createVNode(ContextmenuIcon, {
|
496 | "name": "right-arrow"
|
497 | }, null)])]), this.hover ? createVNode("div", {
|
498 | "ref": "submenuRef",
|
499 | "class": this.menusClasses
|
500 | }, [createVNode("ul", {
|
501 | "class": CLASSES.contextmenuInner
|
502 | }, [(_this$$slots$default = (_this$$slots2 = this.$slots).default) === null || _this$$slots$default === void 0 ? void 0 : _this$$slots$default.call(_this$$slots2)])]) : null]);
|
503 | }
|
504 | });
|
505 |
|
506 | var ContextmenuGroup = defineComponent({
|
507 | name: "VContextmenuGroup",
|
508 | props: {
|
509 | title: {
|
510 | type: String,
|
511 | default: undefined
|
512 | },
|
513 | maxWidth: {
|
514 | type: [Number, String],
|
515 | default: undefined
|
516 | }
|
517 | },
|
518 | setup: function setup(props) {
|
519 | var style = computed(function () {
|
520 | if (!props.maxWidth) return;
|
521 | return {
|
522 | "max-width": typeof props.maxWidth === "number" ? "".concat(props.maxWidth, "px") : props.maxWidth,
|
523 | "overflow-x": "auto"
|
524 | };
|
525 | });
|
526 | return {
|
527 | style: style
|
528 | };
|
529 | },
|
530 | methods: {
|
531 | renderTitle: function renderTitle() {
|
532 | var _this$$slots$title, _this$$slots;
|
533 |
|
534 | var content = ((_this$$slots$title = (_this$$slots = this.$slots).title) === null || _this$$slots$title === void 0 ? void 0 : _this$$slots$title.call(_this$$slots)) || this.title;
|
535 | return content ? createVNode("div", {
|
536 | "class": CLASSES.contextmenuGroupTitle
|
537 | }, [content]) : null;
|
538 | }
|
539 | },
|
540 | render: function render() {
|
541 | var _this$$slots$default, _this$$slots2;
|
542 |
|
543 | return createVNode("li", {
|
544 | "class": CLASSES.contextmenuGroup
|
545 | }, [this.renderTitle(), createVNode("ul", {
|
546 | "style": this.style,
|
547 | "class": CLASSES.contextmenuGroupMenus
|
548 | }, [(_this$$slots$default = (_this$$slots2 = this.$slots).default) === null || _this$$slots$default === void 0 ? void 0 : _this$$slots$default.call(_this$$slots2)])]);
|
549 | }
|
550 | });
|
551 |
|
552 | var version = "3.0.0";
|
553 |
|
554 | var install = function install(app) {
|
555 | app.directive("contextmenu", contextmenuDirective);
|
556 | app.component(Contextmenu.name, Contextmenu);
|
557 | app.component(ContextmenuItem.name, ContextmenuItem);
|
558 | app.component(ContextmenuDivider.name, ContextmenuDivider);
|
559 | app.component(ContextmenuSubmenu.name, ContextmenuSubmenu);
|
560 | app.component(ContextmenuGroup.name, ContextmenuGroup);
|
561 | };
|
562 | var VContextmenu = {
|
563 | install: install,
|
564 | version: version
|
565 | };
|
566 |
|
567 | export default VContextmenu;
|
568 | export { Contextmenu, ContextmenuDivider, ContextmenuGroup, ContextmenuItem, ContextmenuSubmenu, contextmenuDirective as directive, install, version };
|