import React, { useContext, useEffect, useMemo, useRef, useCallback } from "react"; import type { PaintKeyboardEvent } from "paintcannon"; import { useKeyboard } from "./use-keyboard.ts"; declare const priorityBrand: unique symbol; export type Priority = number & { [priorityBrand]: never; }; export const UNCHAINED_PRIORITY: Priority = 0 as Priority; export const FILE_SUGGESTIONS_PRIORITY: Priority = 1 as Priority; type InputPriorityRegistration = { priority: number; id: number; }; type InputPriorityContextValue = { register: (priority: number, id: number) => void; unregister: (id: number) => void; getActiveId: () => number | null; }; const InputPriorityContext = React.createContext(null); let nextId = 0; export function InputPriorityProvider({ children }: { children: React.ReactNode }) { const registrationsRef = useRef>(new Map()); const register = useCallback((priority: number, id: number) => { registrationsRef.current.set(id, { priority, id, }); }, []); const unregister = useCallback((id: number) => { registrationsRef.current.delete(id); }, []); const getActiveId = useCallback(() => { let maxPriority = -Infinity; let activeId: number | null = null; for (const reg of registrationsRef.current.values()) { if (reg.priority > maxPriority) { maxPriority = reg.priority; activeId = reg.id; } } return activeId; }, []); const value = useMemo( () => ({ register, unregister, getActiveId, }), [register, unregister, getActiveId], ); return {children}; } export function usePriorityInput( priority: Priority, callback: (event: PaintKeyboardEvent) => void, ) { const context = useContext(InputPriorityContext); const idRef = useRef(nextId++); useEffect(() => { if (!context) return; context.register(priority, idRef.current); return () => { context.unregister(idRef.current); }; }, [priority, context]); useKeyboard(event => { if (event.shiftKey && event.key === "Tab") { const activeId = context?.getActiveId(); const myId = idRef.current; const willFire = !context || myId === activeId; if (willFire) { callback(event); } } else { callback(event); } }); }