-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(contextmenu): support contextmenu
- Loading branch information
Showing
14 changed files
with
334 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
--- | ||
title: Shadcn Context Menu | ||
--- | ||
|
||
# Introduction | ||
|
||
This document is mainly used to describe some features and usage of the ShadcnContextMenu component. | ||
|
||
- ShadcnContextMenu | ||
- ShadcnContextMenuItem | ||
|
||
## Usage | ||
|
||
::: raw | ||
|
||
<CodeRunner title="Usage"> | ||
<ShadcnContextMenu v-model="showMenu"> | ||
<template #trigger> | ||
<div class="w-full h-32 bg-gray-100 rounded-lg flex items-center justify-center"> | ||
Right click in this area to show menu | ||
</div> | ||
</template> | ||
<ShadcnContextMenuItem @click="onItemClick('edit')">Edit</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('delete')">Delete</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('share')">Share</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('move')">Move</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('copy')">Copy</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('print')">Print</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('duplicate')">Duplicate</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('duplicate-with-images-and-text')">Duplicate with images and text</ShadcnContextMenuItem> | ||
</ShadcnContextMenu> | ||
</CodeRunner> | ||
|
||
::: | ||
|
||
::: details Show code | ||
|
||
```vue | ||
<template> | ||
<ShadcnContextMenu v-model="showMenu"> | ||
<template #trigger> | ||
<div class="w-full h-64 bg-gray-100 rounded-lg flex items-center justify-center"> | ||
Right click in this area to show menu | ||
</div> | ||
</template> | ||
<ShadcnContextMenuItem @click="onItemClick('edit')">Edit</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('delete')">Delete</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('share')">Share</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('move')">Move</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('copy')">Copy</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('print')">Print</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('duplicate')">Duplicate</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('duplicate-with-images-and-text')">Duplicate with images and text</ShadcnContextMenuItem> | ||
</ShadcnContextMenu> | ||
</template> | ||
<script setup> | ||
import { ref } from 'vue' | ||
const showMenu = ref(false) | ||
const onItemClick = (action) => console.log(`Clicked: ${action}`) | ||
</script> | ||
``` | ||
|
||
::: | ||
|
||
## Context Menu Props | ||
|
||
<ApiTable title="Context Menu Props" | ||
:headers="['Attribute', 'Description', 'Type', 'Default Value', 'List']" | ||
:columns="[ | ||
['modelValue', 'The model value of the context menu', 'boolean', 'false', '-'], | ||
]"> | ||
</ApiTable> | ||
|
||
## Context Menu Events | ||
|
||
<ApiTable title="Context Menu Events" | ||
:headers="['Event', 'Description', 'Parameters']" | ||
:columns="[ | ||
['update:modelValue', 'Update the model value of the context menu', 'boolean'], | ||
['on-open', 'Emit when the context menu is opened', '-'], | ||
['on-close', 'Emit when the context menu is closed', '-'], | ||
]"> | ||
</ApiTable> | ||
|
||
<br /> | ||
|
||
<ApiTable title="Context Menu Item Events" | ||
:headers="['Event', 'Description', 'Parameters']" | ||
:columns="[ | ||
['on-click', 'Emit when the context menu item is clicked', '-'], | ||
]"> | ||
</ApiTable> | ||
|
||
## Context Menu Slots | ||
|
||
<ApiTable title="Context Menu Slots" | ||
:headers="['Slot', 'Description']" | ||
:columns="[ | ||
['trigger', 'The trigger slot of the context menu'], | ||
]"> | ||
</ApiTable> | ||
|
||
<script setup> | ||
import { ref } from 'vue' | ||
|
||
const showMenu = ref(false) | ||
|
||
const onItemClick = (action) => console.log(`Clicked: ${action}`) | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,28 @@ | ||
<template> | ||
<div class="p-32 space-y-2"> | ||
<div>Horizontal</div> | ||
<ShadcnDivider type="horizontal"/> | ||
<div class="flex space-x-2"> | ||
<div>Vertical</div> | ||
<ShadcnDivider type="vertical"/> | ||
<a href="#">Link</a> | ||
<ShadcnDivider type="vertical"/> | ||
<div>Vertical</div> | ||
</div> | ||
<div class="min-h-screen p-4"> | ||
<ShadcnContextMenu v-model="showMenu"> | ||
<template #trigger> | ||
<div class="w-full h-64 bg-gray-100 rounded-lg flex items-center justify-center"> | ||
Right click in this area to show menu | ||
</div> | ||
</template> | ||
|
||
<ShadcnDivider orientation="left">Left</ShadcnDivider> | ||
<ShadcnDivider orientation="center">Center</ShadcnDivider> | ||
<ShadcnDivider orientation="right">Right</ShadcnDivider> | ||
|
||
<ShadcnDivider dashed /> | ||
<ShadcnContextMenuItem @click="onItemClick('edit')">Edit</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('delete')">Delete</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('share')">Share</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('move')">Move</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('copy')">Copy</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('print')">Print</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('duplicate')">Duplicate</ShadcnContextMenuItem> | ||
<ShadcnContextMenuItem @click="onItemClick('duplicate-with-images-and-text')">Duplicate with images and text</ShadcnContextMenuItem> | ||
</ShadcnContextMenu> | ||
</div> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
<script setup> | ||
import { ref } from 'vue' | ||
const showMenu = ref(false) | ||
const onItemClick = (action) => console.log(`Clicked: ${action}`) | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// ShadcnContextMenu.vue | ||
<template> | ||
<div ref="triggerRef" @contextmenu.prevent="onContextMenu"> | ||
<slot name="trigger"/> | ||
</div> | ||
|
||
<Teleport to="body"> | ||
<div v-if="modelValue" | ||
ref="menuRef" | ||
class="fixed min-w-[8rem] z-50 bg-white rounded-md shadow-lg border border-gray-200 p-1" | ||
:style="menuStyle"> | ||
<slot/> | ||
</div> | ||
</Teleport> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { computed, defineEmits, onMounted, onUnmounted, provide, ref } from 'vue' | ||
import { ContextMenuEmits, ContextMenuProps } from './types' | ||
import { calcSize } from '@/utils/common.ts' | ||
const emit = defineEmits<ContextMenuEmits>() | ||
const props = withDefaults(defineProps<ContextMenuProps>(), { | ||
modelValue: false | ||
}) | ||
const menuPosition = ref({ x: 0, y: 0 }) | ||
const menuRef = ref<HTMLElement | null>(null) | ||
const triggerRef = ref<HTMLElement | null>(null) | ||
// Calculate the position of the menu, handle boundary cases | ||
const menuStyle = computed(() => { | ||
if (!menuRef.value) { | ||
return { | ||
left: calcSize(menuPosition.value.x), | ||
top: calcSize(menuPosition.value.y) | ||
} | ||
} | ||
const menuRect = menuRef.value.getBoundingClientRect() | ||
const menuWidth = menuRect.width | ||
const menuHeight = menuRect.height | ||
// Get the window size | ||
const viewportWidth = window.innerWidth | ||
const viewportHeight = window.innerHeight | ||
// Calculate the final position | ||
let x = menuPosition.value.x | ||
let y = menuPosition.value.y | ||
// Handle the right boundary | ||
if (x + menuWidth > viewportWidth) { | ||
x = viewportWidth - menuWidth - 10 | ||
} | ||
if (x < 0) { | ||
x = 8 | ||
} | ||
if (y + menuHeight > viewportHeight) { | ||
y = viewportHeight - menuHeight - 8 | ||
} | ||
if (y < 0) { | ||
y = 8 | ||
} | ||
return { | ||
left: calcSize(x), | ||
top: calcSize(y) | ||
} | ||
}) | ||
provide('menuPosition', menuPosition) | ||
const closeMenu = () => { | ||
emit('update:modelValue', false) | ||
emit('on-close', false) | ||
} | ||
provide('closeMenu', closeMenu) | ||
// Handle right-click events | ||
const onContextMenu = (event) => { | ||
event.preventDefault() | ||
menuPosition.value = { | ||
x: event.clientX, | ||
y: event.clientY | ||
} | ||
emit('update:modelValue', true) | ||
emit('on-open', true) | ||
} | ||
// Handle clicking on the external close menu | ||
const onClickOutside = (event) => { | ||
if (menuRef.value && !menuRef.value.contains(event.target)) { | ||
emit('update:modelValue', false) | ||
emit('on-close', false) | ||
} | ||
} | ||
const handleResize = () => { | ||
if (props.modelValue) { | ||
closeMenu() | ||
} | ||
} | ||
onMounted(() => { | ||
document.addEventListener('click', onClickOutside) | ||
window.addEventListener('resize', handleResize) | ||
}) | ||
onUnmounted(() => { | ||
document.removeEventListener('click', onClickOutside) | ||
window.removeEventListener('resize', handleResize) | ||
}) | ||
</script> |
Oops, something went wrong.