1import { type ChangeEvent, type KeyboardEvent, useRef, useState } from "react";
2
3export function useCommitOnBlur(
4 value: string,
5 onCommit: (next: string) => void,
6 normalizeDraft?: (previous: string, next: string) => string,
7) {
8 const [draft, setDraft] = useState<string | null>(null);
9 const valueOnFocus = useRef(value);
10
11 return {
12 value: draft ?? value,
13 onChange: (event: ChangeEvent<HTMLInputElement>) => {
14 const next = event.target.value;
15 setDraft(normalizeDraft ? normalizeDraft(draft ?? value, next) : next);
16 },
17 onFocus: () => {
18 valueOnFocus.current = value;
19 setDraft(value);
20 },
21 onBlur: () => {
22 const next = draft ?? value;
23 setDraft(null);
24 if (next !== valueOnFocus.current && next !== value) {
25 onCommit(next);
26 }
27 },
28 onKeyDown: (event: KeyboardEvent<HTMLInputElement>) => {
29 if (event.nativeEvent.isComposing || event.keyCode === 229) return;
30 if (event.key === "Enter") {
31 event.preventDefault();
32 (event.target as HTMLInputElement).blur();
33 }
34 },
35 };
36}