Skip to content

Commit fcb1859

Browse files
committed
feat: animations for error drawer
1 parent 7995e16 commit fcb1859

File tree

1 file changed

+67
-50
lines changed

1 file changed

+67
-50
lines changed

src/Preview.tsx

Lines changed: 67 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Button } from "@/components/Button";
22
import { ResizablePanel } from "@/components/Resizable";
3+
import { useTheme } from "@/contexts/theme";
34
import {
45
type Diagnostic,
56
type InternalDiagnostic,
@@ -10,7 +11,8 @@ import { useDebouncedValue } from "@/hooks/debounce";
1011
import { useStore } from "@/store";
1112
import { cn } from "@/utils/cn";
1213
import { 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

1517
export 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

Comments
 (0)