From 1c6f588a7ed5787c5bb438885b74c380394fce26 Mon Sep 17 00:00:00 2001 From: Kevin Abatan Date: Thu, 25 Dec 2025 22:12:17 +0100 Subject: [PATCH 1/4] chore: add FRONTEND_PORT env var to allow worktrees --- apps/docs/app.config.ts | 5 ++++- apps/docs/tsconfig.json | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/docs/app.config.ts b/apps/docs/app.config.ts index b836b7e6..fa4254d6 100644 --- a/apps/docs/app.config.ts +++ b/apps/docs/app.config.ts @@ -20,7 +20,10 @@ export default defineConfig( } }, vite: { - plugins: [tailwindcss()] + plugins: [tailwindcss()], + server: { + port: parseInt(process.env.FRONTEND_PORT || "5173", 10) + } } }, { diff --git a/apps/docs/tsconfig.json b/apps/docs/tsconfig.json index 047b6294..cbd39639 100644 --- a/apps/docs/tsconfig.json +++ b/apps/docs/tsconfig.json @@ -22,10 +22,8 @@ "noFallthroughCasesInSwitch": true, "noUncheckedIndexedAccess": true, "noImplicitOverride": true, - // Some stricter flags (disabled by default) "noUnusedLocals": true, "noUnusedParameters": true, - "noPropertyAccessFromIndexSignature": true, "baseUrl": ".", "paths": { "~/*": ["./src/*"] From 395c6ea4988546b6ee6f22457443184d450948ab Mon Sep 17 00:00:00 2001 From: Kevin Abatan Date: Fri, 26 Dec 2025 04:19:30 +0100 Subject: [PATCH 2/4] chore: adding trees to gitignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index dc1b5dd4..ad08f192 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,10 @@ Thumbs.db # Claude .claude logs +trees/ + +# Worktree environment configs +**/.ports.env app.config.timestamp* From 7d32ab55fff667fd4735d98adba9718e3476e609 Mon Sep 17 00:00:00 2001 From: Kevin Abatan Date: Sat, 27 Dec 2025 00:41:01 +0100 Subject: [PATCH 3/4] feat(dialog): sync dialog component from shadcn v4 with Kobalte primitives --- apps/docs/src/config/docs.ts | 4 + apps/docs/src/registry/__index__.tsx | 42 ++++++ apps/docs/src/registry/examples/_registry.ts | 22 +++ .../registry/examples/dialog-close-button.tsx | 64 +++++++++ .../src/registry/examples/dialog-demo.tsx | 47 +++++++ apps/docs/src/registry/styles/style-lyra.css | 4 +- apps/docs/src/registry/styles/style-maia.css | 4 +- apps/docs/src/registry/styles/style-mira.css | 4 +- apps/docs/src/registry/styles/style-nova.css | 4 +- apps/docs/src/registry/styles/style-vega.css | 4 +- apps/docs/src/registry/ui/_registry.ts | 11 ++ apps/docs/src/registry/ui/dialog.tsx | 61 ++++++--- .../src/routes/docs/components/dialog.mdx | 127 ++++++++++++++++++ 13 files changed, 369 insertions(+), 29 deletions(-) create mode 100644 apps/docs/src/registry/examples/dialog-close-button.tsx create mode 100644 apps/docs/src/registry/examples/dialog-demo.tsx create mode 100644 apps/docs/src/routes/docs/components/dialog.mdx diff --git a/apps/docs/src/config/docs.ts b/apps/docs/src/config/docs.ts index a893e129..73671c84 100644 --- a/apps/docs/src/config/docs.ts +++ b/apps/docs/src/config/docs.ts @@ -51,6 +51,10 @@ export const docsConfig: Config = { title: "Checkbox", href: "/docs/components/checkbox" }, + { + title: "Dialog", + href: "/docs/components/dialog" + }, { title: "Dropdown Menu", href: "/docs/components/dropdown-menu" diff --git a/apps/docs/src/registry/__index__.tsx b/apps/docs/src/registry/__index__.tsx index 7eddc1d9..50532b90 100644 --- a/apps/docs/src/registry/__index__.tsx +++ b/apps/docs/src/registry/__index__.tsx @@ -88,6 +88,20 @@ export const Index: Record = { categories: undefined, meta: undefined, }, + "dialog": { + name: "dialog", + description: "", + type: "registry:ui", + registryDependencies: undefined, + component: lazy(() => import("~/registry/ui/dialog.tsx")), + files: [{ + path: "registry/ui/dialog.tsx", + type: "registry:ui", + target: "" + }], + categories: undefined, + meta: undefined, + }, "dropdown-menu": { name: "dropdown-menu", description: "", @@ -452,6 +466,34 @@ export const Index: Record = { categories: undefined, meta: undefined, }, + "dialog-demo": { + name: "dialog-demo", + description: "", + type: "registry:example", + registryDependencies: ["dialog","button","field","input"], + component: lazy(() => import("~/registry/examples/dialog-demo.tsx")), + files: [{ + path: "registry/examples/dialog-demo.tsx", + type: "registry:example", + target: "" + }], + categories: undefined, + meta: undefined, + }, + "dialog-close-button": { + name: "dialog-close-button", + description: "", + type: "registry:example", + registryDependencies: ["dialog","button"], + component: lazy(() => import("~/registry/examples/dialog-close-button.tsx")), + files: [{ + path: "registry/examples/dialog-close-button.tsx", + type: "registry:example", + target: "" + }], + categories: undefined, + meta: undefined, + }, "dropdown-menu-demo": { name: "dropdown-menu-demo", description: "", diff --git a/apps/docs/src/registry/examples/_registry.ts b/apps/docs/src/registry/examples/_registry.ts index 6cd90966..6cec6d68 100644 --- a/apps/docs/src/registry/examples/_registry.ts +++ b/apps/docs/src/registry/examples/_registry.ts @@ -188,6 +188,28 @@ export const examples: Registry["items"] = [ } ] }, + { + name: "dialog-demo", + type: "registry:example", + registryDependencies: ["dialog", "button", "field", "input"], + files: [ + { + path: "examples/dialog-demo.tsx", + type: "registry:example" + } + ] + }, + { + name: "dialog-close-button", + type: "registry:example", + registryDependencies: ["dialog", "button"], + files: [ + { + path: "examples/dialog-close-button.tsx", + type: "registry:example" + } + ] + }, { name: "dropdown-menu-demo", type: "registry:example", diff --git a/apps/docs/src/registry/examples/dialog-close-button.tsx b/apps/docs/src/registry/examples/dialog-close-button.tsx new file mode 100644 index 00000000..8a62a33b --- /dev/null +++ b/apps/docs/src/registry/examples/dialog-close-button.tsx @@ -0,0 +1,64 @@ +import { Button } from "~/registry/ui/button" +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger +} from "~/registry/ui/dialog" + +export default function DialogCloseButton() { + return ( + + } variant="outline"> + Share + + + + Share link + + Anyone who has this link will be able to view this. + + +
+
+ + +
+ +
+ + } variant="secondary"> + Close + + +
+
+ ) +} diff --git a/apps/docs/src/registry/examples/dialog-demo.tsx b/apps/docs/src/registry/examples/dialog-demo.tsx new file mode 100644 index 00000000..7cac026a --- /dev/null +++ b/apps/docs/src/registry/examples/dialog-demo.tsx @@ -0,0 +1,47 @@ +import { Button } from "~/registry/ui/button" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger +} from "~/registry/ui/dialog" +import { Field, FieldGroup, FieldLabel } from "~/registry/ui/field" +import { Input } from "~/registry/ui/input" + +export default function DialogDemo() { + return ( + + } variant="outline"> + Edit Profile + + + + Edit profile + + Make changes to your profile here. Click save when you're done. + + + + + + Name + + + + + + Username + + + + + + + + + + ) +} diff --git a/apps/docs/src/registry/styles/style-lyra.css b/apps/docs/src/registry/styles/style-lyra.css index 47ca492d..7e2d696c 100644 --- a/apps/docs/src/registry/styles/style-lyra.css +++ b/apps/docs/src/registry/styles/style-lyra.css @@ -417,11 +417,11 @@ /* MARK: Dialog */ .cn-dialog-overlay { - @apply data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs; + @apply data-expanded:animate-in data-closed:animate-out data-closed:fade-out-0 data-expanded:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs; } .cn-dialog-content { - @apply bg-background data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-4 rounded-none p-4 text-xs/relaxed ring-1 duration-100 sm:max-w-sm; + @apply bg-background data-expanded:animate-in data-closed:animate-out data-closed:fade-out-0 data-expanded:fade-in-0 data-closed:zoom-out-95 data-expanded:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-4 rounded-none p-4 text-xs/relaxed ring-1 duration-100 sm:max-w-sm; } .cn-dialog-close { diff --git a/apps/docs/src/registry/styles/style-maia.css b/apps/docs/src/registry/styles/style-maia.css index 63ff199a..34d4855d 100644 --- a/apps/docs/src/registry/styles/style-maia.css +++ b/apps/docs/src/registry/styles/style-maia.css @@ -438,11 +438,11 @@ /* MARK: Dialog */ .cn-dialog-overlay { - @apply data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 duration-100 supports-backdrop-filter:backdrop-blur-xs; + @apply data-expanded:animate-in data-closed:animate-out data-closed:fade-out-0 data-expanded:fade-in-0 bg-black/80 duration-100 supports-backdrop-filter:backdrop-blur-xs; } .cn-dialog-content { - @apply bg-background data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/5 grid max-w-[calc(100%-2rem)] gap-6 rounded-4xl p-6 text-sm ring-1 duration-100 sm:max-w-md; + @apply bg-background data-expanded:animate-in data-closed:animate-out data-closed:fade-out-0 data-expanded:fade-in-0 data-closed:zoom-out-95 data-expanded:zoom-in-95 ring-foreground/5 grid max-w-[calc(100%-2rem)] gap-6 rounded-4xl p-6 text-sm ring-1 duration-100 sm:max-w-md; } .cn-dialog-close { diff --git a/apps/docs/src/registry/styles/style-mira.css b/apps/docs/src/registry/styles/style-mira.css index 41b0418d..8871b0e7 100644 --- a/apps/docs/src/registry/styles/style-mira.css +++ b/apps/docs/src/registry/styles/style-mira.css @@ -438,11 +438,11 @@ /* MARK: Dialog */ .cn-dialog-overlay { - @apply data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 duration-100 supports-backdrop-filter:backdrop-blur-xs; + @apply data-expanded:animate-in data-closed:animate-out data-closed:fade-out-0 data-expanded:fade-in-0 bg-black/80 duration-100 supports-backdrop-filter:backdrop-blur-xs; } .cn-dialog-content { - @apply bg-background data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-4 rounded-xl p-4 text-xs/relaxed ring-1 duration-100 sm:max-w-sm; + @apply bg-background data-expanded:animate-in data-closed:animate-out data-closed:fade-out-0 data-expanded:fade-in-0 data-closed:zoom-out-95 data-expanded:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-4 rounded-xl p-4 text-xs/relaxed ring-1 duration-100 sm:max-w-sm; } .cn-dialog-close { diff --git a/apps/docs/src/registry/styles/style-nova.css b/apps/docs/src/registry/styles/style-nova.css index 5aa1d70b..9f45d975 100644 --- a/apps/docs/src/registry/styles/style-nova.css +++ b/apps/docs/src/registry/styles/style-nova.css @@ -438,11 +438,11 @@ /* MARK: Dialog */ .cn-dialog-overlay { - @apply data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs; + @apply data-expanded:animate-in data-closed:animate-out data-closed:fade-out-0 data-expanded:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs; } .cn-dialog-content { - @apply bg-background data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-4 rounded-xl p-4 text-sm ring-1 duration-100 sm:max-w-sm; + @apply bg-background data-expanded:animate-in data-closed:animate-out data-closed:fade-out-0 data-expanded:fade-in-0 data-closed:zoom-out-95 data-expanded:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-4 rounded-xl p-4 text-sm ring-1 duration-100 sm:max-w-sm; } .cn-dialog-close { diff --git a/apps/docs/src/registry/styles/style-vega.css b/apps/docs/src/registry/styles/style-vega.css index 76d971bf..a8044f9e 100644 --- a/apps/docs/src/registry/styles/style-vega.css +++ b/apps/docs/src/registry/styles/style-vega.css @@ -434,11 +434,11 @@ /* MARK: Dialog */ .cn-dialog-overlay { - @apply data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs; + @apply data-expanded:animate-in data-closed:animate-out data-closed:fade-out-0 data-expanded:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs; } .cn-dialog-content { - @apply bg-background data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-6 rounded-xl p-6 text-sm ring-1 duration-100 sm:max-w-md; + @apply bg-background data-expanded:animate-in data-closed:animate-out data-closed:fade-out-0 data-expanded:fade-in-0 data-closed:zoom-out-95 data-expanded:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-6 rounded-xl p-6 text-sm ring-1 duration-100 sm:max-w-md; } .cn-dialog-close { diff --git a/apps/docs/src/registry/ui/_registry.ts b/apps/docs/src/registry/ui/_registry.ts index d4758d03..bc23e093 100644 --- a/apps/docs/src/registry/ui/_registry.ts +++ b/apps/docs/src/registry/ui/_registry.ts @@ -57,6 +57,17 @@ export const ui: Registry["items"] = [ } ] }, + { + name: "dialog", + type: "registry:ui", + dependencies: ["@kobalte/core"], + files: [ + { + path: "ui/dialog.tsx", + type: "registry:ui" + } + ] + }, { name: "dropdown-menu", type: "registry:ui", diff --git a/apps/docs/src/registry/ui/dialog.tsx b/apps/docs/src/registry/ui/dialog.tsx index f305f490..d296edc2 100644 --- a/apps/docs/src/registry/ui/dialog.tsx +++ b/apps/docs/src/registry/ui/dialog.tsx @@ -31,10 +31,7 @@ const DialogOverlay = ( const [local, others] = splitProps(props as DialogOverlayProps, ["class"]) return ( @@ -62,7 +59,7 @@ const DialogContent = ( ( {local.children} ( viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" > - - + + Close @@ -95,25 +92,49 @@ const DialogContent = ( ) } -const DialogHeader: Component> = (props) => { +type DialogHeaderProps = ComponentProps<"div"> & { + class?: string | undefined +} + +const DialogHeader: Component = (props) => { const [local, others] = splitProps(props, ["class"]) return (
) } -const DialogFooter: Component> = (props) => { - const [local, others] = splitProps(props, ["class"]) +type DialogFooterProps = ComponentProps<"div"> & { + class?: string | undefined + children?: JSX.Element + showCloseButton?: boolean +} + +const DialogFooter: Component = (rawProps) => { + const props = mergeProps({ showCloseButton: false }, rawProps) + const [local, others] = splitProps(props, ["class", "children", "showCloseButton"]) return (
+ > + {local.children} + + + Close + + +
) } @@ -127,7 +148,7 @@ const DialogTitle = ( const [local, others] = splitProps(props as DialogTitleProps, ["class"]) return ( @@ -145,7 +166,7 @@ const DialogDescription = ( const [local, others] = splitProps(props as DialogDescriptionProps, ["class"]) return ( @@ -154,11 +175,13 @@ const DialogDescription = ( export { Dialog, - DialogTrigger, DialogClose, DialogContent, - DialogHeader, + DialogDescription, DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, DialogTitle, - DialogDescription + DialogTrigger } diff --git a/apps/docs/src/routes/docs/components/dialog.mdx b/apps/docs/src/routes/docs/components/dialog.mdx new file mode 100644 index 00000000..66f05751 --- /dev/null +++ b/apps/docs/src/routes/docs/components/dialog.mdx @@ -0,0 +1,127 @@ +--- +title: Dialog +description: A window overlaid on either the primary window or another dialog window, rendering the content underneath inert. +links: + doc: https://kobalte.dev/docs/core/components/dialog + api: https://kobalte.dev/docs/core/components/dialog#api-reference +--- + +::::tab-group[preview] +:::tab[Preview] + + + +::: + +:::tab[Code] + +```file="~/registry/examples/dialog-demo" frame=none showLineNumbers + +``` + +::: +:::: + +## Installation + +### CLI + +```package-exec +solidui-cli@latest add dialog +``` + +### Manual + +Install the following dependencies: + +```package-install +@kobalte/core +``` + +Copy and paste the following code into your project. + +```file="~/registry/ui/dialog.tsx" showLineNumbers + +``` + +## Usage + +```tsx +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "~/components/ui/dialog"; +``` + +```tsx + + Open + + + Are you absolutely sure? + + This action cannot be undone. This will permanently delete your account + and remove your data from our servers. + + + + +``` + +## Examples + +### Custom close button + +Use the `DialogClose` component to create a custom close button. + +::::tab-group[close-button] +:::tab[Preview] + + + +::: + +:::tab[Code] + +```file="~/registry/examples/dialog-close-button" frame=none showLineNumbers + +``` + +::: +:::: + +## Notes + +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. See the [Dropdown Menu Dialog example](/docs/components/dropdown-menu#dialog) for more details. + +```tsx 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? + + + + + + + +``` From f0f490549ee486cd28b31b1b4df0c11f980c573f Mon Sep 17 00:00:00 2001 From: Kevin Abatan Date: Sun, 28 Dec 2025 02:21:52 +0100 Subject: [PATCH 4/4] fix: apply good classes --- apps/docs/src/registry/ui/dialog.tsx | 58 +++++++--------------------- 1 file changed, 14 insertions(+), 44 deletions(-) diff --git a/apps/docs/src/registry/ui/dialog.tsx b/apps/docs/src/registry/ui/dialog.tsx index d296edc2..1cb40e7b 100644 --- a/apps/docs/src/registry/ui/dialog.tsx +++ b/apps/docs/src/registry/ui/dialog.tsx @@ -3,8 +3,10 @@ import { mergeProps, Show, splitProps } from "solid-js" import * as DialogPrimitive from "@kobalte/core/dialog" import type { PolymorphicProps } from "@kobalte/core/polymorphic" +import { X } from "lucide-solid" import { cn } from "~/lib/utils" +import { Button } from "~/registry/ui/button" const Dialog: Component = (props) => ( @@ -59,7 +61,7 @@ const DialogContent = ( ( {local.children} - - - - + Close @@ -92,11 +85,7 @@ const DialogContent = ( ) } -type DialogHeaderProps = ComponentProps<"div"> & { - class?: string | undefined -} - -const DialogHeader: Component = (props) => { +const DialogHeader: Component> = (props) => { const [local, others] = splitProps(props, ["class"]) return (
= (props) => { ) } -type DialogFooterProps = ComponentProps<"div"> & { - class?: string | undefined - children?: JSX.Element - showCloseButton?: boolean -} - -const DialogFooter: Component = (rawProps) => { - const props = mergeProps({ showCloseButton: false }, rawProps) - const [local, others] = splitProps(props, ["class", "children", "showCloseButton"]) +const DialogFooter: Component> = (props) => { + const [local, others] = splitProps(props, ["class"]) return (
= (rawProps) => { )} data-slot="dialog-footer" {...others} - > - {local.children} - - - Close - - -
+ /> ) } @@ -175,13 +147,11 @@ const DialogDescription = ( export { Dialog, + DialogTrigger, DialogClose, DialogContent, - DialogDescription, - DialogFooter, DialogHeader, - DialogOverlay, - DialogPortal, + DialogFooter, DialogTitle, - DialogTrigger + DialogDescription }