Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 21 additions & 17 deletions packages/demo/src/components/demo/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
Button,
DialogDescription,
Dialog,
DialogContainer,
DialogContent,
DialogHeader,
DialogTitle,
Expand All @@ -27,11 +28,12 @@ export const DialogDemo = ({
Open Dialog
</Button>
<Dialog open={isModalOpen} onOpenChange={() => setIsModalOpen(false)}>
<DialogContent size={size}>
<DialogContainer size={size}>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
<DialogDescription>Dialog Subtitle</DialogDescription>
</DialogHeader>
<DialogDescription>
<DialogContent>
{showMaxHeight ? (
<>
This is example content to demonstrate the max height behavior
Expand Down Expand Up @@ -101,7 +103,7 @@ export const DialogDemo = ({
nisi ut aliquip ex ea commodo consequat.
</>
)}
</DialogDescription>
</DialogContent>
<DialogFooter>
<Button
size="sm"
Expand All @@ -111,7 +113,7 @@ export const DialogDemo = ({
Close
</Button>
</DialogFooter>
</DialogContent>
</DialogContainer>
</Dialog>
</div>
);
Expand All @@ -126,21 +128,23 @@ export const DialogWithTableDemo = () => {
Open Dialog
</Button>
<Dialog open={isModalOpen} onOpenChange={() => setIsModalOpen(false)}>
<DialogContent>
<DialogContainer>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
<DialogDescription>Dialog Description</DialogDescription>
</DialogHeader>
<DialogDescription>Dialog Description</DialogDescription>
<Card elevation={ELEVATION.FLOATING}>
<CardContent>
<div className="space-y-2">
<h4 className="font-medium">Card</h4>
<p className="text-text-secondary text-sm">
This card has an elevation of Floating.
</p>
</div>
</CardContent>
</Card>
<DialogContent>
<Card elevation={ELEVATION.FLOATING}>
<CardContent>
<div className="space-y-2">
<h4 className="font-medium">Card</h4>
<p className="text-text-secondary text-sm">
This card has an elevation of Floating.
</p>
</div>
</CardContent>
</Card>
</DialogContent>
<DialogFooter>
<Button
size="sm"
Expand All @@ -150,7 +154,7 @@ export const DialogWithTableDemo = () => {
Close
</Button>
</DialogFooter>
</DialogContent>
</DialogContainer>
</Dialog>
</div>
);
Expand Down
109 changes: 93 additions & 16 deletions packages/demo/src/content/components/dialog.mdx
Original file line number Diff line number Diff line change
@@ -1,25 +1,62 @@
---
layout: "@demo/layouts/mdx-layout.astro"
heading: "Dialog"
description: "Dialog with sizes and variants"
description: "A modal dialog component with customizable sizes"
---

import { DialogDemo } from "@demo/components/demo/dialog";
import { DialogDemo, DialogWithTableDemo } from "@demo/components/demo/dialog";

## Size Variants
## Overview

The Dialog component provides a modal overlay for displaying content that requires user interaction to proceed. It can be useful for guiding the user through a form, or focusing their attention away from the rest of the app.

## Usage

Import the dialog components:

```ts
import {
Dialog,
DialogContainer,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogFooter,
} from "@eqtylab/equality";
```

The dialog component supports three size variants for controlling its maximum width: **small**, **medium**, and **large**. You can set the desired variant using the `size` prop: `"sm"`, `"md"`, or `"lg"`. By default, the dialog uses the medium size.
Basic usage with required properties:

Below are examples of each size variant:
```jsx
import { useState } from "react";

const [isOpen, setIsOpen] = useState(false);

<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogContainer>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
<DialogDescription>Dialog description text</DialogDescription>
</DialogHeader>
<DialogContent>Your content here</DialogContent>
<DialogFooter>
<Button onClick={() => setIsOpen(false)}>Close</Button>
</DialogFooter>
</DialogContainer>
</Dialog>;
```

## Size Variants

The dialog component supports three size variants for controlling its maximum width: `small`, `medium`, and `large`. Set the size using the `size` prop on `DialogContainer`. By default, the dialog uses the `medium` size.

### Small

Recommended for compact dialogs (max width: 32rem / 512px).

```jsx
<Dialog open={isModalOpen} onOpenChange={() => setIsModalOpen(false)}>
<DialogContent size="sm">...</DialogContent>
</Dialog>
<DialogContainer size="sm">...</DialogContainer>
```

<DialogDemo client:only="react" size="sm" />
Expand All @@ -29,9 +66,7 @@ Recommended for compact dialogs (max width: 32rem / 512px).
Recommended for typical dialog uses (max width: 42rem / 672px).

```jsx
<Dialog open={isModalOpen} onOpenChange={() => setIsModalOpen(false)}>
<DialogContent size="md">...</DialogContent>
</Dialog>
<DialogContainer size="md">...</DialogContainer>
```

<DialogDemo client:only="react" size="md" />
Expand All @@ -41,15 +76,57 @@ Recommended for typical dialog uses (max width: 42rem / 672px).
Recommended for dialogs that need extra horizontal space (max width: 56rem / 896px).

```jsx
<Dialog open={isModalOpen} onOpenChange={() => setIsModalOpen(false)}>
<DialogContent size="lg">...</DialogContent>
</Dialog>
<DialogContainer size="lg">...</DialogContainer>
```

<DialogDemo client:only="react" size="lg" />

## Constraints
## Scrolling Content

The dialog component enforces a maximum height of 85% of the viewport (85vh). If the dialog content exceeds this height, a vertical scrollbar will appear inside the dialog, allowing users to scroll through the overflowing content without affecting the background page.
The dialog component enforces a maximum height of 85% of the viewport (85vh). If the dialog content exceeds this height, a vertical scrollbar will appear inside the `DialogContent` area, allowing users to scroll through overflowing content without affecting the background page.

<DialogDemo client:only="react" size="md" showMaxHeight />

## Nested Content

You can nest other components like cards within the dialog content area. The `DialogContent` component provides proper spacing and scrolling behavior.

<DialogWithTableDemo client:only="react" />

## Slots

The Dialog component is composed of several sub-components:

| Name | Description |
| ------------------- | -------------------------------------------------------------- |
| `Dialog` | Root component that manages the dialog state |
| `DialogContainer` | The dialog content wrapper with size variants |
| `DialogHeader` | Header section containing title, description, and close button |
| `DialogTitle` | The dialog's title (required for accessibility) |
| `DialogDescription` | Optional description text |
| `DialogContent` | Scrollable content area for the dialog body |
| `DialogFooter` | Footer section typically containing action buttons |
| `DialogTrigger` | Button or element that opens the dialog |
| `DialogClose` | Element that closes the dialog when clicked |

## Props

### DialogContainer

| Name | Description | Type | Default | Required |
| ---------- | ------------------------------------------------- | ---------------- | ------- | -------- |
| `size` | Controls the maximum width of the dialog | `sm`, `md`, `lg` | `md` | ❌ |
| `children` | Dialog content including header, body, and footer | `ReactNode` | - | ✅ |

### Dialog

| Name | Description | Type | Default | Required |
| -------------- | ------------------------------------------- | ------------------------- | ------- | -------- |
| `open` | Controls whether the dialog is open | `boolean` | - | ✅ |
| `onOpenChange` | Callback when the dialog open state changes | `(open: boolean) => void` | - | ✅ |

### DialogTitle

| Name | Description | Type | Default | Required |
| ---------- | -------------- | ----------- | ------- | -------- |
| `children` | The title text | `ReactNode` | - | ✅ |
11 changes: 9 additions & 2 deletions packages/ui/src/components/dialog/dialog.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,26 @@
}

.dialog-header {
@apply flex shrink-0 items-baseline justify-between gap-4;
@apply flex shrink-0 items-start justify-between gap-4;
@apply text-left;
@apply border-b-1 border-border;
@apply px-6 py-3;
}

.dialog-header-content {
@apply flex min-w-0 flex-1 flex-col;
}

.dialog-title {
@apply text-lg font-medium leading-none tracking-tight;
@apply min-w-0 flex-1;
}

.dialog-description {
@apply text-text-secondary text-sm;
@apply mt-1;
}

.dialog-body {
@apply min-h-0 flex-1 overflow-auto;
@apply p-6;
}
Expand Down
18 changes: 12 additions & 6 deletions packages/ui/src/components/dialog/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ const DialogOverlay = React.forwardRef<
));
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;

type DialogContentProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
type DialogContainerProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
size?: 'sm' | 'md' | 'lg';
};

const DialogContent = React.forwardRef<
const DialogContainer = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
DialogContentProps
DialogContainerProps
>(({ className, children, size = 'md', ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
Expand All @@ -50,11 +50,11 @@ const DialogContent = React.forwardRef<
</DialogPrimitive.Content>
</DialogPortal>
));
DialogContent.displayName = DialogPrimitive.Content.displayName;
DialogContainer.displayName = DialogPrimitive.Content.displayName;

const DialogHeader = ({ className, children, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn(styles['dialog-header'], className)} {...props}>
{children}
<div className={styles['dialog-header-content']}>{children}</div>
<DialogPrimitive.Close asChild>
<IconButton name="X" label="Close" size="sm" />
</DialogPrimitive.Close>
Expand All @@ -81,15 +81,21 @@ const DialogDescription = React.forwardRef<
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn(styles['dialog-description'], 'styled-vertical-scrollbar', className)}
className={cn(styles['dialog-description'], className)}
{...props}
/>
));
DialogDescription.displayName = DialogPrimitive.Description.displayName;

const DialogContent = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn(styles['dialog-body'], 'styled-vertical-scrollbar', className)} {...props} />
);
DialogContent.displayName = 'DialogContent';

export {
Dialog,
DialogClose,
DialogContainer,
DialogContent,
DialogDescription,
DialogFooter,
Expand Down
Loading