Parcourir la source

feat: refactor context menu to capture native events (#7858)

* feat: refactor context menu to capture native events

prevent context-menu to show in html input fields

* fix: refactor context-menu.vue for improved structure

* chore: fix format

* chore: remove dead code

* chore: fix lint

* fix: update contenteditable selector in context menu

proposed fixed by coderabitai
mew il y a 1 mois
Parent
commit
99c38c93c8

+ 32 - 2
packages/@core/ui-kit/shadcn-ui/src/components/context-menu/context-menu.vue

@@ -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"