UNPKG

@chayns-components/emoji-input

Version:
103 lines 3.3 kB
import { useCallback, useEffect, useRef, useState } from 'react'; import { getCurrentCursorPosition } from '../utils/selection'; export const useCursorPosition = (editorRef, onChange, options) => { const { isDisabled } = options || {}; const [position, setPosition] = useState(null); const rafIdRef = useRef(null); const lastPositionRef = useRef(null); const emit = useCallback(() => { const el = editorRef.current; if (!el || isDisabled) return; const pos = getCurrentCursorPosition(el); if (pos !== null && pos !== lastPositionRef.current) { lastPositionRef.current = pos; setPosition(pos); if (typeof onChange === 'function') onChange(pos); } }, [editorRef, onChange, isDisabled]); const scheduleEmit = useCallback(() => { if (rafIdRef.current != null) cancelAnimationFrame(rafIdRef.current); rafIdRef.current = requestAnimationFrame(() => { rafIdRef.current = null; emit(); }); }, [emit]); const trigger = useCallback(() => { scheduleEmit(); }, [scheduleEmit]); useEffect(() => { const el = editorRef.current; if (!el) return () => {}; const onKeyUp = e => { const navKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End', 'PageUp', 'PageDown', 'Backspace', 'Delete']; if (navKeys.includes(e.key)) scheduleEmit(); }; el.addEventListener('keyup', onKeyUp, { passive: true }); return () => el.removeEventListener('keyup', onKeyUp); }, [editorRef, scheduleEmit]); useEffect(() => { const el = editorRef.current; if (!el) return () => {}; const onMouseUp = () => scheduleEmit(); const onTouchEnd = () => scheduleEmit(); el.addEventListener('mouseup', onMouseUp, { passive: true }); el.addEventListener('touchend', onTouchEnd, { passive: true }); return () => { el.removeEventListener('mouseup', onMouseUp); el.removeEventListener('touchend', onTouchEnd); }; }, [editorRef, scheduleEmit]); useEffect(() => { const onSelectionChange = () => { const el = editorRef.current; const sel = document.getSelection(); if (!el || !sel) return; const { anchorNode } = sel; if (anchorNode && el.contains(anchorNode) && document.activeElement === el) { scheduleEmit(); } }; document.addEventListener('selectionchange', onSelectionChange, { passive: true }); return () => document.removeEventListener('selectionchange', onSelectionChange); }, [editorRef, scheduleEmit]); useEffect(() => { const el = editorRef.current; if (!el) return () => {}; const onFocus = () => scheduleEmit(); const onBlur = () => { lastPositionRef.current = null; setPosition(null); }; el.addEventListener('focus', onFocus, { passive: true }); el.addEventListener('blur', onBlur, { passive: true }); return () => { el.removeEventListener('focus', onFocus); el.removeEventListener('blur', onBlur); }; }, [editorRef, scheduleEmit]); useEffect(() => () => { if (rafIdRef.current != null) cancelAnimationFrame(rafIdRef.current); }, []); return { position, trigger, lastPositionRef }; }; //# sourceMappingURL=cursor.js.map