11import  {  Button  }  from  "@/components/Button" ; 
22import  {  ResizablePanel  }  from  "@/components/Resizable" ; 
3+ import  {  useTheme  }  from  "@/contexts/theme" ; 
34import  { 
45type  Diagnostic , 
56type  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  =  ( )  =>  { 
1618const  $wasmState  =  useStore ( ( state )  =>  state . wasmState ) ; 
@@ -87,9 +89,23 @@ export const Preview: FC = () => {
8789) } 
8890> 
8991< div  className = "flex w-full items-center justify-between" > 
90- < p  className = "font-semibold text-3xl text-content-primary" > 
91- Parameters
92- </ p > 
92+ < div  className = "flex items-center justify-center gap-4" > 
93+ < p  className = "font-semibold text-3xl text-content-primary" > 
94+ Parameters
95+ </ p > 
96+ 
97+ < AnimatePresence > 
98+ { isDebouncing  &&  $wasmState  ===  "loaded"  ? ( 
99+ < motion . div 
100+ initial = { {  opacity : 0 ,  scale : 0.75  } } 
101+ animate = { {  opacity : 1 ,  scale : 1  } } 
102+ exit = { {  opacity : 0 ,  scale : 0.75  } } 
103+ > 
104+ < LoaderIcon  className = "animate-spin text-content-primary"  /> 
105+ </ motion . div > 
106+ )  : null } 
107+ </ AnimatePresence > 
108+ </ div > 
93109< Button  variant = "destructive" > Reset form</ Button > 
94110</ div > 
95111
@@ -98,9 +114,6 @@ export const Preview: FC = () => {
98114"flex h-full w-full items-center justify-center overflow-x-clip rounded-xl border p-4" , 
99115output  &&  "block overflow-y-scroll" , 
100116) } 
101- style = { { 
102- opacity : isDebouncing  &&  $wasmState  ===  "loaded"  ? 0.5  : 1 , 
103- } } 
104117> 
105118{ output  ? ( 
106119< div  className = "flex flex-col gap-4" > 
@@ -183,60 +196,75 @@ const ErrorPane = () => {
183196const  $errors  =  useStore ( ( state )  =>  state . errors ) ; 
184197const  $toggleShowError  =  useStore ( ( state )  =>  state . toggleShowError ) ; 
185198
186- if  ( $errors . diagnostics . length  ===  0 )  { 
187- return  null ; 
188- } 
199+ const  hasErrors  =  useMemo ( ( )  =>  $errors . diagnostics . length  >  0 ,  [ $errors ] ) ; 
189200
190201return  ( 
191202< > 
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/20 dark:bg-black/50" , 
203- ) } 
204- onClick = { ( )  =>  { 
205- $toggleShowError ( false ) ; 
206- } } 
207- > 
208- { /* OVERLAY */ } 
209- </ div > 
203+ < AnimatePresence  propagate = { true } > 
204+ { $errors . show  &&  hasErrors  ? ( 
205+ // lint/a11y/useKeyWithClickEvents: key events don't seem to 
206+ // work for divs, and I'm otherwise not sure how to make this element 
207+ // more accesible. But I think it's fine since the functionality is able to 
208+ // be used with the button below. 
209+ < motion . div 
210+ initial = { {  opacity : 0  } } 
211+ animate = { {  opacity : 1  } } 
212+ exit = { {  opacity : 0  } } 
213+ aria-hidden = { true } 
214+ className = "absolute top-0 left-0 h-full w-full cursor-pointer bg-black/10 dark:bg-black/50" 
215+ onClick = { ( )  =>  { 
216+ $toggleShowError ( false ) ; 
217+ } } 
218+ > 
219+ { /* OVERLAY */ } 
220+ </ motion . div > 
221+ )  : null } 
222+ </ AnimatePresence > 
210223
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 > 
224+ < AnimatePresence  propagate = { true } > 
225+ { hasErrors  ? ( 
226+ < motion . div 
227+ role = "alertdialog" 
228+ transition = { { 
229+ when : "afterChildren" , 
230+ } } 
231+ exit = { {  opacity : 0  } } 
232+ className = { cn ( 
233+ "absolute bottom-0 left-0 flex max-h-[60%] w-full flex-col justify-start" , 
234+ $errors . show  &&  "h-auto" , 
235+ ) } 
236+ > 
237+ < motion . button 
238+ className = "flex h-4 min-h-4 w-full items-center justify-center rounded-t-xl bg-border-destructive" 
239+ onClick = { ( )  =>  $toggleShowError ( ) } 
240+ aria-label = { 
241+ $errors . show  ? "Hide error dialog"  : "Show error dialog" 
242+ } 
243+ > 
244+ < div  className = "h-0.5 w-2/3 max-w-32 rounded-full bg-white/40" > </ div > 
245+ </ motion . button > 
225246
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 > 
247+ < AnimatePresence  propagate = { true } > 
248+ { $errors . show  ? ( 
249+ < motion . div 
250+ initial = { {  height : 0  } } 
251+ animate = { { 
252+ height : "auto" , 
253+ } } 
254+ exit = { {  height : 0  } } 
255+ className = "flex flex-col gap-6 overflow-y-scroll bg-surface-secondary" 
256+ > 
257+ < div  className = "flex w-full flex-col gap-3 p-6" > 
258+ { $errors . diagnostics . map ( ( diagnostic ,  index )  =>  ( 
259+ < ErrorBlock  diagnostic = { diagnostic }  key = { index }  /> 
260+ ) ) } 
261+ </ div > 
262+ </ motion . div > 
263+ )  : null } 
264+ </ AnimatePresence > 
265+ </ motion . div > 
266+ )  : null } 
267+ </ AnimatePresence > 
240268</ > 
241269) ; 
242270} ; 
0 commit comments