summaryrefslogtreecommitdiffstats
path: root/excalidraw-app/collab/CollabError.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'excalidraw-app/collab/CollabError.tsx')
-rw-r--r--excalidraw-app/collab/CollabError.tsx54
1 files changed, 54 insertions, 0 deletions
diff --git a/excalidraw-app/collab/CollabError.tsx b/excalidraw-app/collab/CollabError.tsx
new file mode 100644
index 0000000..76828cf
--- /dev/null
+++ b/excalidraw-app/collab/CollabError.tsx
@@ -0,0 +1,54 @@
+import { Tooltip } from "@excalidraw/excalidraw/components/Tooltip";
+import { warning } from "@excalidraw/excalidraw/components/icons";
+import clsx from "clsx";
+import { useEffect, useRef, useState } from "react";
+import { atom } from "../app-jotai";
+
+import "./CollabError.scss";
+
+type ErrorIndicator = {
+ message: string | null;
+ /** used to rerun the useEffect responsible for animation */
+ nonce: number;
+};
+
+export const collabErrorIndicatorAtom = atom<ErrorIndicator>({
+ message: null,
+ nonce: 0,
+});
+
+const CollabError = ({ collabError }: { collabError: ErrorIndicator }) => {
+ const [isAnimating, setIsAnimating] = useState(false);
+ const clearAnimationRef = useRef<string | number>(0);
+
+ useEffect(() => {
+ setIsAnimating(true);
+ clearAnimationRef.current = window.setTimeout(() => {
+ setIsAnimating(false);
+ }, 1000);
+
+ return () => {
+ window.clearTimeout(clearAnimationRef.current);
+ };
+ }, [collabError.message, collabError.nonce]);
+
+ if (!collabError.message) {
+ return null;
+ }
+
+ return (
+ <Tooltip label={collabError.message} long={true}>
+ <div
+ className={clsx("collab-errors-button", {
+ "collab-errors-button-shake": isAnimating,
+ })}
+ >
+ {warning}
+ </div>
+ </Tooltip>
+ );
+};
+
+CollabError.displayName = "CollabError";
+
+export default CollabError;