diff options
| author | David Hill <[email protected]> | 2026-01-26 16:39:01 +0000 |
|---|---|---|
| committer | David Hill <[email protected]> | 2026-01-26 19:47:57 +0000 |
| commit | 92229b44f885b78d6c729d5d2e71ddbe096d2672 (patch) | |
| tree | cb3d57506d42b5c3776600dfaa2ba968f489cc9e | |
| parent | 0a572afd46ecdaaee3d411fe95f0ff9c26b8e1ab (diff) | |
| download | opencode-92229b44f885b78d6c729d5d2e71ddbe096d2672.tar.gz opencode-92229b44f885b78d6c729d5d2e71ddbe096d2672.zip | |
feat(ui): add optional transition animations to dialog
| -rw-r--r-- | packages/app/src/components/dialog-settings.tsx | 2 | ||||
| -rw-r--r-- | packages/ui/src/components/dialog.css | 24 | ||||
| -rw-r--r-- | packages/ui/src/components/dialog.tsx | 8 | ||||
| -rw-r--r-- | packages/ui/src/context/dialog.tsx | 17 |
4 files changed, 30 insertions, 21 deletions
diff --git a/packages/app/src/components/dialog-settings.tsx b/packages/app/src/components/dialog-settings.tsx index d77004d91..f8892ebbd 100644 --- a/packages/app/src/components/dialog-settings.tsx +++ b/packages/app/src/components/dialog-settings.tsx @@ -14,7 +14,7 @@ export const DialogSettings: Component = () => { const platform = usePlatform() return ( - <Dialog size="x-large"> + <Dialog size="x-large" transition> <Tabs orientation="vertical" variant="settings" defaultValue="general" class="h-full settings-dialog"> <Tabs.List> <div class="flex flex-col justify-between h-full w-full"> diff --git a/packages/ui/src/components/dialog.css b/packages/ui/src/components/dialog.css index bc3e113bb..e0ccf3fd0 100644 --- a/packages/ui/src/components/dialog.css +++ b/packages/ui/src/components/dialog.css @@ -5,12 +5,6 @@ inset: 0; z-index: 50; background-color: hsl(from var(--background-base) h s l / 0.2); - - /* animation: overlayHide 250ms ease 100ms forwards; */ - /**/ - /* &[data-expanded] { */ - /* animation: overlayShow 250ms ease; */ - /* } */ } [data-component="dialog"] { @@ -58,12 +52,6 @@ background-clip: padding-box; box-shadow: var(--shadow-lg-border-base); - /* animation: contentHide 300ms ease-in forwards; */ - /**/ - /* &[data-expanded] { */ - /* animation: contentShow 300ms ease-out; */ - /* } */ - [data-slot="dialog-header"] { display: flex; padding: 20px; @@ -147,6 +135,14 @@ } } +[data-component="dialog"][data-transition] [data-slot="dialog-content"] { + animation: contentHide 100ms ease-in forwards; + + &[data-expanded] { + animation: contentShow 200ms ease-out; + } +} + @keyframes overlayShow { from { opacity: 0; @@ -166,7 +162,7 @@ @keyframes contentShow { from { opacity: 0; - transform: scale(0.96); + transform: scale(0.98); } to { opacity: 1; @@ -180,6 +176,6 @@ } to { opacity: 0; - transform: scale(0.96); + transform: scale(0.98); } } diff --git a/packages/ui/src/components/dialog.tsx b/packages/ui/src/components/dialog.tsx index 83da6c699..8aa9315e0 100644 --- a/packages/ui/src/components/dialog.tsx +++ b/packages/ui/src/components/dialog.tsx @@ -11,12 +11,18 @@ export interface DialogProps extends ParentProps { class?: ComponentProps<"div">["class"] classList?: ComponentProps<"div">["classList"] fit?: boolean + transition?: boolean } export function Dialog(props: DialogProps) { const i18n = useI18n() return ( - <div data-component="dialog" data-fit={props.fit ? true : undefined} data-size={props.size || "normal"}> + <div + data-component="dialog" + data-fit={props.fit ? true : undefined} + data-size={props.size || "normal"} + data-transition={props.transition ? true : undefined} + > <div data-slot="dialog-container"> <Kobalte.Content data-slot="dialog-content" diff --git a/packages/ui/src/context/dialog.tsx b/packages/ui/src/context/dialog.tsx index a3aafa0c7..4d03b218d 100644 --- a/packages/ui/src/context/dialog.tsx +++ b/packages/ui/src/context/dialog.tsx @@ -21,6 +21,7 @@ type Active = { dispose: () => void owner: Owner onClose?: () => void + setClosing: (closing: boolean) => void } const Context = createContext<ReturnType<typeof init>>() @@ -32,8 +33,11 @@ function init() { const current = active() if (!current) return current.onClose?.() - current.dispose() - setActive(undefined) + current.setClosing(true) + setTimeout(() => { + current.dispose() + setActive(undefined) + }, 100) } createEffect(() => { @@ -55,14 +59,17 @@ function init() { const id = Math.random().toString(36).slice(2) let dispose: (() => void) | undefined + let setClosing: ((closing: boolean) => void) | undefined const node = runWithOwner(owner, () => createRoot((d: () => void) => { dispose = d + const [closing, setClosingSignal] = createSignal(false) + setClosing = setClosingSignal return ( <Kobalte modal - open={true} + open={!closing()} onOpenChange={(open: boolean) => { if (open) return close() @@ -77,9 +84,9 @@ function init() { }), ) - if (!dispose) return + if (!dispose || !setClosing) return - setActive({ id, node, dispose, owner, onClose }) + setActive({ id, node, dispose, owner, onClose, setClosing }) } return { |
