|
|
@@ -9,7 +9,7 @@ import type { ClassType } from '@vben-core/typings';
|
|
|
|
|
|
import type { IContextMenuItem } from './interface';
|
|
|
|
|
|
-import { computed } from 'vue';
|
|
|
+import { computed, onMounted, onUnmounted, ref } from 'vue';
|
|
|
|
|
|
import { useForwardPropsEmits } from 'reka-ui';
|
|
|
|
|
|
@@ -35,6 +35,14 @@ const props = defineProps<
|
|
|
|
|
|
const emits = defineEmits<ContextMenuRootEmits>();
|
|
|
|
|
|
+const NATIVE_CONTEXT_SELECTORS = [
|
|
|
+ 'input',
|
|
|
+ 'textarea',
|
|
|
+ 'select',
|
|
|
+ '[contenteditable]:not([contenteditable="false"])',
|
|
|
+ '.allow-native-context',
|
|
|
+].join(', ');
|
|
|
+
|
|
|
const delegatedProps = computed(() => {
|
|
|
const {
|
|
|
class: _cls,
|
|
|
@@ -59,12 +67,34 @@ function handleClick(menu: IContextMenuItem) {
|
|
|
}
|
|
|
menu?.handler?.(props.handlerData);
|
|
|
}
|
|
|
+
|
|
|
+const triggerRef = ref<HTMLElement | null>(null);
|
|
|
+
|
|
|
+function onContextMenuCapture(e: MouseEvent) {
|
|
|
+ if ((e.target as HTMLElement).closest(NATIVE_CONTEXT_SELECTORS)) {
|
|
|
+ e.stopPropagation();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ triggerRef.value?.addEventListener('contextmenu', onContextMenuCapture, {
|
|
|
+ capture: true,
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ triggerRef.value?.removeEventListener('contextmenu', onContextMenuCapture, {
|
|
|
+ capture: true,
|
|
|
+ });
|
|
|
+});
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
<ContextMenu v-bind="forwarded">
|
|
|
<ContextMenuTrigger as-child>
|
|
|
- <slot></slot>
|
|
|
+ <div ref="triggerRef">
|
|
|
+ <slot></slot>
|
|
|
+ </div>
|
|
|
</ContextMenuTrigger>
|
|
|
<ContextMenuContent
|
|
|
:class="contentClass"
|