Files
zeekay 464e1eece0 State a version once
A version written into a manifest is written into every manifest that wants it,
which is how eslint came to exist in a hundred and four forms across this estate
and how a package came to resolve twice at run time. The catalog moves the number
out of the manifest: a manifest names the package, the workspace names the
version.

Four are held below their latest because the newer release cannot be used, and
the reason is recorded rather than the version alone: @noble/hashes 2 renamed
every subpath the web3 stack imports, @splinetool/runtime 2 depends on a package
that was never published, @dynamic-labs 5.4.1 the same, and react-resizable-panels
3 points its types condition at the bundle.
2026-09-15 11:45:32 -07:00

275 lines
6.9 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Meta, Controls, Primary, Story } from '@storybook/addon-docs/blocks';
import * as DialogStories from './dialog.stories';
import * as DialogWrapperStories from './dialog-wrapper.stories';
import * as ConfirmDialogStories from './confirm-dialog.stories';
import * as ConfirmDialogUrlStories from './confirm-dialog-url.stories';
import * as AlertDialogStories from './alert-dialog.stories';
import * as DialogPrimitiveStories from './dialog-primitive.stories';
import * as DialogTriggerStories from './dialog-trigger.stories';
import * as DialogContentStories from './dialog-content.stories';
import * as DialogHeaderStories from './dialog-header.stories';
import * as DialogTitleStories from './dialog-title.stories';
import * as DialogDescriptionStories from './dialog-description.stories';
import * as DialogFooterStories from './dialog-footer.stories';
import * as DialogCloseStories from './dialog-close.stories';
import * as DialogOverlayStories from './dialog-overlay.stories';
import * as DialogPortalStories from './dialog-portal.stories';
<Meta of={DialogStories} />
# Dialog
A modal dialog component for displaying content that requires user attention or interaction.
## How to use
### DialogWrapper (preset)
Use `DialogWrapper` for a simple dialog with title, optional trigger, and content. Pass `open` and `onOpenChange` for controlled mode with exit animations:
```tsx
import { DialogWrapper, Button } from '@signozhq/ui';
export default function MyComponent() {
const [open, setOpen] = React.useState(false);
return (
<DialogWrapper
open={open}
onOpenChange={setOpen}
title="Edit Details"
trigger={<Button variant="solid">Open Dialog</Button>}
>
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
<p>Dialog content goes here</p>
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button variant="solid" color="primary" onClick={() => setOpen(false)}>
Save Changes
</Button>
</div>
</div>
</DialogWrapper>
);
}
```
<Primary />
## DialogWrapper Props
<Controls of={DialogWrapperStories.Default} />
## ConfirmDialog
For confirm/cancel flows with a title, description, and footer actions:
```tsx
import { ConfirmDialog, Button } from '@signozhq/ui';
export default function MyComponent() {
const [open, setOpen] = useState(false);
return (
<>
<Button onClick={() => setOpen(true)}>Delete</Button>
<ConfirmDialog
open={open}
onOpenChange={setOpen}
title="Confirm action"
confirmText="Delete"
cancelText="Cancel"
confirmColor="destructive"
onConfirm={() => setOpen(false)}
onCancel={() => setOpen(false)}
width="narrow"
>
Are you sure? This action cannot be undone.
</ConfirmDialog>
</>
);
}
```
## ConfirmDialog Props
<Controls of={ConfirmDialogStories.Default} />
## AlertDialog
For destructive or high-impact actions, with optional checkbox (e.g. “Don’t ask again”) and custom footer:
```tsx
import { AlertDialog, Button } from '@signozhq/ui';
export default function MyComponent() {
const [open, setOpen] = useState(false);
const [dontAskAgain, setDontAskAgain] = useState(false);
return (
<AlertDialog
open={open}
onOpenChange={setOpen}
title="Delete this step"
checkboxLabel="Do not ask me this again"
checkboxChecked={dontAskAgain}
onCheckboxChange={setDontAskAgain}
trigger={<Button>Delete</Button>}
footer={
<>
<Button variant="ghost" onClick={() => setOpen(false)}>Cancel</Button>
<Button color="destructive" onClick={() => setOpen(false)}>Delete</Button>
</>
}
>
Deleting this step would stop further analytics using this step.
</AlertDialog>
);
}
```
## AlertDialog Props
<Controls of={AlertDialogStories.Default} />
## ConfirmDialogUrl
For confirm dialogs controlled via a URL query parameter:
> This component requires the setup with [nuqs](https://nuqs.dev/).
```tsx
import { ConfirmDialogUrl, Button } from '@signozhq/ui';
import { useQueryState, parseAsBoolean } from 'nuqs';
export default function MyComponent() {
const [, setOpen] = useQueryState('dialog-delete-step', parseAsBoolean.withDefault(false));
return (
<>
<Button
variant="solid"
color="primary"
onClick={() => setOpen(true)}
>
Open confirm dialog (URL)
</Button>
<ConfirmDialogUrl
urlKey="dialog-delete-step"
title="Delete from URL param"
confirmText="Delete"
cancelText="Cancel"
confirmColor="destructive"
onConfirm={async () => {
// Simulate async work, this will change the button to loading state
await new Promise((resolve) => setTimeout(resolve, 300));
return true;
}}
width="narrow"
>
This confirm dialog is controlled via a URL query parameter using nuqs.
</ConfirmDialogUrl>
</>
);
}
```
## ConfirmDialogUrl Props
<Controls of={ConfirmDialogUrlStories.Default} />
## Primitive composition
For full control, use the low-level building blocks: `Dialog`, `DialogTrigger`, `DialogContent`, `DialogHeader`, `DialogTitle`, `DialogDescription`, `DialogFooter`, and `DialogClose`.
### Exit animations
To animate the dialog on close, wrap `DialogContent` in `AnimatePresence` and pass `forceMount` plus a stable `key`:
```tsx
import {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogFooter,
DialogClose,
Button,
} from '@signozhq/ui';
import { AnimatePresence } from 'motion/react';
export default function MyComponent() {
const [open, setOpen] = useState(false);
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button>Open</Button>
</DialogTrigger>
<AnimatePresence>
{open && (
<DialogContent key="dialog" width="base" forceMount>
<DialogHeader>
<DialogTitle>Title</DialogTitle>
</DialogHeader>
<DialogDescription>
Description and body content.
</DialogDescription>
<DialogFooter>
<Button variant="ghost" onClick={() => setOpen(false)}>Cancel</Button>
<DialogClose asChild>
<Button>Confirm</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
)}
</AnimatePresence>
</Dialog>
);
}
```
Without `AnimatePresence`, `forceMount`, and `key`, the dialog closes instantly. `DialogWrapper` uses this pattern internally when `open` and `onOpenChange` are provided.
## Dialog Props
<Controls of={DialogPrimitiveStories.Default} />
## DialogTrigger Props
<Controls of={DialogTriggerStories.Default} />
## DialogContent Props
<Controls of={DialogContentStories.Default} />
## DialogHeader Props
<Controls of={DialogHeaderStories.Default} />
## DialogTitle Props
<Controls of={DialogTitleStories.Default} />
## DialogDescription Props
<Controls of={DialogDescriptionStories.Default} />
## DialogFooter Props
<Controls of={DialogFooterStories.Default} />
## DialogClose Props
<Controls of={DialogCloseStories.Default} />
## DialogOverlay Props
<Controls of={DialogOverlayStories.Default} />
## DialogPortal Props
<Controls of={DialogPortalStories.Default} />