Files
HMDesign/src/components/context-menu.stories.tsx
T

115 lines
4.9 KiB
TypeScript

import { useState } from "react"
import type { Meta, StoryObj } from "@storybook/react-vite"
import {
ContextMenu,
ContextMenuCheckboxItem,
ContextMenuContent,
ContextMenuGroup,
ContextMenuItem,
ContextMenuLabel,
ContextMenuRadioGroup,
ContextMenuRadioItem,
ContextMenuSeparator,
ContextMenuShortcut,
ContextMenuSub,
ContextMenuSubContent,
ContextMenuSubTrigger,
ContextMenuTrigger,
} from "@hm-design/ui"
import { STORY_KICKER, StoryPage, StoryPageHeader, StorySection } from "@/components/story-page"
// Context Menu opens from pointer context (right click, the context-menu key / Shift+F10, long press) on its trigger area.
// The representative Story is a target area: right click it. Radix owns keyboard navigation, focus return and Escape.
function Full() {
const [showStatus, setShowStatus] = useState(true)
const [showPanel, setShowPanel] = useState(false)
const [position, setPosition] = useState("bottom")
return (
<ContextMenu>
{/* tabIndex lets keyboard users focus the area and open the menu with Shift+F10 / the context-menu key; Radix Trigger is a plain span. */}
<ContextMenuTrigger tabIndex={0} className="flex h-40 w-80 items-center justify-center rounded-md border border-dashed text-sm text-muted-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring">
이 영역에서 오른쪽 클릭
</ContextMenuTrigger>
<ContextMenuContent className="w-56">
<ContextMenuLabel>파일</ContextMenuLabel>
<ContextMenuGroup>
<ContextMenuItem>
열기 <ContextMenuShortcut>⌘O</ContextMenuShortcut>
</ContextMenuItem>
<ContextMenuItem>
이름 바꾸기 <ContextMenuShortcut>F2</ContextMenuShortcut>
</ContextMenuItem>
<ContextMenuItem disabled>붙여넣기 (사용 불가)</ContextMenuItem>
</ContextMenuGroup>
<ContextMenuSeparator />
<ContextMenuLabel>보기</ContextMenuLabel>
<ContextMenuCheckboxItem checked={showStatus} onCheckedChange={setShowStatus}>
상태 표시줄
</ContextMenuCheckboxItem>
<ContextMenuCheckboxItem checked={showPanel} onCheckedChange={setShowPanel}>
패널
</ContextMenuCheckboxItem>
<ContextMenuSeparator />
<ContextMenuLabel>위치</ContextMenuLabel>
<ContextMenuRadioGroup value={position} onValueChange={setPosition}>
<ContextMenuRadioItem value="top">상단</ContextMenuRadioItem>
<ContextMenuRadioItem value="bottom">하단</ContextMenuRadioItem>
<ContextMenuRadioItem value="right">오른쪽</ContextMenuRadioItem>
</ContextMenuRadioGroup>
<ContextMenuSeparator />
<ContextMenuSub>
<ContextMenuSubTrigger>더 보기</ContextMenuSubTrigger>
<ContextMenuSubContent>
<ContextMenuItem>이메일로 공유</ContextMenuItem>
<ContextMenuItem>링크 복사</ContextMenuItem>
</ContextMenuSubContent>
</ContextMenuSub>
<ContextMenuSeparator />
<ContextMenuItem variant="destructive">삭제</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
)
}
const meta = { title: "Components/Overlay/Context Menu", component: ContextMenu, parameters: { layout: "centered" } } satisfies Meta<typeof ContextMenu>
export default meta
type Story = StoryObj<typeof meta>
// Representative Story: right click the area to open the full menu (item, disabled, separator, shortcut, checkbox, radio group, sub menu, destructive).
export const All: Story = {
name: "Context Menu",
parameters: { layout: "fullscreen", controls: { disable: true } },
render: () => (
<StoryPage>
<StoryPageHeader
kicker={STORY_KICKER.components}
title="Context Menu"
description="영역에서 오른쪽 클릭, 컨텍스트 메뉴 키 / Shift+F10, 길게 누르기로 여는 메뉴입니다."
/>
<StorySection title="Overview" description="항목 · Disabled · 단축키 · Checkbox · Radio Group · 하위 메뉴 · 위험 항목을 한 메뉴에서 확인합니다. 점선 영역에서 오른쪽 클릭합니다.">
<Full />
</StorySection>
</StoryPage>
),
}
// Verification Story: opens the menu at the area center on load (synthetic contextmenu event), hidden from the sidebar (tag `verification`).
export const Open: Story = {
tags: ["verification"],
parameters: { layout: "fullscreen" },
render: () => (
<div className="flex min-h-[560px] justify-center p-8">
<Full />
</div>
),
play: async ({ canvasElement }) => {
const area = canvasElement.querySelector<HTMLElement>("[data-slot='context-menu-trigger']")
if (!area) return
const r = area.getBoundingClientRect()
area.dispatchEvent(
new MouseEvent("contextmenu", { bubbles: true, cancelable: true, clientX: r.left + r.width / 2, clientY: r.top + r.height / 2, button: 2 }),
)
},
}