import type { Meta, StoryObj } from '@storybook/react-vite' import { IconCopy, IconHash, IconPin, IconTrash } from '@tabler/icons-react' import { Avatar } from './Avatar' import { useRef, useState } from 'react' import { Button } from './Button' import { Divider } from './Divider' import { EnterHint, Menu, MenuItem, MenuPanel, MenuSub } from './Menu' /** * One row of a menu. Anatomy: `leading` (a 16px icon or an Avatar) · label * with an optional `description` line · one thing at the right edge — * `trailing` (any hint), else `shortcut` (the kbd chip), else the `submenu` * chevron. Stories sit on a `MenuPanel` — the menu's surface, drawn without * its behaviour — so the row is seen where it lives. A live menu portals and * places itself, so it cannot stand in the page (Katerina, D25); **Menu → * FromATrigger** is where the keyboard and the placement are. */ const meta = { title: 'Overlays/MenuItem', component: MenuItem, decorators: [ (Story) => (
), ], args: { label: 'Rename', onClick: () => {} }, argTypes: { onClick: { control: false }, leading: { control: false }, trailing: { control: false }, }, } satisfies Meta export default meta type Story = StoryObj export const Default: Story = {} export const WithAnIcon: Story = { args: { label: 'Pin', leading: }, } export const WithAShortcut: Story = { args: { label: 'Copy link', leading: , shortcut: 'Ctrl+C' }, } /** * A row that opens another menu, working: such a row can only be tried inside * a real menu, so this is one (Katerina, 28 September: one story, the working * one; the chevron is the row's whole affordance). * * Hover **Move to…**, or arrow onto it and press →. The panel opens beside the * row, flips to the other side at a screen edge, and stays open while you * cross the diagonal into it. * * From the keyboard: → opens it and leaves the highlight on the row, ↓ steps * into it, and ← closes it and puts the highlight back on the row. Measured in * that order — → then ← alone does nothing, because focus has not entered yet. */ export const Submenu: Story = { parameters: { controls: { disable: true } }, decorators: [(Story) => ], render: () => (
Open the menu}> {}} /> {}} /> {}} /> {}} /> {}} />
), } /** A person as a row — the face, the name, a second line, a trailing hint. Peek's mention rows. */ export const APerson: Story = { args: { label: 'Ana Duarte', description: 'Product designer', leading: , trailing: , }, } /** The submenu's chosen value. */ export const Selected: Story = { args: { label: 'Item one', selected: true }, } export const Destructive: Story = { args: { label: 'Delete', destructive: true, leading: }, } /** Every shape on one canvas. */ export const AllVariants: Story = { parameters: { controls: { disable: true } }, render: () => ( <> {}} /> } onClick={() => {}} /> {}} /> } shortcut="Ctrl+C" onClick={() => {}} /> {}} /> } trailing={} onClick={() => {}} /> {}} /> } onClick={() => {}} /> {}} /> ), } /** The tall picker row — 48px, px-3, a 32px face or tile, the description line, and the hint while highlighted. TopicMenu, MentionMenu, the files menu and the launcher all draw this row. */ export const Tall: Story = { args: { size: 'tall', label: 'Ana Duarte', description: 'Product designer', leading: , selected: true, // `hint`, not `trailing`: shown only while the row is highlighted, on the fill's own timing. hint: , }, } /** A topic in the picker: `EnterHint`'s `target` says what Enter gives you, after the key. Hover another row and back to see the hint follow the highlight. */ export const ATopic: Story = { args: { size: 'tall', label: 'design', description: '12 members', leading: , selected: true, hint: , }, // axe color-contrast is off here until PLAN.md stage 0.10 is ruled: the // target is muted text, 3.05:1 on a highlighted row in signal (AA 4.5:1). parameters: { a11y: { config: { rules: [{ id: 'color-contrast', enabled: false }] } } }, }