import { Button } from '@/components/ui/button'; import { Modal } from '@/components/ui/modal/modal'; import type { Meta, StoryObj } from '@storybook/react-webpack5'; import { useState } from 'react'; // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export const meta = { title: 'Example/Modal', component: Modal, parameters: { // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout layout: 'centered', docs: { description: { component: ` ## Modal Component The Modal component is a dialog overlay that can be used to present content in a modal window. It provides a flexible way to display information, forms, or any other content on top of the main page content. ### Import Path \`\`\`typescript import { Modal } from '@/components/ui/modal/modal'; \`\`\` ### Basic Usage \`\`\`tsx import { Modal } from '@/components/ui/modal/modal'; import { useState } from 'react'; function MyComponent() { const [open, setOpen] = useState(false); return ( <>

Modal content goes here

); } \`\`\` ### Features - Multiple sizes: small, default, and large - Customizable header with title and close button - Customizable footer with default OK/Cancel buttons - Support for controlled and uncontrolled usage - Loading state for confirmation button - Keyboard navigation support (ESC to close) - Click outside to close functionality - Full screen mode option - Built with Radix UI primitives for accessibility - Customizable styling with className props `, }, }, }, // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs tags: ['autodocs'], // More on argTypes: https://storybook.js.org/docs/api/argtypes argTypes: { open: { description: 'Whether the modal is open or not', control: { type: 'boolean' }, }, onOpenChange: { description: 'Callback function that is called when the open state changes', control: false, }, title: { description: 'Title of the modal', control: { type: 'text' }, }, titleClassName: { description: 'Additional CSS classes for the title container', control: { type: 'text' }, }, children: { description: 'Content to be displayed inside the modal', control: false, }, footer: { description: 'Custom footer content. If not provided, default buttons will be shown', control: { type: 'text' }, }, footerClassName: { description: 'Additional CSS classes for the footer container', control: { type: 'text' }, }, showfooter: { description: 'Whether to show the footer or not', control: { type: 'boolean' }, }, className: { description: 'Additional CSS classes for the modal container', control: { type: 'text' }, }, size: { description: 'Size of the modal', control: { type: 'select' }, options: ['small', 'default', 'large'], }, closable: { description: 'Whether to show the close button in the header', control: { type: 'boolean' }, }, closeIcon: { description: 'Custom close icon', control: false, }, maskClosable: { description: 'Whether to close the modal when clicking on the mask', control: { type: 'boolean' }, }, destroyOnClose: { description: 'Whether to unmount the modal content when closed', control: { type: 'boolean' }, }, full: { description: 'Whether the modal should take the full screen', control: { type: 'boolean' }, }, confirmLoading: { description: 'Whether the confirm button should show a loading state', control: { type: 'boolean' }, }, cancelText: { description: 'Text for the cancel button', control: { type: 'text' }, }, okText: { description: 'Text for the OK button', control: { type: 'text' }, }, onOk: { description: 'Callback function for the OK button', control: false, }, onCancel: { description: 'Callback function for the Cancel button', control: false, }, }, } satisfies Meta; export default meta; type Story = StoryObj; // More on writing stories with args: https://storybook.js.org/docs/writing-stories/args export const Default: Story = { args: { open: false, title: 'Default Modal', children: (

Modal Content

