Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
2.7 kB · 82 lines
TypeScript
at main
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283import { useEffect, useRef } from 'react'import { normalizeFullWidthDigits } from '../../utils/stringUtils.js'
// Delay before accepting a digit as a response, to prevent accidental// submissions when users start messages with numbers (e.g., numbered lists).// Short enough to feel instant for intentional presses, long enough to// cancel when the user types more characters.const DEFAULT_DEBOUNCE_MS = 400
/** * Detects when the user types a single valid digit into the prompt input, * debounces to avoid accidental submissions (e.g., "1. First item"), * trims the digit from the input, and fires a callback. * * Used by survey components that accept numeric responses typed directly * into the main prompt input. */export function useDebouncedDigitInput<T extends string = string>({ inputValue, setInputValue, isValidDigit, onDigit, enabled = true, once = false, debounceMs = DEFAULT_DEBOUNCE_MS,}: { inputValue: string setInputValue: (value: string) => void isValidDigit: (char: string) => char is T onDigit: (digit: T) => void enabled?: boolean once?: boolean debounceMs?: number}): void { const initialInputValue = useRef(inputValue) const hasTriggeredRef = useRef(false) const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null)
// Latest-ref pattern so callers can pass inline callbacks without causing // the effect to re-run (which would reset the debounce timer every render). const callbacksRef = useRef({ setInputValue, isValidDigit, onDigit }) callbacksRef.current = { setInputValue, isValidDigit, onDigit }
useEffect(() => { if (!enabled || (once && hasTriggeredRef.current)) { return }
if (debounceRef.current !== null) { clearTimeout(debounceRef.current) debounceRef.current = null }
if (inputValue !== initialInputValue.current) { const lastChar = normalizeFullWidthDigits(inputValue.slice(-1)) if (callbacksRef.current.isValidDigit(lastChar)) { const trimmed = inputValue.slice(0, -1) debounceRef.current = setTimeout( (debounceRef, hasTriggeredRef, callbacksRef, trimmed, lastChar) => { debounceRef.current = null hasTriggeredRef.current = true callbacksRef.current.setInputValue(trimmed) callbacksRef.current.onDigit(lastChar) }, debounceMs, debounceRef, hasTriggeredRef, callbacksRef, trimmed, lastChar, ) } }
return () => { if (debounceRef.current !== null) { clearTimeout(debounceRef.current) debounceRef.current = null } } }, [inputValue, enabled, once, debounceMs])}