Files
ADS3-Design-System/src/components/molecules/Dialog/Dialog.stories.tsx
Richie 722475215d Reorganise components into atoms/molecules/organisms and fix Input icon colours
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>
2026-05-22 09:10:12 +10:00

251 lines
8.3 KiB
TypeScript

import { useState } from 'react'
import type { Meta, StoryObj } from '@storybook/react-vite'
import { AlertTriangle } from 'lucide-react'
import { Dialog, DialogHeader, DialogTitle, DialogDescription, DialogContent, DialogFooter } from './Dialog'
import { Button } from '@/components/atoms/Button'
import { Input } from '@/components/atoms/Input'
const meta: Meta<typeof Dialog> = {
title: 'Molecules/Dialog',
component: Dialog,
tags: ['autodocs'],
argTypes: {
size: {
control: 'select',
options: ['sm', 'default', 'lg', 'full'],
},
closeOnBackdrop: {
control: 'boolean',
},
},
}
export default meta
type Story = StoryObj<typeof meta>
// --- Default ---
export const Default: Story = {
render: () => {
const [open, setOpen] = useState(false)
return (
<>
<Button onClick={() => setOpen(true)}>Open dialog</Button>
<Dialog open={open} onClose={() => setOpen(false)}>
<DialogHeader onClose={() => setOpen(false)}>
<DialogTitle>Dialog title</DialogTitle>
<DialogDescription>A short description of the dialog purpose.</DialogDescription>
</DialogHeader>
<DialogContent>
<p className="text-body text-text">
This is the dialog body. It can contain any content text, forms, lists, or other
components.
</p>
</DialogContent>
<DialogFooter>
<Button variant="secondary" intent="neutral" onClick={() => setOpen(false)}>
Cancel
</Button>
<Button onClick={() => setOpen(false)}>Confirm</Button>
</DialogFooter>
</Dialog>
</>
)
},
}
// --- Small ---
export const Small: Story = {
render: () => {
const [open, setOpen] = useState(false)
return (
<>
<Button onClick={() => setOpen(true)}>Open small dialog</Button>
<Dialog open={open} onClose={() => setOpen(false)} size="sm">
<DialogHeader onClose={() => setOpen(false)}>
<DialogTitle>Quick confirmation</DialogTitle>
</DialogHeader>
<DialogContent>
<p className="text-body text-text">Are you sure you want to proceed?</p>
</DialogContent>
<DialogFooter>
<Button variant="tertiary" intent="neutral" onClick={() => setOpen(false)}>
No
</Button>
<Button onClick={() => setOpen(false)}>Yes</Button>
</DialogFooter>
</Dialog>
</>
)
},
}
// --- Large ---
export const Large: Story = {
render: () => {
const [open, setOpen] = useState(false)
return (
<>
<Button onClick={() => setOpen(true)}>Open large dialog</Button>
<Dialog open={open} onClose={() => setOpen(false)} size="lg">
<DialogHeader onClose={() => setOpen(false)}>
<DialogTitle>Review submission details</DialogTitle>
<DialogDescription>
Please review the information below before submitting.
</DialogDescription>
</DialogHeader>
<DialogContent>
<div className="space-y-3">
<div className="rounded-lg bg-bg px-4 py-3">
<p className="text-small font-bold text-text">Participant count</p>
<p className="text-body text-text-secondary">24 participants across 3 schools</p>
</div>
<div className="rounded-lg bg-bg px-4 py-3">
<p className="text-small font-bold text-text">Data collection period</p>
<p className="text-body text-text-secondary">March 2026 June 2026</p>
</div>
<div className="rounded-lg bg-bg px-4 py-3">
<p className="text-small font-bold text-text">Ethics approval</p>
<p className="text-body text-text-secondary">SERAP 2026-0142 (approved)</p>
</div>
</div>
</DialogContent>
<DialogFooter>
<Button variant="secondary" intent="neutral" onClick={() => setOpen(false)}>
Go back
</Button>
<Button onClick={() => setOpen(false)}>Submit</Button>
</DialogFooter>
</Dialog>
</>
)
},
}
// --- Danger confirmation ---
export const DangerConfirmation: Story = {
render: () => {
const [open, setOpen] = useState(false)
return (
<>
<Button intent="danger" onClick={() => setOpen(true)}>
Delete project
</Button>
<Dialog open={open} onClose={() => setOpen(false)} size="sm">
<DialogHeader onClose={() => setOpen(false)}>
<div className="flex items-center gap-2">
<div className="flex size-10 items-center justify-center rounded-full bg-error/10">
<AlertTriangle className="size-5 text-error" />
</div>
<DialogTitle>Delete project?</DialogTitle>
</div>
</DialogHeader>
<DialogContent>
<p className="text-body text-text">
This action cannot be undone. All data, themes, and participant responses associated
with this project will be permanently deleted.
</p>
</DialogContent>
<DialogFooter>
<Button variant="secondary" intent="neutral" onClick={() => setOpen(false)}>
Cancel
</Button>
<Button intent="danger" onClick={() => setOpen(false)}>
Delete
</Button>
</DialogFooter>
</Dialog>
</>
)
},
}
// --- With form ---
export const WithForm: Story = {
render: () => {
const [open, setOpen] = useState(false)
return (
<>
<Button onClick={() => setOpen(true)}>Create new theme</Button>
<Dialog open={open} onClose={() => setOpen(false)}>
<DialogHeader onClose={() => setOpen(false)}>
<DialogTitle>New theme</DialogTitle>
<DialogDescription>
Give your theme a name and description to help organise your findings.
</DialogDescription>
</DialogHeader>
<DialogContent>
<div className="space-y-4">
<Input label="Theme name" placeholder="e.g. Student engagement" />
<Input label="Description" placeholder="Brief summary of this theme" hint="Optional — you can add this later" />
</div>
</DialogContent>
<DialogFooter>
<Button variant="secondary" intent="neutral" onClick={() => setOpen(false)}>
Cancel
</Button>
<Button onClick={() => setOpen(false)}>Create theme</Button>
</DialogFooter>
</Dialog>
</>
)
},
}
// --- No close button ---
export const NoCloseButton: Story = {
render: () => {
const [open, setOpen] = useState(false)
return (
<>
<Button onClick={() => setOpen(true)}>Open without close button</Button>
<Dialog open={open} onClose={() => setOpen(false)} closeOnBackdrop={false}>
<DialogHeader>
<DialogTitle>Terms of use</DialogTitle>
</DialogHeader>
<DialogContent>
<p className="text-body text-text">
You must accept the terms of use before continuing. This dialog cannot be dismissed
by clicking the backdrop or pressing Escape only through the action buttons.
</p>
</DialogContent>
<DialogFooter>
<Button variant="secondary" intent="neutral" onClick={() => setOpen(false)}>
Decline
</Button>
<Button onClick={() => setOpen(false)}>Accept</Button>
</DialogFooter>
</Dialog>
</>
)
},
}
// --- Content only ---
export const ContentOnly: Story = {
render: () => {
const [open, setOpen] = useState(false)
return (
<>
<Button onClick={() => setOpen(true)}>Open minimal dialog</Button>
<Dialog open={open} onClose={() => setOpen(false)} size="sm">
<DialogContent className="py-6">
<p className="text-center text-body text-text">
Your changes have been saved.
</p>
<div className="mt-4 flex justify-center">
<Button onClick={() => setOpen(false)}>Done</Button>
</div>
</DialogContent>
</Dialog>
</>
)
},
}