From 73c7dac802eb6656dff3bffce9f4c5355e9f9e38 Mon Sep 17 00:00:00 2001 From: Drew Haven Date: Wed, 28 May 2025 15:22:32 -0700 Subject: [PATCH] Edit strong-starts --- src/components/AutoSaveTextarea.tsx | 71 +++++++++++++++++++ .../_authenticated/document.$documentId.tsx | 30 +++++--- 2 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 src/components/AutoSaveTextarea.tsx diff --git a/src/components/AutoSaveTextarea.tsx b/src/components/AutoSaveTextarea.tsx new file mode 100644 index 0000000..bdfb15c --- /dev/null +++ b/src/components/AutoSaveTextarea.tsx @@ -0,0 +1,71 @@ +import { useState, useRef, useEffect } from "react"; + +/** + * AutoSaveTextarea is a textarea that auto-saves its value after the user stops typing for a short delay. + * Shows a green flash and a "saved" message when the save is successful. + */ +export function AutoSaveTextarea({ + value: initialValue, + onSave, + delay = 500, + className = "", + ...props +}: { + value: string; + onSave: (value: string) => Promise; + delay?: number; + className?: string; + [key: string]: any; +}) { + const [value, setValue] = useState(initialValue || ""); + const [saving, setSaving] = useState(false); + const [saved, setSaved] = useState(false); + const [flash, setFlash] = useState(false); + const timeoutRef = useRef(null); + const saveTimeoutRef = useRef(null); + + useEffect(() => { + setValue(initialValue || ""); + }, [initialValue]); + + useEffect(() => { + return () => { + if (timeoutRef.current) window.clearTimeout(timeoutRef.current); + if (saveTimeoutRef.current) window.clearTimeout(saveTimeoutRef.current); + }; + }, []); + + const handleChange = (e: React.ChangeEvent) => { + setValue(e.target.value); + setSaved(false); + setFlash(false); + if (timeoutRef.current) window.clearTimeout(timeoutRef.current); + timeoutRef.current = window.setTimeout(async () => { + setSaving(true); + try { + await onSave(e.target.value); + setSaved(true); + setFlash(true); + saveTimeoutRef.current = window.setTimeout(() => setFlash(false), 600); + } finally { + setSaving(false); + } + }, delay); + }; + + return ( +
+