Skip to content
Closed
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
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"use client";
import { DialogContainer } from "@/components/dialog-container";
import { toast } from "@/components/ui/toaster";
import { formatNumber } from "@/lib/fmt";
import { trpc } from "@/lib/trpc/client";
import { zodResolver } from "@hookform/resolvers/zod";
import { Lock } from "@unkey/icons";
import { DialogContainer } from "@unkey/ui";
import { Button, Input, SettingCard } from "@unkey/ui";
import { useRouter } from "next/navigation";
import type React from "react";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"use client";
import { DialogContainer } from "@/components/dialog-container";
import { toast } from "@/components/ui/toaster";
import { trpc } from "@/lib/trpc/client";
import { zodResolver } from "@hookform/resolvers/zod";
import { ArrowUpRight, TriangleWarning2 } from "@unkey/icons";
import { DialogContainer } from "@unkey/ui";
import { InlineLink, Input, SettingCard } from "@unkey/ui";
import { Button } from "@unkey/ui";
import { useRouter } from "next/navigation";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"use client";
import { revalidateTag } from "@/app/actions";
import { DialogContainer } from "@/components/dialog-container";
import { toast } from "@/components/ui/toaster";
import { tags } from "@/lib/cache";
import { trpc } from "@/lib/trpc/client";
import { zodResolver } from "@hookform/resolvers/zod";
import { DialogContainer } from "@unkey/ui";
import { Button, FormInput, FormTextarea } from "@unkey/ui";
import { validation } from "@unkey/validation";
import { useRouter } from "next/navigation";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"use client";
import { revalidate } from "@/app/actions";
import { DialogContainer } from "@/components/dialog-container";
import { toast } from "@/components/ui/toaster";
import { trpc } from "@/lib/trpc/client";
import { zodResolver } from "@hookform/resolvers/zod";
import { DialogContainer } from "@unkey/ui";
import { Button, Input } from "@unkey/ui";
import { useRouter } from "next/navigation";
import { useState } from "react";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"use client";
import { DialogContainer } from "@/components/dialog-container";
import { toast } from "@/components/ui/toaster";
import { trpc } from "@/lib/trpc/client";
import { zodResolver } from "@hookform/resolvers/zod";
import { DialogContainer } from "@unkey/ui";
import { Button, Input } from "@unkey/ui";
import { useRouter } from "next/navigation";
import { useState } from "react";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"use client";

import { DialogContainer } from "@/components/dialog-container";
import { toast } from "@/components/ui/toaster";
import { trpc } from "@/lib/trpc/client";
import { zodResolver } from "@hookform/resolvers/zod";
import { DialogContainer } from "@unkey/ui";
import { Button, Input } from "@unkey/ui";
import type { PropsWithChildren } from "react";
import { useForm } from "react-hook-form";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
"use client";