This is the default modal with standard size and functionality.

), }, render: (args) => { // eslint-disable-next-line react-hooks/rules-of-hooks const [open, setOpen] = useState(false); return (
{args.children}
); }, parameters: { docs: { description: { story: ` ### Default Modal Shows the basic modal with default size and standard header/footer. \`\`\`tsx const [open, setOpen] = useState(false);

Modal Content

This is the default modal with standard size and functionality.

\`\`\` `, }, }, }, }; export const Small: Story = { args: { open: false, title: 'Small Modal', size: 'small', children: (

Small Modal

This is a small modal, suitable for simple confirmations or short messages.

), }, render: (args) => { // eslint-disable-next-line react-hooks/rules-of-hooks const [open, setOpen] = useState(false); return (
{args.children}
); }, parameters: { docs: { description: { story: ` ### Small Modal Shows a small-sized modal, ideal for confirmations or brief messages. \`\`\`tsx const [open, setOpen] = useState(false);

Small Modal

This is a small modal, suitable for simple confirmations or short messages.

\`\`\` `, }, }, }, }; export const Large: Story = { args: { open: false, title: 'Large Modal', size: 'large', children: (

Large Modal

This is a large modal with more content. It can accommodate forms, tables, or other complex content.

Additional content area

You can put any content here

), }, render: (args) => { // eslint-disable-next-line react-hooks/rules-of-hooks const [open, setOpen] = useState(false); return (
{args.children}
); }, parameters: { docs: { description: { story: ` ### Large Modal Shows a large-sized modal, suitable for complex content like forms or data tables. \`\`\`tsx const [open, setOpen] = useState(false);

Large Modal

This is a large modal with more content. It can accommodate forms, tables, or other complex content.

Additional content area

You can put any content here

\`\`\` `, }, }, }, }; export const WithCustomFooter: Story = { args: { open: false, title: 'Custom Footer', children: (

Modal with Custom Footer

This modal has a custom footer with multiple buttons.

), }, render: (args) => { // eslint-disable-next-line react-hooks/rules-of-hooks const [open, setOpen] = useState(false); return (
} > {args.children} ); }, parameters: { docs: { description: { story: ` ### Custom Footer Shows a modal with a custom footer. You can provide your own footer content instead of using the default OK/Cancel buttons. \`\`\`tsx const [open, setOpen] = useState(false);
} >

Modal with Custom Footer

This modal has a custom footer with multiple buttons.

\`\`\` `, }, }, }, }; export const WithoutFooter: Story = { args: { open: false, title: 'No Footer', children: (

Modal without Footer

This modal has no footer. The content area extends to the bottom of the modal.

), }, render: (args) => { // eslint-disable-next-line react-hooks/rules-of-hooks const [open, setOpen] = useState(false); return (
{args.children}
); }, parameters: { docs: { description: { story: ` ### Without Footer Shows a modal without a footer. Useful when you want to include action buttons within the content area or don't need any footer actions. \`\`\`tsx const [open, setOpen] = useState(false);

Modal without Footer

This modal has no footer. The content area extends to the bottom of the modal.

\`\`\` `, }, }, }, }; export const FullScreen: Story = { args: { open: false, title: 'Full Screen Modal', children: (

Full Screen Modal

This modal takes up the full screen. Useful for complex workflows or when you need maximum space.

Content area that can expand to fill available space

), }, render: (args) => { // eslint-disable-next-line react-hooks/rules-of-hooks const [open, setOpen] = useState(false); return (
{args.children}
); }, parameters: { docs: { description: { story: ` ### Full Screen Modal Shows a full screen modal that takes up the entire viewport. Useful for complex workflows or when maximum space is needed. \`\`\`tsx const [open, setOpen] = useState(false);

Full Screen Modal

This modal takes up the full screen. Useful for complex workflows or when you need maximum space.

Content area that can expand to fill available space

\`\`\` `, }, }, }, }; export const LoadingState: Story = { args: { open: false, title: 'Loading State', children: (

Modal with Loading State

The OK button shows a loading spinner when confirmLoading is true.

), }, render: (args) => { // eslint-disable-next-line react-hooks/rules-of-hooks const [open, setOpen] = useState(false); // eslint-disable-next-line react-hooks/rules-of-hooks const [loading, setLoading] = useState(false); const handleOk = () => { setLoading(true); setTimeout(() => { setLoading(false); setOpen(false); }, 2000); }; return (
{args.children}
); }, parameters: { docs: { description: { story: ` ### Loading State Shows a modal with the confirm button in a loading state. This is useful when performing async operations after clicking OK. \`\`\`tsx const [open, setOpen] = useState(false); const [loading, setLoading] = useState(false); const handleOk = () => { setLoading(true); setTimeout(() => { setLoading(false); setOpen(false); }, 2000); };

Modal with Loading State

The OK button shows a loading spinner when confirmLoading is true.

\`\`\` `, }, }, }, }; // Interactive example showing how to use the modal in a real component export const Interactive: Story = { args: { open: false, title: 'Interactive Modal', children: (

Interactive Modal

Click OK to see the loading state, or click Cancel/Close to close the modal.

), }, render: (args) => { // eslint-disable-next-line react-hooks/rules-of-hooks const [open, setOpen] = useState(false); return (
{ // Simulate API call setTimeout(() => { setOpen(false); }, 1000); }} > {args.children}
); }, parameters: { docs: { description: { story: ` ### Interactive Example This is a fully interactive example showing how to use the modal in a real component with state management. \`\`\`tsx import { useState } from 'react'; import { Button } from '@/components/ui/button'; import { Modal } from '@/components/ui/modal/modal'; function InteractiveModal() { const [open, setOpen] = useState(false); return (
{ // Simulate API call setTimeout(() => { setOpen(false); }, 1000); }} >

Interactive Modal

Click OK to see the loading state, or click Cancel/Close to close the modal.

); } \`\`\` `, }, }, }, };