Skip to main content

Navigation

Context Menu code

Copy the implementation or inspect every file that belongs to this component unit.

resources/views/components/ui/context-menu.blade.php

@props([
    'width' => '56',
])

@php
    /*
    | Right-click menu. Wrap the area that owns the menu in the default slot and
    | put <x-ui.dropdown.item> rows in the `menu` slot. The menu opens at the
    | cursor and closes on click, Escape, outside click or scroll.
    |
    | Usage:
    |   <x-ui.context-menu>
    |       <div class="rounded-xl border p-6">Right-click this card</div>
    |       <x-slot:menu>
    |           <x-ui.dropdown.item icon="pencil-simple">Rename</x-ui.dropdown.item>
    |           <x-ui.dropdown.item icon="trash" variant="danger">Delete</x-ui.dropdown.item>
    |       </x-slot:menu>
    |   </x-ui.context-menu>
    */
    $widthClass = [
        '48' => 'w-48', '56' => 'w-56', '64' => 'w-64',
    ][$width] ?? $width;

    $menuId = 'context-menu-'.substr(md5($width.$slot), 0, 10);
@endphp

<div
    x-data="{
        open: false,
        x: 0,
        y: 0,
        show(event) {
            this.x = Math.min(event.clientX, window.innerWidth - 260);
            this.y = Math.min(event.clientY, window.innerHeight - 260);
            this.open = true;
        },
    }"
    @contextmenu.prevent="show($event)"
    @click.outside="open = false"
    @keydown.escape.window="open = false"
    @scroll.window="open = false"
    {{ $attributes }}
>
    {{ $slot }}

    <div
        id="{{ $menuId }}"
        x-show="open" x-cloak
        x-transition:enter="transition ease-out duration-150"
        x-transition:enter-start="opacity-0 scale-95"
        x-transition:enter-end="opacity-100 scale-100"
        x-transition:leave="transition ease-in duration-100"
        x-transition:leave-start="opacity-100 scale-100"
        x-transition:leave-end="opacity-0 scale-95"
        :style="`top: ${y}px; left: ${x}px`"
        class="fixed z-50 {{ $widthClass }} rounded-xl border border-gray-200 bg-white p-1.5 shadow-lg ring-1 ring-black/5 dark:border-gray-800 dark:bg-gray-900"
        role="menu"
        aria-label="Context menu"
        @click="open = false"
    >
        {{ $menu }}
    </div>
</div>