diff --git a/apps/docs/src/config/sidebarConfig.ts b/apps/docs/src/config/sidebarConfig.ts index f55870d..4326eb9 100644 --- a/apps/docs/src/config/sidebarConfig.ts +++ b/apps/docs/src/config/sidebarConfig.ts @@ -116,6 +116,11 @@ export const sidebarConfig: DocsConfig = { label: "Checkbox Group", href: "/components/checkbox-group", }, + { + label: "Dialog", + href: "/components/dialog", + new: true, + }, { label: "Dropdown Menu", href: "/components/dropdown-menu", diff --git a/apps/docs/src/content/components/dialog.mdx b/apps/docs/src/content/components/dialog.mdx new file mode 100644 index 0000000..2c2bf14 --- /dev/null +++ b/apps/docs/src/content/components/dialog.mdx @@ -0,0 +1,115 @@ +--- +title: Dialog +description: A window overlaid on either the primary window or another dialog window, rendering the content underneath inert. +links: + source: https://github.com/lmsqueezy/wedges/blob/main/packages/wedges/src/components/Dialog/Dialog.tsx + radix: https://www.radix-ui.com/docs/primitives/components/dialog +--- + + + + +### Usage + +```tsx +import { Dialog } from "@lemonsqueezy/wedges"; +``` + +```tsx showLineNumbers + + Dialog content goes here. + +``` + +For more advanced usage, you can use the Dialog.Root component to compose your own Dialog. These components include pre-defined styles and accessiblity features. + +```tsx showLineNumbers + + Open Dialog + + + Dialog Title + Dialog Description + + + Dialog content goes here. + + + Dialog footer goes here. + + + +``` + +### API Reference + +#### Dialog +The Wedges component of the Dialog. In most cases this is the only Dialog component you will need to use. + + void" }, {}], + [{ value: "title" }, { value: "ReactNode" }, {}], + [{ value: "description" }, { value: "ReactNode" }, {}], + [{ value: "size" }, { value: '"sm" | "md" | "lg" | "xl"' }, { value: '"md"' }], + [{ value: "container" }, { value: "HTMLElement" }, { value: "document.body" }], + ]} +/> + +#### Dialog.Content + +Extends the Radix Dialog Content primitive with custom configuration. + + + +#### Dialog.Header + + + +#### Dialog.Root + +Extends the Radix Dialog Root primitive. + +#### Dialog.Overlay + +Extends the Radix Dialog Overlay primitive. + +#### Dialog.Title + +Extends the Radix Dialog Title primitive. + +#### Dialog.Description + +Extends the Radix Dialog Description primitive. + +#### Dialog.Trigger + +Extends the Radix Dialog Trigger primitive. + +#### Dialog.Footer + +Extends the Radix Dialog Footer primitive. + +#### Dialog.Close + +Extends the Radix Dialog Close primitive. + +### Examples + + + \ No newline at end of file diff --git a/apps/docs/src/examples/dialog/example-1.tsx b/apps/docs/src/examples/dialog/example-1.tsx new file mode 100644 index 0000000..ac10911 --- /dev/null +++ b/apps/docs/src/examples/dialog/example-1.tsx @@ -0,0 +1,30 @@ +import { useRef } from "react"; +import { Button, Dialog } from "@lemonsqueezy/wedges"; + +export default function Example() { + // You most likely don't need to use `containerRef` in your implementation. This is just for preview. + const containerRef = useRef(null); + + return ( +
+ + + + + + + + Dialog Custom Close + Dialog with custom close button + + Dialog content goes here. + + + + + + + +
+ ); +} diff --git a/apps/docs/src/examples/dialog/example-2.tsx b/apps/docs/src/examples/dialog/example-2.tsx new file mode 100644 index 0000000..e34a985 --- /dev/null +++ b/apps/docs/src/examples/dialog/example-2.tsx @@ -0,0 +1,30 @@ +import { useRef, useState } from "react"; +import { Button, Dialog } from "@lemonsqueezy/wedges"; + +export default function Example() { + // You most likely don't need to use `containerRef` in your implementation. This is just for preview. + const containerRef = useRef(null); + const [open, setOpen] = useState(false); + + return ( +
+ + + + Dialog content goes here. + + + + +
+ ); +} diff --git a/apps/docs/src/examples/dialog/preview.tsx b/apps/docs/src/examples/dialog/preview.tsx new file mode 100644 index 0000000..36348fd --- /dev/null +++ b/apps/docs/src/examples/dialog/preview.tsx @@ -0,0 +1,25 @@ +import { useRef, useState } from "react"; +import { Button, Dialog } from "@lemonsqueezy/wedges"; + +export default function Example() { + // You most likely don't need to use `containerRef` in your implementation. This is just for preview. + const containerRef = useRef(null); + const [open, setOpen] = useState(false); + + return ( +
+ + + + Dialog content goes here. + +
+ ); +} diff --git a/apps/docs/src/examples/index.ts b/apps/docs/src/examples/index.ts index af92f5c..f9f4bf0 100644 --- a/apps/docs/src/examples/index.ts +++ b/apps/docs/src/examples/index.ts @@ -1377,6 +1377,103 @@ export function Example() { ); } +`, + }, + "dialog/example-1": { + component: lazy(() => import("@/examples/dialog/example-1.tsx")), + code: `import { useRef } from "react"; +import { Button, Dialog } from "@lemonsqueezy/wedges"; + +export function Example() { + // You most likely don't need to use \`containerRef\` in your implementation. This is just for preview. + const containerRef = useRef(null); + + return ( +
+ + + + + + + + Dialog Custom Close + Dialog with custom close button + + Dialog content goes here. + + + + + + + +
+ ); +} +`, + }, + "dialog/example-2": { + component: lazy(() => import("@/examples/dialog/example-2.tsx")), + code: `import { useRef, useState } from "react"; +import { Button, Dialog } from "@lemonsqueezy/wedges"; + +export function Example() { + // You most likely don't need to use \`containerRef\` in your implementation. This is just for preview. + const containerRef = useRef(null); + const [open, setOpen] = useState(false); + + return ( +
+ + + + Dialog content goes here. + + + + +
+ ); +} +`, + }, + "dialog/preview": { + component: lazy(() => import("@/examples/dialog/preview.tsx")), + code: `import { useRef, useState } from "react"; +import { Button, Dialog } from "@lemonsqueezy/wedges"; + +export function Example() { + // You most likely don't need to use \`containerRef\` in your implementation. This is just for preview. + const containerRef = useRef(null); + const [open, setOpen] = useState(false); + + return ( +
+ + + + Dialog content goes here. + +
+ ); +} `, }, "dropdown-menu/example-1": { diff --git a/packages/wedges/package.json b/packages/wedges/package.json index 8e24529..5fa57cb 100644 --- a/packages/wedges/package.json +++ b/packages/wedges/package.json @@ -70,6 +70,7 @@ "@iconicicons/react": "latest", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-checkbox": "^1.0.4", + "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-popover": "^1.0.7", diff --git a/packages/wedges/src/components/Dialog/Dialog.tsx b/packages/wedges/src/components/Dialog/Dialog.tsx new file mode 100644 index 0000000..9439f39 --- /dev/null +++ b/packages/wedges/src/components/Dialog/Dialog.tsx @@ -0,0 +1,148 @@ +import * as React from "react"; +import { CloseIcon } from "@iconicicons/react"; +import * as DialogPrimitive from "@radix-ui/react-dialog"; + +import { cn } from "../../helpers/utils"; +import { Button } from "../Button"; +import { dialogVariants } from "./variants"; + +/* ---------------------------------- Types --------------------------------- */ +export type DialogElement = React.ElementRef; +export type DialogElementProps = React.ComponentPropsWithoutRef & + DialogHeaderElementProps & + DialogContentElementProps; + +export type DialogHeaderElement = React.ElementRef<"div">; +export type DialogHeaderElementProps = React.ComponentPropsWithoutRef<"div"> & { + title?: React.ReactNode; + description?: React.ReactNode; +}; + +export type DialogContentElement = React.ElementRef; +export type DialogContentElementProps = React.ComponentPropsWithoutRef< + typeof DialogPrimitive.Content +> & { + size?: keyof typeof dialogVariants; + container?: DialogPrimitive.DialogPortalProps["container"]; +}; + +/* ------------------------------- Components ------------------------------- */ + +const DialogRoot = React.forwardRef( + ({ title, description, size, container, className, ...props }, ref) => ( + + + + {props.children} + + + ) +); + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +const DialogHeader = React.forwardRef( + ({ title, description, children, className, ...props }, ref) => ( +
+ {title && {title}} + {description && {description}} + {children} +
+ ) +); + +const DialogContent = React.forwardRef( + ({ className, size, container, children, ...props }, ref) => ( + + + + {children} + +