add documentation for dialog component
Signed-off-by: Sofia Sjöblad <ssjoblad@spotify.com>
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import { PropsTable } from '@/components/PropsTable';
|
||||
import { Snippet } from '@/components/Snippet';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import {DialogSnippet} from '@/snippets/stories-snippets';
|
||||
import {
|
||||
dialogPropDefs,
|
||||
dialogTriggerPropDefs,
|
||||
dialogHeaderPropDefs,
|
||||
dialogBodyPropDefs,
|
||||
dialogFooterPropDefs,
|
||||
dialogClosePropDefs,
|
||||
dialogUsageSnippet,
|
||||
dialogDefaultSnippet,
|
||||
dialogScrollableSnippet,
|
||||
dialogWithFormSnippet,
|
||||
} from './dialog.props';
|
||||
import { PageTitle } from '@/components/PageTitle';
|
||||
import { Theming } from '@/components/Theming';
|
||||
import { ChangelogComponent } from '@/components/ChangelogComponent';
|
||||
|
||||
<PageTitle
|
||||
title="Dialog"
|
||||
description="A modal dialog component that displays content in an overlay window."
|
||||
/>
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<DialogSnippet story="Default" />}
|
||||
code={dialogDefaultSnippet}
|
||||
/>
|
||||
|
||||
## Usage
|
||||
|
||||
<CodeBlock code={dialogUsageSnippet} />
|
||||
|
||||
## API reference
|
||||
|
||||
### Dialog
|
||||
|
||||
The main dialog container that renders as a modal overlay.
|
||||
|
||||
<PropsTable data={dialogPropDefs} />
|
||||
|
||||
### DialogTrigger
|
||||
|
||||
Wraps a trigger element and the dialog content to handle open/close state.
|
||||
|
||||
<PropsTable data={dialogTriggerPropDefs} />
|
||||
|
||||
### DialogHeader
|
||||
|
||||
Displays the dialog title with a built-in close button.
|
||||
|
||||
<PropsTable data={dialogHeaderPropDefs} />
|
||||
|
||||
### DialogBody
|
||||
|
||||
The main content area of the dialog with optional scrolling.
|
||||
|
||||
<PropsTable data={dialogBodyPropDefs} />
|
||||
|
||||
### DialogFooter
|
||||
|
||||
Contains action buttons or other footer content.
|
||||
|
||||
<PropsTable data={dialogFooterPropDefs} />
|
||||
|
||||
### DialogClose
|
||||
|
||||
A button that closes the dialog when pressed.
|
||||
|
||||
<PropsTable data={dialogClosePropDefs} />
|
||||
|
||||
## Examples
|
||||
|
||||
### Scrollable Content
|
||||
|
||||
Dialog with a fixed height body that scrolls when content overflows.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<DialogSnippet story="Scrollable" />}
|
||||
code={dialogScrollableSnippet}
|
||||
/>
|
||||
|
||||
### Dialog with Form
|
||||
|
||||
Dialog containing form elements for user input.
|
||||
|
||||
<Snippet
|
||||
align="center"
|
||||
py={4}
|
||||
preview={<DialogSnippet story="WithForm" />}
|
||||
code={dialogWithFormSnippet}
|
||||
/>
|
||||
|
||||
<Theming component="Dialog" />
|
||||
|
||||
<ChangelogComponent component="dialog" />
|
||||
@@ -0,0 +1,139 @@
|
||||
import {
|
||||
classNamePropDefs,
|
||||
stylePropDefs,
|
||||
type PropDef,
|
||||
} from '@/utils/propDefs';
|
||||
|
||||
export const dialogPropDefs: Record<string, PropDef> = {
|
||||
children: { type: 'enum', values: ['ReactNode'], responsive: false },
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const dialogTriggerPropDefs: Record<string, PropDef> = {
|
||||
children: { type: 'enum', values: ['ReactNode'], responsive: false },
|
||||
};
|
||||
|
||||
export const dialogHeaderPropDefs: Record<string, PropDef> = {
|
||||
children: { type: 'enum', values: ['ReactNode'], responsive: false },
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const dialogBodyPropDefs: Record<string, PropDef> = {
|
||||
children: { type: 'enum', values: ['ReactNode'], responsive: false },
|
||||
height: {
|
||||
type: 'enum',
|
||||
values: ['number', 'string'],
|
||||
responsive: false,
|
||||
},
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const dialogFooterPropDefs: Record<string, PropDef> = {
|
||||
children: { type: 'enum', values: ['ReactNode'], responsive: false },
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const dialogClosePropDefs: Record<string, PropDef> = {
|
||||
variant: {
|
||||
type: 'enum',
|
||||
values: ['primary', 'secondary', 'tertiary'],
|
||||
default: 'secondary',
|
||||
responsive: false,
|
||||
},
|
||||
children: { type: 'enum', values: ['ReactNode'], responsive: false },
|
||||
...classNamePropDefs,
|
||||
...stylePropDefs,
|
||||
};
|
||||
|
||||
export const dialogUsageSnippet = `import {
|
||||
Dialog,
|
||||
DialogTrigger,
|
||||
DialogHeader,
|
||||
DialogBody,
|
||||
DialogFooter,
|
||||
DialogClose
|
||||
} from '@backstage/ui';
|
||||
|
||||
<DialogTrigger>
|
||||
<Button>Open Dialog</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>Title</DialogHeader>
|
||||
<DialogBody>Content</DialogBody>
|
||||
<DialogFooter>
|
||||
<DialogClose>Close</DialogClose>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
</DialogTrigger>`;
|
||||
|
||||
export const dialogDefaultSnippet = `<DialogTrigger>
|
||||
<Button variant="secondary">Open Dialog</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>Example Dialog</DialogHeader>
|
||||
<DialogBody>
|
||||
<Text>This is a basic dialog example with React Aria Components.</Text>
|
||||
</DialogBody>
|
||||
<DialogFooter>
|
||||
<DialogClose>Close</DialogClose>
|
||||
<DialogClose variant="primary">Save</DialogClose>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
</DialogTrigger>`;
|
||||
|
||||
export const dialogScrollableSnippet = `<DialogTrigger>
|
||||
<Button variant="secondary">Scrollable Dialog</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>Long Content Dialog</DialogHeader>
|
||||
<DialogBody height={200}>
|
||||
<Text>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
commodo consequat.
|
||||
</Text>
|
||||
<Text>
|
||||
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
|
||||
dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
</Text>
|
||||
<Text>
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium
|
||||
doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore
|
||||
veritatis et quasi architecto beatae vitae dicta sunt explicabo.
|
||||
</Text>
|
||||
</DialogBody>
|
||||
<DialogFooter>
|
||||
<Flex gap="2" justify="end">
|
||||
<DialogClose>Cancel</DialogClose>
|
||||
<DialogClose variant="primary">Accept</DialogClose>
|
||||
</Flex>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
</DialogTrigger>`;
|
||||
|
||||
export const dialogWithFormSnippet = `<DialogTrigger>
|
||||
<Button variant="secondary">Create User</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>Create New User</DialogHeader>
|
||||
<DialogBody>
|
||||
<Flex direction="column" gap="3">
|
||||
<TextField label="Name" placeholder="Enter full name" />
|
||||
<TextField label="Email" placeholder="Enter email address" />
|
||||
<Select label="Role">
|
||||
<SelectItem>Admin</SelectItem>
|
||||
<SelectItem>User</SelectItem>
|
||||
<SelectItem>Viewer</SelectItem>
|
||||
</Select>
|
||||
</Flex>
|
||||
</DialogBody>
|
||||
<DialogFooter>
|
||||
<Flex gap="2" justify="end">
|
||||
<DialogClose>Cancel</DialogClose>
|
||||
<DialogClose variant="primary">Create User</DialogClose>
|
||||
</Flex>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
</DialogTrigger>`;
|
||||
@@ -17,6 +17,7 @@ import * as MenuStories from '../../../packages/ui/src/components/Menu/Menu.stor
|
||||
import * as LinkStories from '../../../packages/ui/src/components/Link/Link.stories';
|
||||
import * as AvatarStories from '../../../packages/ui/src/components/Avatar/Avatar.stories';
|
||||
import * as CollapsibleStories from '../../../packages/ui/src/components/Collapsible/Collapsible.stories';
|
||||
import * as DialogStories from '../../../packages/ui/src/components/Dialog/Dialog.stories';
|
||||
import * as RadioGroupStories from '../../../packages/ui/src/components/RadioGroup/RadioGroup.stories';
|
||||
import * as TabsStories from '../../../packages/ui/src/components/Tabs/Tabs.stories';
|
||||
import * as SwitchStories from '../../../packages/ui/src/components/Switch/Switch.stories';
|
||||
@@ -60,6 +61,7 @@ export const MenuSnippet = createSnippetComponent(MenuStories);
|
||||
export const LinkSnippet = createSnippetComponent(LinkStories);
|
||||
export const AvatarSnippet = createSnippetComponent(AvatarStories);
|
||||
export const CollapsibleSnippet = createSnippetComponent(CollapsibleStories);
|
||||
export const DialogSnippet = createSnippetComponent(DialogStories);
|
||||
export const RadioGroupSnippet = createSnippetComponent(RadioGroupStories);
|
||||
export const TabsSnippet = createSnippetComponent(TabsStories);
|
||||
export const SwitchSnippet = createSnippetComponent(SwitchStories);
|
||||
|
||||
@@ -101,6 +101,11 @@ export const components: Page[] = [
|
||||
slug: 'collapsible',
|
||||
status: 'alpha',
|
||||
},
|
||||
{
|
||||
title: 'Dialog',
|
||||
slug: 'dialog',
|
||||
status: 'alpha',
|
||||
},
|
||||
{
|
||||
title: 'Header',
|
||||
slug: 'header',
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
DialogFooter,
|
||||
DialogClose,
|
||||
} from './Dialog';
|
||||
import { Button, Flex, Text } from '@backstage/ui';
|
||||
import { Button, Flex, Text, TextField, Select } from '@backstage/ui';
|
||||
|
||||
const meta = {
|
||||
title: 'Components/Dialog',
|
||||
@@ -33,64 +33,106 @@ export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
children: (
|
||||
<>
|
||||
<DialogHeader>Hello</DialogHeader>
|
||||
render: () => (
|
||||
<DialogTrigger>
|
||||
<Button variant="secondary">Open Dialog</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>Example Dialog</DialogHeader>
|
||||
<DialogBody>
|
||||
<Text>Hello world</Text>
|
||||
<Text>
|
||||
This is a basic dialog example with React Aria Components.
|
||||
</Text>
|
||||
</DialogBody>
|
||||
<DialogFooter>
|
||||
<Flex gap="2" align="center" justify="end">
|
||||
<DialogClose>Close</DialogClose>
|
||||
<DialogClose variant="primary" onPress={() => console.log('Save')}>
|
||||
Save
|
||||
</DialogClose>
|
||||
</Flex>
|
||||
<DialogClose>Close</DialogClose>
|
||||
<DialogClose variant="primary">Save</DialogClose>
|
||||
</DialogFooter>
|
||||
</>
|
||||
),
|
||||
},
|
||||
render: args => (
|
||||
<DialogTrigger>
|
||||
<Button size="small" variant="secondary">
|
||||
Open Dialog
|
||||
</Button>
|
||||
<Dialog {...args} />
|
||||
</Dialog>
|
||||
</DialogTrigger>
|
||||
),
|
||||
};
|
||||
|
||||
export const CustomBodyMaxHeight: Story = {
|
||||
args: {
|
||||
children: (
|
||||
<>
|
||||
<DialogHeader> Hello</DialogHeader>
|
||||
<DialogBody height={400}>
|
||||
{Array.from({ length: 40 }).map((_, index) => (
|
||||
<Text key={index}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam,
|
||||
quos.
|
||||
</Text>
|
||||
))}
|
||||
export const Scrollable: Story = {
|
||||
render: () => (
|
||||
<DialogTrigger>
|
||||
<Button variant="secondary">Scrollable Dialog</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>Long Content Dialog</DialogHeader>
|
||||
<DialogBody height={200}>
|
||||
<Text>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
|
||||
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
|
||||
aliquip ex ea commodo consequat.
|
||||
</Text>
|
||||
<Text>
|
||||
Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
|
||||
cupidatat non proident, sunt in culpa qui officia deserunt mollit
|
||||
anim id est laborum.
|
||||
</Text>
|
||||
<Text>
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem
|
||||
accusantium doloremque laudantium, totam rem aperiam, eaque ipsa
|
||||
quae ab illo inventore veritatis et quasi architecto beatae vitae
|
||||
dicta sunt explicabo.
|
||||
</Text>
|
||||
</DialogBody>
|
||||
<DialogFooter>
|
||||
<Flex gap="2" align="center" justify="end">
|
||||
<DialogClose>Close</DialogClose>
|
||||
<DialogClose variant="primary" onPress={() => console.log('Save')}>
|
||||
Save
|
||||
</DialogClose>
|
||||
</Flex>
|
||||
<DialogClose>Cancel</DialogClose>
|
||||
<DialogClose variant="primary">Accept</DialogClose>
|
||||
</DialogFooter>
|
||||
</>
|
||||
),
|
||||
},
|
||||
render: args => (
|
||||
<DialogTrigger>
|
||||
<Button size="small" variant="secondary">
|
||||
Open Dialog
|
||||
</Button>
|
||||
<Dialog {...args} />
|
||||
</Dialog>
|
||||
</DialogTrigger>
|
||||
),
|
||||
};
|
||||
|
||||
export const Confirmation: Story = {
|
||||
render: () => (
|
||||
<DialogTrigger>
|
||||
<Button variant="secondary">Delete Item</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>Confirm Delete</DialogHeader>
|
||||
<DialogBody>
|
||||
<Text>
|
||||
Are you sure you want to delete this item? This action cannot be
|
||||
undone.
|
||||
</Text>
|
||||
</DialogBody>
|
||||
<DialogFooter>
|
||||
<DialogClose>Cancel</DialogClose>
|
||||
<DialogClose variant="primary">Delete</DialogClose>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
</DialogTrigger>
|
||||
),
|
||||
};
|
||||
|
||||
export const WithForm: Story = {
|
||||
render: () => (
|
||||
<DialogTrigger>
|
||||
<Button variant="secondary">Create User</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>Create New User</DialogHeader>
|
||||
<DialogBody>
|
||||
<Flex direction="column" gap="3">
|
||||
<TextField label="Name" placeholder="Enter full name" />
|
||||
<TextField label="Email" placeholder="Enter email address" />
|
||||
<Select
|
||||
label="Role"
|
||||
options={[
|
||||
{ value: 'admin', label: 'Admin' },
|
||||
{ value: 'user', label: 'User' },
|
||||
{ value: 'viewer', label: 'Viewer' },
|
||||
]}
|
||||
/>
|
||||
</Flex>
|
||||
</DialogBody>
|
||||
<DialogFooter>
|
||||
<DialogClose>Cancel</DialogClose>
|
||||
<DialogClose variant="primary">Create User</DialogClose>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
</DialogTrigger>
|
||||
),
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.bui-Dialog[data-entering] {
|
||||
|
||||
Reference in New Issue
Block a user