From da07cf6ffeb89bd5b9ca358ae11addf68a638e7c Mon Sep 17 00:00:00 2001 From: shadcn Date: Thu, 15 Jan 2026 13:17:45 +0400 Subject: [PATCH] feat: add data-table dialog and drawer --- .../docs/components/base/data-table.mdx | 9 +- .../content/docs/components/base/dialog.mdx | 54 +-- .../content/docs/components/base/drawer.mdx | 22 +- .../docs/components/radix/data-table.mdx | 5 +- .../content/docs/components/radix/dialog.mdx | 54 +-- .../content/docs/components/radix/drawer.mdx | 26 +- apps/v4/examples/__index__.tsx | 118 ++--- .../v4/examples/base/dialog-chat-settings.tsx | 429 ------------------ apps/v4/examples/base/dialog-close-button.tsx | 4 +- .../examples/base/dialog-no-close-button.tsx | 35 +- .../base/dialog-scrollable-content.tsx | 57 ++- .../v4/examples/base/dialog-sticky-footer.tsx | 46 ++ apps/v4/examples/base/dialog-with-form.tsx | 50 -- .../base/dialog-with-sticky-footer.tsx | 52 --- .../base/drawer-scrollable-content.tsx | 5 +- ...drawer-with-sides.tsx => drawer-sides.tsx} | 5 +- ...-item-group.tsx => item-group-default.tsx} | 0 .../examples/radix/dialog-chat-settings.tsx | 396 ---------------- .../v4/examples/radix/dialog-close-button.tsx | 4 +- .../examples/radix/dialog-no-close-button.tsx | 7 - .../radix/dialog-scrollable-content.tsx | 7 +- ...ky-footer.tsx => dialog-sticky-footer.tsx} | 14 +- apps/v4/examples/radix/dialog-with-form.tsx | 50 -- ...drawer-with-sides.tsx => drawer-sides.tsx} | 0 24 files changed, 219 insertions(+), 1230 deletions(-) delete mode 100644 apps/v4/examples/base/dialog-chat-settings.tsx create mode 100644 apps/v4/examples/base/dialog-sticky-footer.tsx delete mode 100644 apps/v4/examples/base/dialog-with-form.tsx delete mode 100644 apps/v4/examples/base/dialog-with-sticky-footer.tsx rename apps/v4/examples/base/{drawer-with-sides.tsx => drawer-sides.tsx} (93%) rename apps/v4/examples/base/{default-item-group.tsx => item-group-default.tsx} (100%) delete mode 100644 apps/v4/examples/radix/dialog-chat-settings.tsx rename apps/v4/examples/radix/{dialog-with-sticky-footer.tsx => dialog-sticky-footer.tsx} (71%) delete mode 100644 apps/v4/examples/radix/dialog-with-form.tsx rename apps/v4/examples/radix/{drawer-with-sides.tsx => drawer-sides.tsx} (100%) diff --git a/apps/v4/content/docs/components/base/data-table.mdx b/apps/v4/content/docs/components/base/data-table.mdx index 10fcf8f117..8e42fcdc89 100644 --- a/apps/v4/content/docs/components/base/data-table.mdx +++ b/apps/v4/content/docs/components/base/data-table.mdx @@ -8,9 +8,10 @@ links: --- ## Introduction @@ -863,7 +864,7 @@ Add pagination controls to your table including page size and selection count. ```tsx @@ -876,7 +877,7 @@ A component to toggle column visibility. ```tsx diff --git a/apps/v4/content/docs/components/base/dialog.mdx b/apps/v4/content/docs/components/base/dialog.mdx index 6388e288e3..c1b0e52cc8 100644 --- a/apps/v4/content/docs/components/base/dialog.mdx +++ b/apps/v4/content/docs/components/base/dialog.mdx @@ -87,40 +87,30 @@ import { ## Examples -### Custom close button +### Custom Close Button + +Replace the default close control with your own button. -## Notes +### No Close Button -To use the `Dialog` component from within a `Context Menu` or `Dropdown Menu`, you must encase the `Context Menu` or -`Dropdown Menu` component in the `Dialog` component. +Use `showCloseButton={false}` to hide the close button. -```tsx showLineNumbers title="components/example-dialog-context-menu.tsx" {1, 26} - - - Right click - - Open - Download - - - Delete - - - - - - - Are you absolutely sure? - - This action cannot be undone. Are you sure you want to permanently - delete this file from our servers? - - - - - - - -``` + + +### Sticky Footer + +Keep actions visible while the content scrolls. + + + +### Scrollable Content + +Long content can scroll while the header stays in view. + + + +## API Reference + +See the [Base UI](https://base-ui.com/react/components/dialog#api-reference) documentation for more information. diff --git a/apps/v4/content/docs/components/base/drawer.mdx b/apps/v4/content/docs/components/base/drawer.mdx index 2d6e8f2382..d72166e135 100644 --- a/apps/v4/content/docs/components/base/drawer.mdx +++ b/apps/v4/content/docs/components/base/drawer.mdx @@ -7,11 +7,7 @@ links: doc: https://vaul.emilkowal.ski/getting-started --- - + ## About @@ -94,8 +90,24 @@ import { ## Examples +### Scrollable Content + +Keep actions visible while the content scrolls. + + + +### Sides + +Use the `direction` prop to set the side of the drawer. Available options are `top`, `right`, `bottom`, and `left`. + + + ### Responsive Dialog You can combine the `Dialog` and `Drawer` components to create a responsive dialog. This renders a `Dialog` component on desktop and a `Drawer` on mobile. + +## API Reference + +See the [Vaul documentation](https://vaul.emilkowal.ski/components/drawer) for the full API reference. diff --git a/apps/v4/content/docs/components/radix/data-table.mdx b/apps/v4/content/docs/components/radix/data-table.mdx index 1495103583..8e42fcdc89 100644 --- a/apps/v4/content/docs/components/radix/data-table.mdx +++ b/apps/v4/content/docs/components/radix/data-table.mdx @@ -1,7 +1,7 @@ --- title: Data Table description: Powerful table and datagrids built using TanStack Table. -base: radix +base: base component: true links: doc: https://tanstack.com/table/v8/docs/introduction @@ -10,7 +10,8 @@ links: ## Introduction diff --git a/apps/v4/content/docs/components/radix/dialog.mdx b/apps/v4/content/docs/components/radix/dialog.mdx index 394ee5829b..fadc790bfc 100644 --- a/apps/v4/content/docs/components/radix/dialog.mdx +++ b/apps/v4/content/docs/components/radix/dialog.mdx @@ -87,40 +87,30 @@ import { ## Examples -### Custom close button +### Custom Close Button + +Replace the default close control with your own button. -## Notes +### No Close Button -To use the `Dialog` component from within a `Context Menu` or `Dropdown Menu`, you must encase the `Context Menu` or -`Dropdown Menu` component in the `Dialog` component. +Use `showCloseButton={false}` to hide the close button. -```tsx showLineNumbers title="components/example-dialog-context-menu.tsx" {1, 26} - - - Right click - - Open - Download - - - Delete - - - - - - - Are you absolutely sure? - - This action cannot be undone. Are you sure you want to permanently - delete this file from our servers? - - - - - - - -``` + + +### Sticky Footer + +Keep actions visible while the content scrolls. + + + +### Scrollable Content + +Long content can scroll while the header stays in view. + + + +## API Reference + +See the [Radix UI](https://www.radix-ui.com/docs/primitives/components/dialog#api-reference) documentation for more information. diff --git a/apps/v4/content/docs/components/radix/drawer.mdx b/apps/v4/content/docs/components/radix/drawer.mdx index aa2c8777b0..0e816351a3 100644 --- a/apps/v4/content/docs/components/radix/drawer.mdx +++ b/apps/v4/content/docs/components/radix/drawer.mdx @@ -7,11 +7,7 @@ links: doc: https://vaul.emilkowal.ski/getting-started --- - + ## About @@ -48,7 +44,7 @@ npm install vaul Update the import paths to match your project setup. @@ -94,8 +90,24 @@ import { ## Examples +### Scrollable Content + +Keep actions visible while the content scrolls. + + + +### Sides + +Use the `direction` prop to set the side of the drawer. Available options are `top`, `right`, `bottom`, and `left`. + + + ### Responsive Dialog You can combine the `Dialog` and `Drawer` components to create a responsive dialog. This renders a `Dialog` component on desktop and a `Drawer` on mobile. - + + +## API Reference + +See the [Vaul documentation](https://vaul.emilkowal.ski/components/drawer) for the full API reference. diff --git a/apps/v4/examples/__index__.tsx b/apps/v4/examples/__index__.tsx index d9b43061c5..7a417cdc6b 100644 --- a/apps/v4/examples/__index__.tsx +++ b/apps/v4/examples/__index__.tsx @@ -1799,19 +1799,6 @@ export const ExamplesIndex: Record> = { return { default: mod.default || mod[exportName] } }), }, - "dialog-chat-settings": { - name: "dialog-chat-settings", - filePath: "examples/radix/dialog-chat-settings.tsx", - component: React.lazy(async () => { - const mod = await import("./radix/dialog-chat-settings") - const exportName = - Object.keys(mod).find( - (key) => - typeof mod[key] === "function" || typeof mod[key] === "object" - ) || "dialog-chat-settings" - return { default: mod.default || mod[exportName] } - }), - }, "dialog-close-button": { name: "dialog-close-button", filePath: "examples/radix/dialog-close-button.tsx", @@ -1864,29 +1851,16 @@ export const ExamplesIndex: Record> = { return { default: mod.default || mod[exportName] } }), }, - "dialog-with-form": { - name: "dialog-with-form", - filePath: "examples/radix/dialog-with-form.tsx", + "dialog-sticky-footer": { + name: "dialog-sticky-footer", + filePath: "examples/radix/dialog-sticky-footer.tsx", component: React.lazy(async () => { - const mod = await import("./radix/dialog-with-form") + const mod = await import("./radix/dialog-sticky-footer") const exportName = Object.keys(mod).find( (key) => typeof mod[key] === "function" || typeof mod[key] === "object" - ) || "dialog-with-form" - return { default: mod.default || mod[exportName] } - }), - }, - "dialog-with-sticky-footer": { - name: "dialog-with-sticky-footer", - filePath: "examples/radix/dialog-with-sticky-footer.tsx", - component: React.lazy(async () => { - const mod = await import("./radix/dialog-with-sticky-footer") - const exportName = - Object.keys(mod).find( - (key) => - typeof mod[key] === "function" || typeof mod[key] === "object" - ) || "dialog-with-sticky-footer" + ) || "dialog-sticky-footer" return { default: mod.default || mod[exportName] } }), }, @@ -1929,16 +1903,16 @@ export const ExamplesIndex: Record> = { return { default: mod.default || mod[exportName] } }), }, - "drawer-with-sides": { - name: "drawer-with-sides", - filePath: "examples/radix/drawer-with-sides.tsx", + "drawer-sides": { + name: "drawer-sides", + filePath: "examples/radix/drawer-sides.tsx", component: React.lazy(async () => { - const mod = await import("./radix/drawer-with-sides") + const mod = await import("./radix/drawer-sides") const exportName = Object.keys(mod).find( (key) => typeof mod[key] === "function" || typeof mod[key] === "object" - ) || "drawer-with-sides" + ) || "drawer-sides" return { default: mod.default || mod[exportName] } }), }, @@ -8238,32 +8212,6 @@ export const ExamplesIndex: Record> = { return { default: mod.default || mod[exportName] } }), }, - "default-item-group": { - name: "default-item-group", - filePath: "examples/base/default-item-group.tsx", - component: React.lazy(async () => { - const mod = await import("./base/default-item-group") - const exportName = - Object.keys(mod).find( - (key) => - typeof mod[key] === "function" || typeof mod[key] === "object" - ) || "default-item-group" - return { default: mod.default || mod[exportName] } - }), - }, - "dialog-chat-settings": { - name: "dialog-chat-settings", - filePath: "examples/base/dialog-chat-settings.tsx", - component: React.lazy(async () => { - const mod = await import("./base/dialog-chat-settings") - const exportName = - Object.keys(mod).find( - (key) => - typeof mod[key] === "function" || typeof mod[key] === "object" - ) || "dialog-chat-settings" - return { default: mod.default || mod[exportName] } - }), - }, "dialog-close-button": { name: "dialog-close-button", filePath: "examples/base/dialog-close-button.tsx", @@ -8316,29 +8264,16 @@ export const ExamplesIndex: Record> = { return { default: mod.default || mod[exportName] } }), }, - "dialog-with-form": { - name: "dialog-with-form", - filePath: "examples/base/dialog-with-form.tsx", + "dialog-sticky-footer": { + name: "dialog-sticky-footer", + filePath: "examples/base/dialog-sticky-footer.tsx", component: React.lazy(async () => { - const mod = await import("./base/dialog-with-form") + const mod = await import("./base/dialog-sticky-footer") const exportName = Object.keys(mod).find( (key) => typeof mod[key] === "function" || typeof mod[key] === "object" - ) || "dialog-with-form" - return { default: mod.default || mod[exportName] } - }), - }, - "dialog-with-sticky-footer": { - name: "dialog-with-sticky-footer", - filePath: "examples/base/dialog-with-sticky-footer.tsx", - component: React.lazy(async () => { - const mod = await import("./base/dialog-with-sticky-footer") - const exportName = - Object.keys(mod).find( - (key) => - typeof mod[key] === "function" || typeof mod[key] === "object" - ) || "dialog-with-sticky-footer" + ) || "dialog-sticky-footer" return { default: mod.default || mod[exportName] } }), }, @@ -8381,16 +8316,16 @@ export const ExamplesIndex: Record> = { return { default: mod.default || mod[exportName] } }), }, - "drawer-with-sides": { - name: "drawer-with-sides", - filePath: "examples/base/drawer-with-sides.tsx", + "drawer-sides": { + name: "drawer-sides", + filePath: "examples/base/drawer-sides.tsx", component: React.lazy(async () => { - const mod = await import("./base/drawer-with-sides") + const mod = await import("./base/drawer-sides") const exportName = Object.keys(mod).find( (key) => typeof mod[key] === "function" || typeof mod[key] === "object" - ) || "drawer-with-sides" + ) || "drawer-sides" return { default: mod.default || mod[exportName] } }), }, @@ -9655,6 +9590,19 @@ export const ExamplesIndex: Record> = { return { default: mod.default || mod[exportName] } }), }, + "item-group-default": { + name: "item-group-default", + filePath: "examples/base/item-group-default.tsx", + component: React.lazy(async () => { + const mod = await import("./base/item-group-default") + const exportName = + Object.keys(mod).find( + (key) => + typeof mod[key] === "function" || typeof mod[key] === "object" + ) || "item-group-default" + return { default: mod.default || mod[exportName] } + }), + }, "item-group": { name: "item-group", filePath: "examples/base/item-group.tsx", diff --git a/apps/v4/examples/base/dialog-chat-settings.tsx b/apps/v4/examples/base/dialog-chat-settings.tsx deleted file mode 100644 index c7f653d1dc..0000000000 --- a/apps/v4/examples/base/dialog-chat-settings.tsx +++ /dev/null @@ -1,429 +0,0 @@ -"use client" - -import * as React from "react" -import { Button } from "@/examples/base/ui/button" -import { Checkbox } from "@/examples/base/ui/checkbox" -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@/examples/base/ui/dialog" -import { - Field, - FieldContent, - FieldDescription, - FieldGroup, - FieldLabel, - FieldSeparator, - FieldSet, - FieldTitle, -} from "@/examples/base/ui/field" -import { Input } from "@/examples/base/ui/input" -import { - InputGroup, - InputGroupAddon, - InputGroupButton, - InputGroupInput, -} from "@/examples/base/ui/input-group" -import { Kbd } from "@/examples/base/ui/kbd" -import { - NativeSelect, - NativeSelectOption, -} from "@/examples/base/ui/native-select" -import { - Select, - SelectContent, - SelectGroup, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/examples/base/ui/select" -import { Switch } from "@/examples/base/ui/switch" -import { - Tabs, - TabsContent, - TabsList, - TabsTrigger, -} from "@/examples/base/ui/tabs" -import { Textarea } from "@/examples/base/ui/textarea" -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from "@/examples/base/ui/tooltip" -import { InfoIcon } from "lucide-react" - -const spokenLanguages = [ - { label: "Auto", value: "auto" }, - { label: "English", value: "en" }, - { label: "Spanish", value: "es" }, - { label: "French", value: "fr" }, - { label: "German", value: "de" }, - { label: "Italian", value: "it" }, - { label: "Portuguese", value: "pt" }, - { label: "Russian", value: "ru" }, - { label: "Chinese", value: "zh" }, - { label: "Japanese", value: "ja" }, - { label: "Korean", value: "ko" }, - { label: "Arabic", value: "ar" }, - { label: "Hindi", value: "hi" }, - { label: "Bengali", value: "bn" }, - { label: "Telugu", value: "te" }, - { label: "Marathi", value: "mr" }, - { label: "Kannada", value: "kn" }, - { label: "Malayalam", value: "ml" }, -] - -const voices = [ - { label: "Samantha", value: "samantha" }, - { label: "Alex", value: "alex" }, - { label: "Fred", value: "fred" }, - { label: "Victoria", value: "victoria" }, - { label: "Tom", value: "tom" }, - { label: "Karen", value: "karen" }, - { label: "Sam", value: "sam" }, - { label: "Daniel", value: "daniel" }, -] - -const themes = [ - { label: "Light", value: "light" }, - { label: "Dark", value: "dark" }, - { label: "System", value: "system" }, -] - -const accents = [ - { label: "Default", value: "default" }, - { label: "Red", value: "red" }, - { label: "Blue", value: "blue" }, - { label: "Green", value: "green" }, - { label: "Purple", value: "purple" }, - { label: "Pink", value: "pink" }, -] - -export function DialogChatSettings() { - const [tab, setTab] = React.useState("general") - const [theme, setTheme] = React.useState("system") - const [accentColor, setAccentColor] = React.useState("default") - const [spokenLanguage, setSpokenLanguage] = React.useState("en") - const [voice, setVoice] = React.useState("samantha") - - return ( - <> - - }> - Chat Settings - - - - Chat Settings - - Customize your chat settings: theme, accent color, spoken - language, voice, personality, and custom instructions. - - -
- setTab(e.target.value)} - className="w-full md:hidden" - > - General - - Notifications - - - Personalization - - Security - - - - General - Notifications - - Personalization - - Security - -
- -
- - - Theme - - - - - - Accent Color - - - - - - - - Spoken Language - - - For best results, select the language you mainly - speak. If it's not listed, it may still be - supported via auto-detection. - - - - - - - Voice - - - -
-
- - -
- Responses - - Get notified when ChatGPT responds to requests that take - time, like research or image generation. - - - - - - Push notifications - - - -
- -
- Tasks - - Get notified when tasks you've created have - updates. Manage tasks - - - - - - Push notifications - - - - - - Email notifications - - - -
-
-
- - - - Nickname - - - - - } - > - - - - Used to identify you in the chat. N - - - - - - - - - More about you - - Tell us more about yourself. This will be used to help - us personalize your experience. - - -