44 lines · 1.4 KB · TypeScript
RawDownload
import { type ChangeEvent, type KeyboardEvent, 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 `<Input>`: * *   const bag = useCommitOnBlur(instance.displayName ?? "", (next) => {...}); *   <Input {...bag} placeholder="e.g. Work" /> */export function useCommitOnBlur(value: string, onCommit: (next: string) => void) {  const [draft, setDraft] = useState<string | null>(null);   return {    value: draft ?? value,    onChange: (event: ChangeEvent<HTMLInputElement>) => {      setDraft(event.target.value);    },    onFocus: () => {      setDraft(value);    },    onBlur: () => {      const next = draft ?? value;      setDraft(null);      if (next !== value) {        onCommit(next);      }    },    onKeyDown: (event: KeyboardEvent<HTMLInputElement>) => {      if (event.nativeEvent.isComposing || event.keyCode === 229) return;      if (event.key === "Enter") {        event.preventDefault();        (event.target as HTMLInputElement).blur();      }    },  };}