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