| 1 | import { useCallback, useEffect, useState } from "react"; |
| 2 | import { |
| 3 | COMPOSER_TYPING_IDLE_MS, |
| 4 | createComposerTypingGuardState, |
| 5 | updateComposerTypingGuard, |
| 6 | } from "./composerTypingGuard"; |
| 7 | |
| 8 | export function useComposerTypingGuard(scope: string, requestIds: readonly string[]) { |
| 9 | const requestsKey = JSON.stringify(requestIds); |
| 10 | const [snapshot, setSnapshot] = useState(() => ({ |
| 11 | scope, |
| 12 | requestsKey, |
| 13 | state: updateComposerTypingGuard(createComposerTypingGuardState(), { |
| 14 | type: "requests", |
| 15 | requestIds, |
| 16 | now: Date.now(), |
| 17 | }), |
| 18 | })); |
| 19 | const state = snapshot.state; |
| 20 | if (snapshot.scope !== scope || snapshot.requestsKey !== requestsKey) { |
| 21 | setSnapshot((current) => ({ |
| 22 | scope, |
| 23 | requestsKey, |
| 24 | state: updateComposerTypingGuard( |
| 25 | current.scope === scope |
| 26 | ? current.state |
| 27 | : { ...createComposerTypingGuardState(), focused: current.state.focused }, |
| 28 | { type: "requests", requestIds, now: Date.now() }, |
| 29 | ), |
| 30 | })); |
| 31 | } |
| 32 | const dispatch = useCallback((event: Parameters<typeof updateComposerTypingGuard>[1]) => { |
| 33 | setSnapshot((current) => ({ |
| 34 | ...current, |
| 35 | state: updateComposerTypingGuard(current.state, event), |
| 36 | })); |
| 37 | }, []); |
| 38 | const onDraftChange = useCallback(() => dispatch({ type: "type", now: Date.now() }), [dispatch]); |
| 39 | const onFocus = useCallback(() => dispatch({ type: "focus" }), [dispatch]); |
| 40 | const onBlur = useCallback(() => dispatch({ type: "blur" }), [dispatch]); |
| 41 | const onSend = useCallback(() => dispatch({ type: "send" }), [dispatch]); |
| 42 | useEffect(() => { |
| 43 | if (state.held.size === 0) return; |
| 44 | const timeout = window.setTimeout( |
| 45 | () => dispatch({ type: "idle" }), |
| 46 | Math.max(0, state.lastTypedAt + COMPOSER_TYPING_IDLE_MS - Date.now()), |
| 47 | ); |
| 48 | return () => window.clearTimeout(timeout); |
| 49 | }, [state.held, state.lastTypedAt, dispatch]); |
| 50 | return { heldRequestIds: state.held, onDraftChange, onFocus, onBlur, onSend }; |
| 51 | } |