ContextMenu
O'ng tugma (yoki uzoq bosish) bilan ochiladigan amallar menyusi — DropdownMenu bilan bir xil API va ko'rinish.
'use client';
import { ContextMenu, toast } from '@akhatmirzo/ui';
import { Copy, Download, FileText, Pencil, Trash2 } from 'lucide-react';
export default function ContextMenuBasic() {
return (
<ContextMenu>
<ContextMenu.Trigger asChild>
<div className="flex w-72 items-center gap-3 rounded-xl border border-dashed border-border-strong bg-surface p-4 select-none">
<span className="grid size-10 place-items-center rounded-lg bg-primary-soft text-primary-soft-foreground">
<FileText className="size-5" aria-hidden="true" />
</span>
<span className="flex flex-col">
<span className="text-sm font-medium">Hisobot-2026.pdf</span>
<span className="text-xs text-text-muted">O'ng tugma bilan bosing</span>
</span>
</div>
</ContextMenu.Trigger>
<ContextMenu.Content>
<ContextMenu.Item
icon={<Pencil />}
shortcut={['mod', 'E']}
onSelect={() => toast('Tahrirlash')}
>
Tahrirlash
</ContextMenu.Item>
<ContextMenu.Item
icon={<Copy />}
shortcut={['mod', 'D']}
onSelect={() => toast('Nusxa olindi')}
>
Nusxa olish
</ContextMenu.Item>
<ContextMenu.Item icon={<Download />} onSelect={() => toast('Yuklanmoqda')}>
Yuklab olish
</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Item icon={<Trash2 />} variant="danger" onSelect={() => toast("O'chirildi")}>
O'chirish
</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu>
);
}
Import
import { ContextMenu } from '@akhatmirzo/ui';Qachon ishlatish
- Fayl, karta, jadval qatori ustidagi tezkor amallar — kompyuterda ishlaydigan foydalanuvchilar o'ng tugmani kutadi.
- Faqat qo'shimcha yo'l sifatida. O'ng tugma menyusini hamma ham topmaydi, telefonda esa u
uzoq bosish bilan ochiladi. Muhim amallar boshqa joyda ham — tugma yoki
DropdownMenuorqali — mavjud bo'lsin. - Tugma bosilganda ochiladigan menyu kerak bo'lsa —
DropdownMenu. Ikkalasining qismlari bir xil, amallarni bir marta yozib, ikkala joyda ishlatish mumkin.
Tuzilishi
Qismlar, prop'lar va stillar DropdownMenu bilan bir xil (stillar umumiy
moduldan olinadi). Farqi — Trigger tugma emas, o'ng tugma bosiladigan hudud, panel esa
kursor turgan joyda ochiladi.
| Qism | Vazifasi |
|---|---|
ContextMenu | Holat: onOpenChange, modal, dir |
ContextMenu.Trigger | Hudud (stilsiz <span>; odatda asChild bilan) |
ContextMenu.Content | Panel: portal, kursor yonida ochiladi, aylanma navigatsiya |
ContextMenu.Item | Amal: icon, shortcut, variant, onSelect |
ContextMenu.CheckboxItem | Yoqib-o'chiriladigan element (✓) |
ContextMenu.RadioGroup / RadioItem | Bir nechtadan bittasini tanlash (●) |
ContextMenu.Label / Group / Separator | Sarlavha, guruh va ajratuvchi chiziq |
ContextMenu.Sub / SubTrigger / SubContent | Ichki menyu |
<ContextMenu>
<ContextMenu.Trigger asChild>
<Card>…fayl…</Card>
</ContextMenu.Trigger>
<ContextMenu.Content>
<ContextMenu.Item icon={<Pencil />} shortcut={['mod', 'E']}>
Tahrirlash
</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Item variant="danger">O'chirish</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu>Belgilanadigan elementlar
CheckboxItem (checked / onCheckedChange) va RadioGroup (value / onValueChange yoki
defaultValue) — ko'rinish sozlamalari uchun qulay.
'use client';
import { ContextMenu, cn } from '@akhatmirzo/ui';
import { useState } from 'react';
export default function ContextMenuCheckboxRadio() {
const [grid, setGrid] = useState(true);
const [rulers, setRulers] = useState(false);
const [zoom, setZoom] = useState('100');
return (
<ContextMenu>
<ContextMenu.Trigger asChild>
<div
className={cn(
'grid h-48 w-full max-w-md place-items-center rounded-xl border border-border bg-surface text-sm text-text-muted select-none',
grid && 'border-dashed',
rulers && 'border-l-4 border-t-4',
)}
>
Kanvas · {zoom}% — o'ng tugma bilan bosing
</div>
</ContextMenu.Trigger>
<ContextMenu.Content>
<ContextMenu.Label>Ko'rinish</ContextMenu.Label>
<ContextMenu.CheckboxItem checked={grid} onCheckedChange={setGrid}>
Panjara
</ContextMenu.CheckboxItem>
<ContextMenu.CheckboxItem checked={rulers} onCheckedChange={setRulers}>
Chizg'ichlar
</ContextMenu.CheckboxItem>
<ContextMenu.Separator />
<ContextMenu.Label>Masshtab</ContextMenu.Label>
<ContextMenu.RadioGroup value={zoom} onValueChange={setZoom}>
<ContextMenu.RadioItem value="50">50%</ContextMenu.RadioItem>
<ContextMenu.RadioItem value="100">100%</ContextMenu.RadioItem>
<ContextMenu.RadioItem value="200">200%</ContextMenu.RadioItem>
</ContextMenu.RadioGroup>
</ContextMenu.Content>
</ContextMenu>
);
}
Jadval qatori: ikki yo'l bilan
Qator ustida o'ng tugma — ContextMenu, "⋯" tugmasi — xuddi shu amallar bilan DropdownMenu.
Qismlar nomi bir xil bo'lgani uchun amallar bitta komponentda yoziladi. Ichki menyu → yoki
kursor bilan ochiladi.
- #1042Dilnoza Karimova1 250 000 so'm
- #1043Javohir Toshmatov480 000 so'm
'use client';
import { ContextMenu, DropdownMenu, IconButton, toast } from '@akhatmirzo/ui';
import { Ellipsis, Pencil, Send, Trash2 } from 'lucide-react';
const orders = [
{ id: '#1042', customer: 'Dilnoza Karimova', total: "1 250 000 so'm" },
{ id: '#1043', customer: 'Javohir Toshmatov', total: "480 000 so'm" },
];
/** ContextMenu va DropdownMenu qismlari bir xil — amallar bir marta yoziladi */
function Actions({ id, Menu }: { id: string; Menu: typeof ContextMenu | typeof DropdownMenu }) {
return (
<>
<Menu.Item icon={<Pencil />} onSelect={() => toast(`${id} tahrirlanmoqda`)}>
Tahrirlash
</Menu.Item>
<Menu.Sub>
<Menu.SubTrigger icon={<Send />}>Yuborish</Menu.SubTrigger>
<Menu.SubContent>
<Menu.Item onSelect={() => toast('Telegram')}>Telegram</Menu.Item>
<Menu.Item onSelect={() => toast('Email')}>Email</Menu.Item>
</Menu.SubContent>
</Menu.Sub>
<Menu.Separator />
<Menu.Item icon={<Trash2 />} variant="danger" onSelect={() => toast(`${id} o'chirildi`)}>
O'chirish
</Menu.Item>
</>
);
}
export default function ContextMenuTableRow() {
return (
<ul className="m-0 w-full max-w-lg list-none rounded-xl border border-border bg-surface p-0">
{orders.map((o) => (
<ContextMenu key={o.id}>
<ContextMenu.Trigger asChild>
<li className="flex items-center gap-3 border-b border-border px-4 py-2 text-sm last:border-b-0">
<span className="font-medium">{o.id}</span>
<span className="truncate text-text-muted">{o.customer}</span>
<span className="ml-auto tabular-nums">{o.total}</span>
{/* Xuddi shu amallar tugma orqali ham mavjud */}
<DropdownMenu>
<DropdownMenu.Trigger asChild>
<IconButton size="sm" variant="ghost" aria-label={`${o.id} amallari`}>
<Ellipsis />
</IconButton>
</DropdownMenu.Trigger>
<DropdownMenu.Content align="end">
<Actions id={o.id} Menu={DropdownMenu} />
</DropdownMenu.Content>
</DropdownMenu>
</li>
</ContextMenu.Trigger>
<ContextMenu.Content>
<Actions id={o.id} Menu={ContextMenu} />
</ContextMenu.Content>
</ContextMenu>
))}
</ul>
);
}
Telefonda
Sensorli ekranda menyu uzoq bosish (long press) bilan ochiladi. Bu yashirin imo-ishora — shuning uchun amallarni ko'rinadigan tugma orqali ham bering.
Props
ContextMenu
Radix ContextMenu Root prop'lari: onOpenChange, modal (standart true) va dir. Menyu
faqat foydalanuvchi harakati bilan ochiladi.
ContextMenu.Trigger
| Prop | Tip | Standart | Tavsif |
|---|---|---|---|
asChild | boolean | false | Bolani (karta, qator) hudud sifatida ishlatadi |
disabled | boolean | — | true — o'ng tugma menyusi ochilmaydi |
ContextMenu.Content
Radix ContextMenu.Content ning qolgan prop'lari (alignOffset, onCloseAutoFocus,
onEscapeKeyDown ...), <div> atributlari va ref ham qabul qilinadi.
| Prop | Tip | Standart | Tavsif |
|---|---|---|---|
collisionPadding | number | 8 | Ekran chetidan minimal masofa, px |
loop | boolean | true | ↑ ↓ oxiridan boshiga o'tadi |
container | HTMLElement | null | — | Portal konteyneri (standart — document.body) |
ContextMenu.Item
| Prop | Tip | Standart | Tavsif |
|---|---|---|---|
icon | ReactNode | — | Chapdagi ikonka (16px) |
shortcut | string[] | — | O'ngdagi Kbd yorlig'i, masalan ['mod', 'E'] |
variant | 'default' | 'danger' | 'default' | danger — qizil matn va ajratish |
onSelect | (event: Event) => void | — | Tanlanganda. preventDefault() — menyu ochiq qoladi |
disabled | boolean | — | Elementni o'chiradi |
asChild | boolean | false | Bolani (masalan, <a>) element sifatida chizadi |
CheckboxItem, RadioGroup, RadioItem, Sub, SubTrigger va SubContent prop'lari
DropdownMenu dagi bilan bir xil.
Data atributlari
| Atribut | Qayerda | Qiymat |
|---|---|---|
data-state | trigger, panel | open · closed |
data-variant | element | default · danger |
data-highlighted | element | klaviatura yoki sichqoncha ustida |
data-disabled | element, trigger | o'chirilganda mavjud |
data-state | Checkbox/RadioItem | checked · unchecked |
Klaviatura
| Tugma | Harakat |
|---|---|
Shift + F10 | Fokusdagi hududda menyuni ochadi (brauzer) |
↓ / ↑ | Elementlar bo'ylab yurish (aylanma) |
Home / End | Birinchi / oxirgi element |
| Harf | Shu harf bilan boshlanadigan elementga sakrash |
→ / ← | Ichki menyuni ochish / yopish |
Enter / Space | Tanlash va yopish |
Esc | Yopish |
Accessibility
- Rollar. Panel —
role="menu", elementlar —menuitem,menuitemcheckbox,menuitemradio. Asosida Radix ContextMenu. - Topilishi qiyin. O'ng tugma menyusi ekran o'quvchi va klaviatura foydalanuvchilari uchun ko'rinmaydi — muhim amallarni albatta boshqa yo'l bilan ham bering.
- Qisqa yo'llar.
shortcutberilsa,aria-keyshortcutsqo'yiladi; ko'rinadiganKbdekran o'quvchidan yashirin. Yorliq tugmani o'zi tinglamaydi —useHotkeysbilan ulang. - Ikonkalar
aria-hidden.