import { type ChangeEvent, type KeyboardEvent, useEffect, useRef, useState } from "react"; /** * Buffer text input locally so keystrokes don't cause a settings-wide * re-render (and optionally a server RPC round-trip) on every character. * `onCommit` fires on blur and on Enter. * * The draft resynchronizes from the upstream `value` only when the input * is not focused, so an external push (e.g. an optimistic settings * update from the user's own commit, or a reset to defaults) doesn't * clobber an in-progress edit. * * Returns a bag of props that should be spread onto an ``: * * const bag = useCommitOnBlur(instance.displayName ?? "", (next) => {...}); * */ export function useCommitOnBlur(value: string, onCommit: (next: string) => void) { const [draft, setDraft] = useState(value); const focusedRef = useRef(false); useEffect(() => { if (!focusedRef.current) { setDraft(value); } }, [value]); return { value: draft, onChange: (event: ChangeEvent) => { setDraft(event.target.value); }, onFocus: () => { focusedRef.current = true; }, onBlur: () => { focusedRef.current = false; if (draft !== value) { onCommit(draft); } }, onKeyDown: (event: KeyboardEvent) => { if (event.key === "Enter") { event.preventDefault(); (event.target as HTMLInputElement).blur(); } }, }; }