11import { Button } from "@/components/Button" ;
22import { ResizablePanel } from "@/components/Resizable" ;
3+ import { useTheme } from "@/contexts/theme" ;
34import {
45 type Diagnostic ,
56 type InternalDiagnostic ,
@@ -10,7 +11,8 @@ import { useDebouncedValue } from "@/hooks/debounce";
1011import { useStore } from "@/store" ;
1112import { cn } from "@/utils/cn" ;
1213import { ActivityIcon , ExternalLinkIcon , LoaderIcon } from "lucide-react" ;
13- import { type FC , useEffect , useState } from "react" ;
14+ import { AnimatePresence , motion } from "motion/react" ;
15+ import { type FC , useEffect , useMemo , useState } from "react" ;
1416
1517export const Preview : FC = ( ) => {
1618 const $wasmState = useStore ( ( state ) => state . wasmState ) ;
@@ -183,60 +185,75 @@ const ErrorPane = () => {
183185 const $errors = useStore ( ( state ) => state . errors ) ;
184186 const $toggleShowError = useStore ( ( state ) => state . toggleShowError ) ;
185187
186- if ( $errors . diagnostics . length === 0 ) {
187- return null ;
188- }
188+ const hasErrors = useMemo ( ( ) => $errors . diagnostics . length > 0 , [ $errors ] ) ;
189189
190190 return (
191191 < >
192- { /*
193- * biome-ignore lint/a11y/useKeyWithClickEvents: key events don't seem to
194- * work for divs, and I'm otherwise not sure how to make this element
195- * more accesible. But I think it's fine since the functionality is able to
196- * be used with the button.
197- */ }
198- < div
199- aria-hidden = { true }
200- className = { cn (
201- "absolute top-0 left-0 hidden h-full w-full transition-all" ,
202- $errors . show && "block cursor-pointer bg-black/10 dark:bg-black/50" ,
203- ) }
204- onClick = { ( ) => {
205- $toggleShowError ( false ) ;
206- } }
207- >
208- { /* OVERLAY */ }
209- </ div >
192+ < AnimatePresence propagate = { true } >
193+ { $errors . show && hasErrors ? (
194+ // lint/a11y/useKeyWithClickEvents: key events don't seem to
195+ // work for divs, and I'm otherwise not sure how to make this element
196+ // more accesible. But I think it's fine since the functionality is able to
197+ // be used with the button below.
198+ < motion . div
199+ initial = { { opacity : 0 } }
200+ animate = { { opacity : 1 } }
201+ exit = { { opacity : 0 } }
202+ aria-hidden = { true }
203+ className = "absolute top-0 left-0 h-full w-full cursor-pointer bg-black/10 dark:bg-black/50"
204+ onClick = { ( ) => {
205+ $toggleShowError ( false ) ;
206+ } }
207+ >
208+ { /* OVERLAY */ }
209+ </ motion . div >
210+ ) : null }
211+ </ AnimatePresence >
210212
211- < div
212- role = "alertdialog"
213- className = { cn (
214- "absolute bottom-0 left-0 flex max-h-[60%] w-full flex-col justify-start" ,
215- $errors . show && "h-auto" ,
216- ) }
217- >
218- < button
219- className = "flex h-4 min-h-4 w-full items-center justify-center rounded-t-xl bg-border-destructive"
220- onClick = { ( ) => $toggleShowError ( ) }
221- aria-label = { $errors . show ? "Hide error dialog" : "Show error dialog" }
222- >
223- < div className = "h-0.5 w-2/3 max-w-32 rounded-full bg-white/40" > </ div >
224- </ button >
213+ < AnimatePresence propagate = { true } >
214+ { hasErrors ? (
215+ < motion . div
216+ role = "alertdialog"
217+ transition = { {
218+ when : "afterChildren" ,
219+ } }
220+ exit = { { opacity : 0 } }
221+ className = { cn (
222+ "absolute bottom-0 left-0 flex max-h-[60%] w-full flex-col justify-start" ,
223+ $errors . show && "h-auto" ,
224+ ) }
225+ >
226+ < motion . button
227+ className = "flex h-4 min-h-4 w-full items-center justify-center rounded-t-xl bg-border-destructive"
228+ onClick = { ( ) => $toggleShowError ( ) }
229+ aria-label = {
230+ $errors . show ? "Hide error dialog" : "Show error dialog"
231+ }
232+ >
233+ < div className = "h-0.5 w-2/3 max-w-32 rounded-full bg-white/40" > </ div >
234+ </ motion . button >
225235
226- < div
227- aria-hidden = { ! $errors . show }
228- className = { cn (
229- "flex flex-col gap-6 overflow-y-scroll bg-surface-secondary p-6" ,
230- ! $errors . show && "pointer-events-none h-0 p-0" ,
231- ) }
232- >
233- < div className = "flex w-full flex-col gap-3" >
234- { $errors . diagnostics . map ( ( diagnostic , index ) => (
235- < ErrorBlock diagnostic = { diagnostic } key = { index } />
236- ) ) }
237- </ div >
238- </ div >
239- </ div >
236+ < AnimatePresence propagate = { true } >
237+ { $errors . show ? (
238+ < motion . div
239+ initial = { { height : 0 } }
240+ animate = { {
241+ height : "auto" ,
242+ } }
243+ exit = { { height : 0 } }
244+ className = "flex flex-col gap-6 overflow-y-scroll bg-surface-secondary"
245+ >
246+ < div className = "flex w-full flex-col gap-3 p-6" >
247+ { $errors . diagnostics . map ( ( diagnostic , index ) => (
248+ < ErrorBlock diagnostic = { diagnostic } key = { index } />
249+ ) ) }
250+ </ div >
251+ </ motion . div >
252+ ) : null }
253+ </ AnimatePresence >
254+ </ motion . div >
255+ ) : null }
256+ </ AnimatePresence >
240257 </ >
241258 ) ;
242259} ;
0 commit comments