diff --git a/docs/pages/examples.vue b/docs/pages/examples.vue index d09cf6fe..baf704e4 100644 --- a/docs/pages/examples.vue +++ b/docs/pages/examples.vue @@ -165,6 +165,20 @@ +
+
+ Context menu: +
+ + + + + Menu + + + +
+
Command palette: @@ -266,6 +280,32 @@ const form = reactive({ const { $toast } = useNuxtApp() +const x = ref(0) +const y = ref(0) +const isContextMenuOpen = ref(false) +const contextMenuRef = ref(null) + +onMounted(() => { + document.addEventListener('mousemove', ({ clientX, clientY }) => { + x.value = clientX + y.value = clientY + }) +}) + +const virtualElement = computed(() => ({ + getBoundingClientRect () { + return { + width: 0, + height: 0, + top: y.value, + right: x.value, + bottom: y.value, + left: x.value + } + }, + contextElement: contextMenuRef.value?.$el +})) + const customQuery = query => computed(() => query.value ? `${query.value} | =1` : '') function toggleModalIsOpen () { diff --git a/src/runtime/components/overlays/ContextMenu.vue b/src/runtime/components/overlays/ContextMenu.vue new file mode 100644 index 00000000..d6608ebd --- /dev/null +++ b/src/runtime/components/overlays/ContextMenu.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/src/runtime/composables/usePopper.ts b/src/runtime/composables/usePopper.ts index f2b97b5d..b18b0f79 100644 --- a/src/runtime/composables/usePopper.ts +++ b/src/runtime/composables/usePopper.ts @@ -1,11 +1,13 @@ import { ref, onMounted, watchEffect } from 'vue' +import type { Ref } from 'vue' import { popperGenerator, defaultModifiers } from '@popperjs/core/lib/popper-lite' +import type { Instance } from '@popperjs/core' import { omitBy, isUndefined } from 'lodash-es' import flip from '@popperjs/core/lib/modifiers/flip' import offset from '@popperjs/core/lib/modifiers/offset' import preventOverflow from '@popperjs/core/lib/modifiers/preventOverflow' -const createPopper = popperGenerator({ +export const createPopper = popperGenerator({ defaultModifiers: [...defaultModifiers, offset, flip, preventOverflow] }) @@ -16,22 +18,23 @@ export function usePopper ({ offsetSkid = 0, placement, strategy -}) { - const reference = ref(null) - const popper = ref(null) +}, virtualReference) { + const reference: Ref = ref(null) + const popper: Ref = ref(null) + const instance: Ref = ref(null) onMounted(() => { watchEffect((onInvalidate) => { if (!popper.value) { return } - if (!reference.value) { return } + if (!reference.value && !virtualReference.value) { return } const popperEl = popper.value.$el || popper.value - const referenceEl = reference.value.$el || reference.value + const referenceEl = virtualReference?.value || reference.value.$el || reference.value - if (!(referenceEl instanceof HTMLElement)) { return } + // if (!(referenceEl instanceof HTMLElement)) { return } if (!(popperEl instanceof HTMLElement)) { return } - const { destroy } = createPopper(referenceEl, popperEl, omitBy({ + instance.value = createPopper(referenceEl, popperEl, omitBy({ placement, strategy, modifiers: [{ @@ -50,9 +53,9 @@ export function usePopper ({ }] }, isUndefined)) - onInvalidate(destroy) + onInvalidate(instance.value.destroy) }) }) - return [reference, popper] + return [reference, popper, instance] } diff --git a/src/runtime/presets/default.ts b/src/runtime/presets/default.ts index 8c9e4551..0d0cec6f 100644 --- a/src/runtime/presets/default.ts +++ b/src/runtime/presets/default.ts @@ -503,6 +503,21 @@ export default (variantColors: string[]) => { } } + const contextMenu = { + wrapper: 'relative', + container: 'z-20', + width: '', + base: '', + transition: { + enterActiveClass: 'transition ease-out duration-200', + enterFromClass: 'opacity-0 translate-y-1', + enterToClass: 'opacity-100 translate-y-0', + leaveActiveClass: 'transition ease-in duration-150', + leaveFromClass: 'opacity-100 translate-y-0', + leaveToClass: 'opacity-0 translate-y-1' + } + } + return { card, modal, @@ -527,6 +542,7 @@ export default (variantColors: string[]) => { slideover, notification, tooltip, - popover + popover, + contextMenu } }