| 1 | import { useCallback, useRef, useState } from "react"; |
| 2 | |
| 3 | import type { ComposerTrigger } from "../../composer-logic"; |
| 4 | |
| 5 | /** Keep a dismissed suggestion closed until the caret leaves its token. */ |
| 6 | export function useComposerTriggerState(initialTrigger: () => ComposerTrigger | null) { |
| 7 | const [trigger, setActiveTrigger] = useState(initialTrigger); |
| 8 | const dismissedTriggerRef = useRef<ComposerTrigger | null>(null); |
| 9 | |
| 10 | const resolveTrigger = useCallback((candidate: ComposerTrigger | null) => { |
| 11 | const dismissed = dismissedTriggerRef.current; |
| 12 | return candidate && |
| 13 | dismissed && |
| 14 | candidate.kind === dismissed.kind && |
| 15 | candidate.rangeStart === dismissed.rangeStart |
| 16 | ? null |
| 17 | : candidate; |
| 18 | }, []); |
| 19 | |
| 20 | const setTrigger = useCallback( |
| 21 | (candidate: ComposerTrigger | null) => { |
| 22 | const activeTrigger = resolveTrigger(candidate); |
| 23 | if (candidate === null || activeTrigger !== null) { |
| 24 | dismissedTriggerRef.current = null; |
| 25 | } |
| 26 | setActiveTrigger(activeTrigger); |
| 27 | }, |
| 28 | [resolveTrigger], |
| 29 | ); |
| 30 | |
| 31 | const dismissTrigger = useCallback((candidate: ComposerTrigger | null) => { |
| 32 | dismissedTriggerRef.current = candidate; |
| 33 | setActiveTrigger(null); |
| 34 | }, []); |
| 35 | |
| 36 | const resetTrigger = useCallback((candidate: ComposerTrigger | null) => { |
| 37 | dismissedTriggerRef.current = null; |
| 38 | setActiveTrigger(candidate); |
| 39 | }, []); |
| 40 | |
| 41 | return { trigger, setTrigger, resolveTrigger, dismissTrigger, resetTrigger }; |
| 42 | } |