import { DialogContainer } from "@/components/dialog-container";
import { Badge } from "@/components/ui/badge";
import { toast } from "@/components/ui/toaster";
import { trpc } from "@/lib/trpc/client";
import { zodResolver } from "@hookform/resolvers/zod";
import { CircleInfo } from "@unkey/icons";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@unkey/ui";
import { Button, FormInput } from "@unkey/ui";
import {
Button,
DialogContainer,
FormInput,
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@unkey/ui";
import type { PropsWithChildren } from "react";
import { Controller, useForm } from "react-hook-form";
import { z } from "zod";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"use client";

import { revalidateTag } from "@/app/actions";
import { DialogContainer } from "@/components/dialog-container";
import { toast } from "@/components/ui/toaster";
import { tags } from "@/lib/cache";
import { trpc } from "@/lib/trpc/client";
import { zodResolver } from "@hookform/resolvers/zod";
import { DialogContainer } from "@unkey/ui";
import { Button, Input } from "@unkey/ui";
import { useRouter } from "next/navigation";
import { useForm } from "react-hook-form";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"use client";

import { revalidate } from "@/app/actions";
import { DialogContainer } from "@/components/dialog-container";
import { NavbarActionButton } from "@/components/navigation/action-button";
import { toast } from "@/components/ui/toaster";
import { trpc } from "@/lib/trpc/client";
import { zodResolver } from "@hookform/resolvers/zod";
import { DialogContainer } from "@unkey/ui";
import { Button, FormInput } from "@unkey/ui";
import { Plus } from "lucide-react";
import { useRouter } from "next/navigation";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { DialogContainer } from "@/components/dialog-container";
import { DialogContainer } from "@unkey/ui";
import { Button } from "@unkey/ui";
import { useState } from "react";

Expand Down
12 changes: 9 additions & 3 deletions apps/dashboard/app/(app)/settings/team/invite.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"use client";
import { DialogContainer } from "@/components/dialog-container";
import {
Form,
FormControl,
Expand All @@ -14,8 +13,15 @@ import { toast } from "@/components/ui/toaster";
import type { AuthenticatedUser, Organization } from "@/lib/auth/types";
import { trpc } from "@/lib/trpc/client";
import { zodResolver } from "@hookform/resolvers/zod";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@unkey/ui";
import { Button } from "@unkey/ui";
import {
Button,
DialogContainer,
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@unkey/ui";
import { Plus } from "lucide-react";
import type React from "react";
import { useState } from "react";
Expand Down
2 changes: 1 addition & 1 deletion apps/dashboard/app/auth/sign-in/org-selector.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { DialogContainer } from "@/components/dialog-container";
import { DialogContainer } from "@unkey/ui";

import type { Organization } from "@/lib/auth/types";
import { Button } from "@unkey/ui";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"use client";
import { RenderComponentWithSnippet } from "@/app/components/render";
import { DialogContainer } from "@unkey/ui";
import { Button, Input } from "@unkey/ui";
import { useState } from "react";

export function DialogContainerExample() {
const [isOpen, setIsOpen] = useState(false);
const [inputValue, setInputValue] = useState("");
const [inputResult, setInputResult] = useState("");

const handleSubmit = () => {
setInputResult(inputValue);
setIsOpen(false);
};

return (
<RenderComponentWithSnippet>
<div className="flex flex-row gap-2 justify-center">
<div className="flex flex-col gap-2 w-[200px]">
<Button className="text-gray-11 text-[13px]" onClick={() => setIsOpen(!isOpen)}>
Open Dialog
</Button>

<DialogContainer
isOpen={isOpen}
onOpenChange={() => setIsOpen(!isOpen)}
subTitle="This is an example of a subTitle. Normally used to describe the dialog"
title="Example Dialog Title"
footer={
<div className="flex flex-col w-full gap-2 items-center justify-center">
<Button
type="submit"
variant="primary"
size="lg"
className="w-full"
onClick={() => handleSubmit()}
>
Submit
</Button>
<div className="text-error-11 text-xs">
This is an example of a footer with a button for actions needed to be done
</div>
</div>
}
>
<div className="flex flex-col text-gray-11 text-[13px] gap-2">
<p>Dialog Content</p>
<Input
placeholder="Example Input"
type="text"
onChange={(e) => setInputValue(e.target.value)}
/>
</div>
</DialogContainer>
<p>
Input Result: <span className="text-success-6">{inputResult}</span>
</p>
</div>
</div>
</RenderComponentWithSnippet>
);
}
36 changes: 36 additions & 0 deletions apps/engineering/content/design/components/dialog-container.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: Dialog Container
---
import { DialogContainerExample } from "./dialog-container.example"

## Dialog Container

The Dialog Container is a flexible modal component that provides a consistent way to display content in a modal dialog. It's built on top of Radix UI's Dialog primitive with additional styling and functionality.

### Features

- Accessible modal implementation
- Customizable overlay and content styling
- Close button with warning support
- Keyboard navigation support
- Customizable animations
- Responsive design

### Usage

<DialogContainerExample />

### Props

| Prop | Type | Default | Description |
|-------------------|-------------------------|-----------|--------------------------------------------------|
| isOpen | boolean | - | Controls the open state of the dialog |
| onOpenChange | (value: boolean) => void | - | Callback when the open state changes |
| title | string | - | The title of the dialog |
| subTitle | string | - | Optional subtitle for the dialog |
| footer | ReactNode | - | Optional footer content |
| className | string | - | Additional classes for the dialog container |
| contentClassName | string | - | Additional classes for the dialog content |
| preventAutoFocus | boolean | false | Whether to prevent auto-focus on open |
| children | ReactNode | - | The content to display in the dialog |

1 change: 1 addition & 0 deletions internal/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
},
"dependencies": {
"@radix-ui/colors": "^3.0.0",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tooltip": "^1.0.7",
Expand Down
52 changes: 52 additions & 0 deletions internal/ui/src/components/dialog/dialog-container.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"use client";
import type { PropsWithChildren, ReactNode } from "react";
// biome-ignore lint: React in this context is used throughout, so biome will change to types because no APIs are used even though React is needed.
import React from "react";
import { cn } from "../../lib/utils";
import { Dialog, DialogContent } from "./dialog";
import { DefaultDialogContentArea, DefaultDialogFooter, DefaultDialogHeader } from "./dialog-parts";

type DialogContainerProps = PropsWithChildren<{
className?: string;
isOpen: boolean;
onOpenChange: (value: boolean) => void;
title: string;
footer?: ReactNode;
contentClassName?: string;
preventAutoFocus?: boolean;
subTitle?: string;
}>;

export const DialogContainer = ({
className,
isOpen,
subTitle,
onOpenChange,
title,
children,
footer,
contentClassName,
preventAutoFocus = true,
}: DialogContainerProps) => {
return (
<Dialog open={isOpen} onOpenChange={onOpenChange}>
<DialogContent
className={cn(
"drop-shadow-2xl border-gray-4 overflow-hidden !rounded-2xl p-0 gap-0",
className,
)}
onOpenAutoFocus={(e: Event) => {
if (preventAutoFocus) {
e.preventDefault();
}
}}
>
<DefaultDialogHeader title={title} subTitle={subTitle} />
<DefaultDialogContentArea className={contentClassName}>{children}</DefaultDialogContentArea>
{footer && <DefaultDialogFooter>{footer}</DefaultDialogFooter>}
</DialogContent>
</Dialog>
);
};

export { DefaultDialogHeader, DefaultDialogContentArea, DefaultDialogFooter };
59 changes: 59 additions & 0 deletions internal/ui/src/components/dialog/dialog-parts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"use client";

// biome-ignore lint: React in this context is used throughout, so biome will change to types because no APIs are used even though React is needed.
import * as React from "react";
import type { PropsWithChildren } from "react";
import { cn } from "../../lib/utils";
import {
DialogFooter as ShadcnDialogFooter,
DialogHeader as ShadcnDialogHeader,
DialogTitle as ShadcnDialogTitle,
} from "./dialog";

type DefaultDialogHeaderProps = {
title: string;
subTitle?: string;
className?: string;
};

export const DefaultDialogHeader = ({ title, subTitle, className }: DefaultDialogHeaderProps) => {
return (
<ShadcnDialogHeader className={cn("border-b border-gray-4 bg-white dark:bg-black", className)}>
<ShadcnDialogTitle className="px-6 py-4 text-gray-12 font-medium text-base flex flex-col">
<span className="leading-[32px]">{title}</span>
{subTitle && ( // Conditionally render subtitle span only if it exists
<span className="text-gray-9 leading-[20px] text-[13px] font-normal">{subTitle}</span>
)}
</ShadcnDialogTitle>
</ShadcnDialogHeader>
);
};

type DefaultDialogContentAreaProps = PropsWithChildren<{
className?: string;
}>;

export const DefaultDialogContentArea = ({
children,
className,
}: DefaultDialogContentAreaProps) => {
return (
<div className={cn("bg-grayA-2 flex flex-col gap-4 py-4 px-6 text-gray-11", className)}>
{children}
</div>
);
};

type DefaultDialogFooterProps = PropsWithChildren<{
className?: string;
}>;

export const DefaultDialogFooter = ({ children, className }: DefaultDialogFooterProps) => {
return (
<ShadcnDialogFooter
className={cn("p-6 border-t border-grayA-4 bg-white dark:bg-black text-gray-9", className)}
>
{children}
</ShadcnDialogFooter>
);
};
Loading
Loading