Skip to content

Commit 04b60d8

Browse files
feat(dialog): switch native dialog to corvu dialog, add demos: icon, nested, long content, remove native dialogs
1 parent 927b361 commit 04b60d8

File tree

10 files changed

+262
-377
lines changed

10 files changed

+262
-377
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { ttt } from "~ui/i18n/ttt"
2+
3+
export type CorcuDialogTexts = {
4+
closeDialog: string
5+
}
6+
7+
export const corvuDialogTextDefault = {
8+
closeDialog: ttt("Close dialog"),
9+
} as const satisfies CorcuDialogTexts
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import Dialog from "@corvu/dialog"
2+
import { mdiClose } from "@mdi/js"
3+
import type { JSX } from "solid-js"
4+
import { classesDisabledDirectly } from "~ui/classes/classesDisabledDirectly"
5+
import { buttonCva2, buttonCvaIconOnly, buttonVariant } from "~ui/interactive/button/buttonCva"
6+
import type { ButtonIcon1Props } from "~ui/interactive/button/ButtonIcon1"
7+
import { buttonIconCva } from "~ui/interactive/button/buttonIconCva"
8+
import { classesButtonClickAnimation } from "~ui/interactive/button/classesButtonClickAnimation"
9+
import { classesDialogContentMerge, classesDialogOverlayMerge } from "~ui/interactive/dialog/classesDialogContent"
10+
import type { CorcuDialogTexts } from "~ui/interactive/dialog/CorcuDialogTexts"
11+
import { corvuDialogTextDefault } from "~ui/interactive/dialog/CorcuDialogTexts"
12+
import { Icon1 } from "~ui/static/icon/Icon1"
13+
import { classMerge } from "~ui/utils/classMerge"
14+
import type { MayHaveChildren } from "~ui/utils/MayHaveChildren"
15+
import type { MayHaveClass } from "~ui/utils/MayHaveClass"
16+
import type { MayHaveInnerClass } from "~ui/utils/MayHaveInnerClass"
17+
18+
export interface CorvuDialogProps extends MayHaveClass, MayHaveInnerClass, MayHaveChildren, ButtonIcon1Props {
19+
buttonChildren?: JSX.Element
20+
title: string
21+
description?: string
22+
titleClass?: string
23+
descriptionClass?: string
24+
texts?: CorcuDialogTexts
25+
}
26+
27+
export function CorvuDialog(p: CorvuDialogProps) {
28+
const texts = p.texts ?? corvuDialogTextDefault
29+
30+
return (
31+
<Dialog>
32+
<Dialog.Trigger
33+
class={buttonCva2(
34+
p.variant,
35+
p.size,
36+
classesButtonClickAnimation,
37+
(p.disabled || p.isDisabled?.()) && classesDisabledDirectly,
38+
p.class,
39+
)}
40+
>
41+
{p.icon && <Icon1 path={p.icon} class={buttonIconCva(p.variant, p.buttonChildren && "mr-2", p.iconClass)} />}
42+
{p.buttonChildren}
43+
{p.iconRight && (
44+
<Icon1 path={p.iconRight} class={buttonIconCva(p.variant, p.buttonChildren && "ml-2", p.iconClass)} />
45+
)}
46+
</Dialog.Trigger>
47+
<Dialog.Portal>
48+
<Dialog.Overlay class={classesDialogOverlayMerge()} />
49+
<Dialog.Content class={classesDialogContentMerge(p.innerClass)}>
50+
<header class="flex items-start justify-between mb-4">
51+
<div>
52+
<Dialog.Label class={classMerge("text-lg font-semibold", p.titleClass)}>{p.title}</Dialog.Label>
53+
{p.description && (
54+
<Dialog.Description class={classMerge("text-muted-foreground", p.descriptionClass)}>
55+
{p.description}
56+
</Dialog.Description>
57+
)}
58+
</div>
59+
<Dialog.Close class={buttonCvaIconOnly(buttonVariant.outline, false, false)} title={texts.closeDialog}>
60+
<Icon1 path={mdiClose} class={buttonIconCva(buttonVariant.outline, "")} />
61+
</Dialog.Close>
62+
</header>
63+
{p.children}
64+
</Dialog.Content>
65+
</Dialog.Portal>
66+
</Dialog>
67+
)
68+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import Dialog from "@corvu/dialog"
2+
import { mdiClose } from "@mdi/js"
3+
import { splitProps, type Component, type ComponentProps } from "solid-js"
4+
import { classesDisabledDirectly } from "~ui/classes/classesDisabledDirectly"
5+
import { buttonCvaIconOnly, buttonVariant, type ButtonCvaProps } from "~ui/interactive/button/buttonCva"
6+
import { buttonIconCva } from "~ui/interactive/button/buttonIconCva"
7+
import { classesButtonClickAnimation } from "~ui/interactive/button/classesButtonClickAnimation"
8+
import type { CorcuDialogTexts } from "~ui/interactive/dialog/CorcuDialogTexts"
9+
import { corvuDialogTextDefault } from "~ui/interactive/dialog/CorcuDialogTexts"
10+
import { classesDialogContentMerge, classesDialogOverlayMerge } from "~ui/interactive/dialog/classesDialogContent"
11+
import { Icon0 } from "~ui/static/icon/Icon0"
12+
import type { HasIcon } from "~ui/utils/HasIcon"
13+
import type { HasTitle } from "~ui/utils/HasTitle"
14+
import type { MayHaveChildren } from "~ui/utils/MayHaveChildren"
15+
import type { MayHaveClass } from "~ui/utils/MayHaveClass"
16+
import type { MayHaveInnerClass } from "~ui/utils/MayHaveInnerClass"
17+
import { isLoading, type MayHaveIsLoading } from "~ui/utils/MayHaveIsLoading"
18+
import { classMerge } from "~ui/utils/classMerge"
19+
20+
export interface CorvuDialogIconProps
21+
extends Omit<ComponentProps<"button">, "title">,
22+
ButtonCvaProps,
23+
HasIcon,
24+
HasTitle,
25+
MayHaveClass,
26+
MayHaveInnerClass,
27+
MayHaveChildren,
28+
MayHaveIsLoading {
29+
dialogTitle: string
30+
description?: string
31+
titleClass?: string
32+
descriptionClass?: string
33+
texts?: CorcuDialogTexts
34+
}
35+
36+
export const CorvuDialogIcon: Component<CorvuDialogIconProps> = (p) => {
37+
const [s, rest] = splitProps(p, [
38+
// button
39+
"variant",
40+
"size",
41+
"class",
42+
// state
43+
"isLoading",
44+
"disabled",
45+
// icons
46+
"title",
47+
"icon",
48+
"iconClass",
49+
// dialog
50+
"innerClass",
51+
"children",
52+
"dialogTitle",
53+
"description",
54+
"titleClass",
55+
"descriptionClass",
56+
"texts",
57+
])
58+
59+
const texts = s.texts ?? corvuDialogTextDefault
60+
61+
return (
62+
<Dialog>
63+
<Dialog.Trigger
64+
class={buttonCvaIconOnly(s.variant, isLoading(p), s.disabled, classesButtonClickAnimation, s.class)}
65+
title={s.title}
66+
{...rest}
67+
>
68+
<Icon0
69+
path={s.icon}
70+
class={buttonIconCva(
71+
s.variant,
72+
isLoading(p) && "animate-spin-faster",
73+
s.disabled && classesDisabledDirectly,
74+
s.iconClass,
75+
)}
76+
/>
77+
</Dialog.Trigger>
78+
<Dialog.Portal>
79+
<Dialog.Overlay class={classesDialogOverlayMerge()} />
80+
<Dialog.Content class={classesDialogContentMerge(s.innerClass)}>
81+
<header class="flex items-start justify-between mb-4">
82+
<div>
83+
<Dialog.Label class={classMerge("text-lg font-semibold", s.titleClass)}>{s.dialogTitle}</Dialog.Label>
84+
{s.description && (
85+
<Dialog.Description class={classMerge("text-muted-foreground", s.descriptionClass)}>
86+
{s.description}
87+
</Dialog.Description>
88+
)}
89+
</div>
90+
<Dialog.Close class={buttonCvaIconOnly(buttonVariant.outline, false, false)} title={texts.closeDialog}>
91+
<Icon0 path={mdiClose} class={buttonIconCva(buttonVariant.outline, "")} />
92+
</Dialog.Close>
93+
</header>
94+
{s.children}
95+
</Dialog.Content>
96+
</Dialog.Portal>
97+
</Dialog>
98+
)
99+
}

lib/interactive/dialog/NativeDialog.module.css

Lines changed: 0 additions & 26 deletions
This file was deleted.

lib/interactive/dialog/NativeDialog.tsx

Lines changed: 0 additions & 124 deletions
This file was deleted.

lib/interactive/dialog/NativeDialogTexts.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { classMerge } from "~ui/utils/classMerge"
2+
3+
export const classesDialogContent = [
4+
"z-50", // positioning
5+
"fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2", // centering
6+
// "w-full max-w-lg", // sizing
7+
"max-h-[95vh]", // max height to allow scrolling
8+
"overflow-auto", // enable scrolling when content overflows
9+
"p-6", // spacing
10+
"bg-white dark:bg-gray-900", // background
11+
"border border-gray-200 dark:border-gray-700", // border
12+
"rounded-lg shadow-lg", // border/shadow
13+
"data-open:animate-in data-open:fade-in-50% data-open:zoom-in-95% data-closed:animate-out data-closed:fade-out-50% data-closed:zoom-out-95%", // animations
14+
]
15+
16+
export const classesDialogOverlay = [
17+
"fixed inset-0", // positioning
18+
"z-40", // positioning
19+
"bg-black/50", // background
20+
"data-open:animate-in data-open:fade-in-50% data-closed:animate-out data-closed:fade-out-50%", // animations
21+
]
22+
23+
export function classesDialogContentMerge(innerClass?: string) {
24+
return classMerge(classesDialogContent, innerClass)
25+
}
26+
27+
export function classesDialogOverlayMerge(innerClass?: string) {
28+
return classMerge(classesDialogOverlay, innerClass)
29+
}

0 commit comments

Comments
 (0)