mirror of
https://github.com/hanzoai/o11y-components.git
synced 2026-10-30 14:54:15 +00:00
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.
256 lines
6.4 KiB
Plaintext
256 lines
6.4 KiB
Plaintext
import { Meta, Controls, Primary } from '@storybook/addon-docs/blocks';
|
|
import * as DrawerStories from './drawer.stories';
|
|
import * as DrawerWrapperStories from './drawer-wrapper.stories';
|
|
import * as ConfirmDrawerStories from './confirm-drawer.stories';
|
|
import * as ConfirmDrawerUrlStories from './confirm-drawer-url.stories';
|
|
import * as DrawerTriggerStories from './drawer-trigger.stories';
|
|
import * as DrawerContentStories from './drawer-content.stories';
|
|
import * as DrawerHeaderStories from './drawer-header.stories';
|
|
import * as DrawerTitleStories from './drawer-title.stories';
|
|
import * as DrawerSubtitleStories from './drawer-subtitle.stories';
|
|
import * as DrawerDescriptionStories from './drawer-description.stories';
|
|
import * as DrawerFooterStories from './drawer-footer.stories';
|
|
import * as DrawerCloseStories from './drawer-close.stories';
|
|
import * as DrawerOverlayStories from './drawer-overlay.stories';
|
|
import * as DrawerPortalStories from './drawer-portal.stories';
|
|
|
|
<Meta of={DrawerStories} />
|
|
|
|
# Drawer
|
|
|
|
A slide-in drawer component that can appear from any edge of the screen, with support for header, content, and footer sections.
|
|
|
|
## How to use
|
|
|
|
### DrawerWrapper (preset)
|
|
|
|
`DrawerWrapper` is a higher-level preset built on top of the primitive drawer components. It wires
|
|
`DrawerHeader`, `DrawerTitle`, `DrawerSubtitle`, `DrawerDescription`, and `DrawerFooter` into a single
|
|
convenient API for common layouts with header, content, and optional footer:
|
|
|
|
```tsx
|
|
import { DrawerWrapper, Button } from '@signozhq/ui';
|
|
|
|
export default function MyComponent() {
|
|
return (
|
|
<DrawerWrapper
|
|
trigger={
|
|
<Button variant="solid" color="primary">
|
|
Open Drawer
|
|
</Button>
|
|
}
|
|
title="Drawer title"
|
|
subTitle="Optional subtitle for the drawer."
|
|
footer={
|
|
<div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
|
|
<Button variant="ghost">Cancel</Button>
|
|
<Button variant="solid" color="primary">
|
|
Save
|
|
</Button>
|
|
</div>
|
|
}
|
|
direction="right"
|
|
>
|
|
<p>Main content of the drawer goes here.</p>
|
|
</DrawerWrapper>
|
|
);
|
|
}
|
|
```
|
|
|
|
<Primary />
|
|
|
|
## DrawerWrapper Props
|
|
|
|
<Controls of={DrawerWrapperStories.Default} />
|
|
|
|
## ConfirmDrawer
|
|
|
|
For confirm/cancel flows with a title, description, and footer actions:
|
|
|
|
```tsx
|
|
import { ConfirmDrawer, Button } from '@signozhq/ui';
|
|
|
|
export default function MyComponent() {
|
|
const [open, setOpen] = useState(false);
|
|
|
|
return (
|
|
<>
|
|
<Button onClick={() => setOpen(true)}>Delete</Button>
|
|
<ConfirmDrawer
|
|
open={open}
|
|
onOpenChange={setOpen}
|
|
title="Confirm action"
|
|
confirmText="Delete"
|
|
cancelText="Cancel"
|
|
confirmColor="destructive"
|
|
onConfirm={() => setOpen(false)}
|
|
onCancel={() => setOpen(false)}
|
|
direction="right"
|
|
width="narrow"
|
|
>
|
|
Are you sure? This action cannot be undone.
|
|
</ConfirmDrawer>
|
|
</>
|
|
);
|
|
}
|
|
```
|
|
|
|
## ConfirmDrawer Props
|
|
|
|
<Controls of={ConfirmDrawerStories.Default} />
|
|
|
|
## ConfirmDrawerUrl
|
|
|
|
For confirm drawers controlled via a URL query parameter:
|
|
|
|
> This component requires the setup with [nuqs](https://nuqs.dev/).
|
|
|
|
```tsx
|
|
import { ConfirmDrawerUrl, Button } from '@signozhq/ui';
|
|
import { useQueryState, parseAsBoolean } from 'nuqs';
|
|
|
|
export default function MyComponent() {
|
|
const [, setOpen] = useQueryState('drawer-delete-step', parseAsBoolean.withDefault(false));
|
|
|
|
return (
|
|
<>
|
|
<Button
|
|
variant="solid"
|
|
color="primary"
|
|
onClick={() => setOpen(true)}
|
|
>
|
|
Open confirm drawer (URL)
|
|
</Button>
|
|
<ConfirmDrawerUrl
|
|
urlKey="drawer-delete-step"
|
|
title="Delete from URL param"
|
|
confirmText="Delete"
|
|
cancelText="Cancel"
|
|
confirmColor="destructive"
|
|
onConfirm={async () => {
|
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
return true;
|
|
}}
|
|
direction="right"
|
|
width="narrow"
|
|
>
|
|
This confirm drawer is controlled via a URL query parameter using nuqs.
|
|
</ConfirmDrawerUrl>
|
|
</>
|
|
);
|
|
}
|
|
```
|
|
|
|
## ConfirmDrawerUrl Props
|
|
|
|
<Controls of={ConfirmDrawerUrlStories.Default} />
|
|
|
|
## Primitive composition
|
|
|
|
For full control, use the low-level building blocks: `Drawer`, `DrawerTrigger`, `DrawerContent`, `DrawerHeader`, `DrawerTitle`, `DrawerDescription`, `DrawerFooter`, `DrawerClose`, `DrawerOverlay`, and `DrawerPortal`.
|
|
|
|
### Exit animations
|
|
|
|
To animate the drawer on close, wrap `DrawerContent` in `AnimatePresence` and pass `forceMount` plus a stable `key`:
|
|
|
|
```tsx
|
|
import {
|
|
Drawer,
|
|
DrawerTrigger,
|
|
DrawerContent,
|
|
DrawerHeader,
|
|
DrawerTitle,
|
|
DrawerDescription,
|
|
DrawerFooter,
|
|
DrawerClose,
|
|
Button,
|
|
} from '@signozhq/ui';
|
|
import { AnimatePresence } from 'motion/react';
|
|
|
|
export default function MyComponent() {
|
|
const [open, setOpen] = React.useState(false);
|
|
|
|
return (
|
|
<Drawer open={open} onOpenChange={setOpen}>
|
|
<DrawerTrigger asChild>
|
|
<Button variant="solid" color="primary">
|
|
Open drawer
|
|
</Button>
|
|
</DrawerTrigger>
|
|
<AnimatePresence>
|
|
{open && (
|
|
<DrawerContent key="drawer" forceMount>
|
|
<DrawerHeader>
|
|
<DrawerTitle>Drawer title</DrawerTitle>
|
|
</DrawerHeader>
|
|
<DrawerDescription>
|
|
<div style={{ fontSize: 14, lineHeight: 1.42857, color: '#4a5565' }}>
|
|
Description and body content. Use the primitive components when you need
|
|
lower-level control.
|
|
</div>
|
|
</DrawerDescription>
|
|
<DrawerFooter>
|
|
<Button variant="ghost" onClick={() => setOpen(false)}>
|
|
Cancel
|
|
</Button>
|
|
<DrawerClose asChild>
|
|
<Button variant="solid" color="primary">
|
|
Confirm
|
|
</Button>
|
|
</DrawerClose>
|
|
</DrawerFooter>
|
|
</DrawerContent>
|
|
)}
|
|
</AnimatePresence>
|
|
</Drawer>
|
|
);
|
|
}
|
|
```
|
|
|
|
Without `AnimatePresence`, `forceMount`, and `key`, the drawer closes instantly. `DrawerWrapper` uses this pattern internally when `open` and `onOpenChange` are provided.
|
|
|
|
## Drawer Props
|
|
|
|
<Controls of={DrawerStories.Default} />
|
|
|
|
## DrawerTrigger Props
|
|
|
|
<Controls of={DrawerTriggerStories.Default} />
|
|
|
|
## DrawerContent Props
|
|
|
|
<Controls of={DrawerContentStories.Default} />
|
|
|
|
## DrawerHeader Props
|
|
|
|
<Controls of={DrawerHeaderStories.Default} />
|
|
|
|
## DrawerTitle Props
|
|
|
|
<Controls of={DrawerTitleStories.Default} />
|
|
|
|
## DrawerSubtitle Props
|
|
|
|
<Controls of={DrawerSubtitleStories.Default} />
|
|
|
|
## DrawerDescription Props
|
|
|
|
<Controls of={DrawerDescriptionStories.Default} />
|
|
|
|
## DrawerFooter Props
|
|
|
|
<Controls of={DrawerFooterStories.Default} />
|
|
|
|
## DrawerClose Props
|
|
|
|
<Controls of={DrawerCloseStories.Default} />
|
|
|
|
## DrawerOverlay Props
|
|
|
|
<Controls of={DrawerOverlayStories.Default} />
|
|
|
|
## DrawerPortal Props
|
|
|
|
<Controls of={DrawerPortalStories.Default} />
|
|
|