Moved all 17 components from ui/ into atomic design tiers: atoms (Button, IconButton, Input, Textarea, Select, Checkbox, Radio, Switch, Badge, Tag, Chip, Tooltip) and molecules (Alert, Accordion, Card, Dialog, Popover). Updated all Storybook titles and cross-component imports. Changed Input icons to primary-dark and replaced palette token references with semantic tokens. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
156 lines
4.8 KiB
TypeScript
156 lines
4.8 KiB
TypeScript
import type { Meta, StoryObj } from '@storybook/react-vite'
|
|
import { Settings, Filter, MoreVertical } from 'lucide-react'
|
|
import { Popover, PopoverTrigger, PopoverContent, PopoverClose } from './Popover'
|
|
import { Button } from '@/components/atoms/Button'
|
|
import { IconButton } from '@/components/atoms/IconButton'
|
|
import { Input } from '@/components/atoms/Input'
|
|
import { Checkbox } from '@/components/atoms/Checkbox'
|
|
|
|
const meta: Meta<typeof Popover> = {
|
|
title: 'Molecules/Popover',
|
|
component: Popover,
|
|
tags: ['autodocs'],
|
|
argTypes: {
|
|
placement: {
|
|
control: 'select',
|
|
options: ['top', 'right', 'bottom', 'left', 'bottom-start', 'bottom-end'],
|
|
},
|
|
},
|
|
decorators: [
|
|
(Story) => (
|
|
<div className="flex min-h-80 items-start justify-center p-16">
|
|
<Story />
|
|
</div>
|
|
),
|
|
],
|
|
}
|
|
|
|
export default meta
|
|
type Story = StoryObj<typeof meta>
|
|
|
|
export const Default: Story = {
|
|
render: () => (
|
|
<Popover>
|
|
<PopoverTrigger>
|
|
<Button variant="secondary">Open popover</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent>
|
|
<p className="text-body font-bold text-text">Popover title</p>
|
|
<p className="mt-1 text-small text-text-secondary">
|
|
This is a popover with rich content. It can contain text, forms, or any components.
|
|
</p>
|
|
</PopoverContent>
|
|
</Popover>
|
|
),
|
|
}
|
|
|
|
// --- With form ---
|
|
|
|
export const WithForm: Story = {
|
|
render: () => (
|
|
<Popover>
|
|
<PopoverTrigger>
|
|
<Button leftIcon={<Settings className="size-4" />}>Settings</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent className="w-80">
|
|
<p className="mb-3 text-body font-bold text-text">Display settings</p>
|
|
<div className="space-y-3">
|
|
<Input label="Items per page" type="number" defaultValue="25" />
|
|
<Checkbox label="Show archived items" />
|
|
<Checkbox label="Compact view" />
|
|
</div>
|
|
<div className="mt-4 flex justify-end gap-2">
|
|
<PopoverClose className="rounded-full px-3 py-1.5 text-small font-bold text-text-secondary hover:bg-bg">
|
|
Cancel
|
|
</PopoverClose>
|
|
<PopoverClose className="rounded-full bg-primary-dark px-3 py-1.5 text-small font-bold text-white hover:bg-primary-dark/90">
|
|
Apply
|
|
</PopoverClose>
|
|
</div>
|
|
</PopoverContent>
|
|
</Popover>
|
|
),
|
|
}
|
|
|
|
// --- Filter popover ---
|
|
|
|
export const FilterPopover: Story = {
|
|
render: () => (
|
|
<Popover placement="bottom-start">
|
|
<PopoverTrigger>
|
|
<Button variant="secondary" intent="neutral" leftIcon={<Filter className="size-4" />}>
|
|
Filters
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent className="w-64">
|
|
<p className="mb-3 text-small font-bold text-text">Filter by status</p>
|
|
<div className="space-y-2">
|
|
<Checkbox label="Active" defaultChecked />
|
|
<Checkbox label="Completed" defaultChecked />
|
|
<Checkbox label="Archived" />
|
|
<Checkbox label="Draft" />
|
|
</div>
|
|
<div className="mt-4 border-t border-border pt-3">
|
|
<PopoverClose className="text-small font-bold text-primary-dark hover:underline">
|
|
Clear all filters
|
|
</PopoverClose>
|
|
</div>
|
|
</PopoverContent>
|
|
</Popover>
|
|
),
|
|
}
|
|
|
|
// --- Context menu style ---
|
|
|
|
export const ActionMenu: Story = {
|
|
render: () => (
|
|
<Popover placement="bottom-end">
|
|
<PopoverTrigger>
|
|
<IconButton variant="tertiary" intent="neutral" icon={<MoreVertical />} aria-label="More actions" />
|
|
</PopoverTrigger>
|
|
<PopoverContent className="w-48 p-1">
|
|
{['Edit', 'Duplicate', 'Move to folder'].map((item) => (
|
|
<PopoverClose
|
|
key={item}
|
|
className="flex w-full rounded-md px-3 py-2 text-left text-small text-text hover:bg-bg"
|
|
>
|
|
{item}
|
|
</PopoverClose>
|
|
))}
|
|
<div className="my-1 border-t border-border" />
|
|
<PopoverClose className="flex w-full rounded-md px-3 py-2 text-left text-small text-error hover:bg-error/5">
|
|
Delete
|
|
</PopoverClose>
|
|
</PopoverContent>
|
|
</Popover>
|
|
),
|
|
}
|
|
|
|
// --- Placements ---
|
|
|
|
export const BottomStart: Story = {
|
|
render: () => (
|
|
<Popover placement="bottom-start">
|
|
<PopoverTrigger>
|
|
<Button variant="secondary" intent="neutral">Bottom start</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent>
|
|
<p className="text-small text-text">Aligned to the start of the trigger.</p>
|
|
</PopoverContent>
|
|
</Popover>
|
|
),
|
|
}
|
|
|
|
export const TopEnd: Story = {
|
|
render: () => (
|
|
<Popover placement="top-end">
|
|
<PopoverTrigger>
|
|
<Button variant="secondary" intent="neutral">Top end</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent>
|
|
<p className="text-small text-text">Aligned to the end of the trigger, above.</p>
|
|
</PopoverContent>
|
|
</Popover>
|
|
),
|
|
}
|