Files
Excalidraw/excalidraw/excalidraw-app/collab/CollabError.tsx
T
Yuzhong Zhang 602f4629ff init frontend
2025-07-05 23:22:48 +08:00

60 lines
1.5 KiB
TypeScript

import { Tooltip } from "../../packages/excalidraw/components/Tooltip";
import { warning } from "../../packages/excalidraw/components/icons";
import clsx from "clsx";
import { useEffect, useRef, useState } from "react";
import "./CollabError.scss";
import { atom } from "jotai";
export type ErrorIndicator = {
message: string | null;
/** used to rerun the useEffect responsible for animation */
nonce: number;
};
const _collabErrorIndicatorAtom = atom<ErrorIndicator>({
message: null,
nonce: 0,
});
export const collabErrorIndicatorAtom = atom(
(get) => get(_collabErrorIndicatorAtom),
(get, set, update: ErrorIndicator) => set(_collabErrorIndicatorAtom, update),
);
const CollabError = ({ collabError }: { collabError: ErrorIndicator }) => {
const [isAnimating, setIsAnimating] = useState(false);
const clearAnimationRef = useRef<string | number | NodeJS.Timeout>();
useEffect(() => {
setIsAnimating(true);
clearAnimationRef.current = setTimeout(() => {
setIsAnimating(false);
}, 1000);
return () => {
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;