diff --git a/packages/demo/src/components/demo/dialog.tsx b/packages/demo/src/components/demo/dialog.tsx index 56ef6dca..3c60c71d 100644 --- a/packages/demo/src/components/demo/dialog.tsx +++ b/packages/demo/src/components/demo/dialog.tsx @@ -2,6 +2,7 @@ import { Button, DialogDescription, Dialog, + DialogContainer, DialogContent, DialogHeader, DialogTitle, @@ -27,11 +28,12 @@ export const DialogDemo = ({ Open Dialog setIsModalOpen(false)}> - + Dialog Title + Dialog Subtitle - + {showMaxHeight ? ( <> This is example content to demonstrate the max height behavior @@ -101,7 +103,7 @@ export const DialogDemo = ({ nisi ut aliquip ex ea commodo consequat. )} - + ); @@ -126,21 +128,23 @@ export const DialogWithTableDemo = () => { Open Dialog setIsModalOpen(false)}> - + Dialog Title + Dialog Description - Dialog Description - - -
-

Card

-

- This card has an elevation of Floating. -

-
-
-
+ + + +
+

Card

+

+ This card has an elevation of Floating. +

+
+
+
+
-
+
); diff --git a/packages/demo/src/content/components/dialog.mdx b/packages/demo/src/content/components/dialog.mdx index 98b8b470..360e2410 100644 --- a/packages/demo/src/content/components/dialog.mdx +++ b/packages/demo/src/content/components/dialog.mdx @@ -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 Title + Dialog description text + + Your content here + + + + +; +``` + +## 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 - setIsModalOpen(false)}> - ... - +... ``` @@ -29,9 +66,7 @@ Recommended for compact dialogs (max width: 32rem / 512px). Recommended for typical dialog uses (max width: 42rem / 672px). ```jsx - setIsModalOpen(false)}> - ... - +... ``` @@ -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 - setIsModalOpen(false)}> - ... - +... ``` -## 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. + +## Nested Content + +You can nest other components like cards within the dialog content area. The `DialogContent` component provides proper spacing and scrolling behavior. + + + +## 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` | - | ✅ | diff --git a/packages/ui/src/components/dialog/dialog.module.css b/packages/ui/src/components/dialog/dialog.module.css index e289eb60..0c730985 100644 --- a/packages/ui/src/components/dialog/dialog.module.css +++ b/packages/ui/src/components/dialog/dialog.module.css @@ -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; } diff --git a/packages/ui/src/components/dialog/dialog.tsx b/packages/ui/src/components/dialog/dialog.tsx index bf8b86c8..bd9c17ff 100644 --- a/packages/ui/src/components/dialog/dialog.tsx +++ b/packages/ui/src/components/dialog/dialog.tsx @@ -27,13 +27,13 @@ const DialogOverlay = React.forwardRef< )); DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; -type DialogContentProps = React.ComponentPropsWithoutRef & { +type DialogContainerProps = React.ComponentPropsWithoutRef & { size?: 'sm' | 'md' | 'lg'; }; -const DialogContent = React.forwardRef< +const DialogContainer = React.forwardRef< React.ElementRef, - DialogContentProps + DialogContainerProps >(({ className, children, size = 'md', ...props }, ref) => ( @@ -50,11 +50,11 @@ const DialogContent = React.forwardRef< )); -DialogContent.displayName = DialogPrimitive.Content.displayName; +DialogContainer.displayName = DialogPrimitive.Content.displayName; const DialogHeader = ({ className, children, ...props }: React.HTMLAttributes) => (
- {children} +
{children}
@@ -81,15 +81,21 @@ const DialogDescription = React.forwardRef< >(({ className, ...props }, ref) => ( )); DialogDescription.displayName = DialogPrimitive.Description.displayName; +const DialogContent = ({ className, ...props }: React.HTMLAttributes) => ( +
+); +DialogContent.displayName = 'DialogContent'; + export { Dialog, DialogClose, + DialogContainer, DialogContent, DialogDescription, DialogFooter,