Files
eranos/src/hooks/useInsertText.ts
T
Mary Kate Fain 1f5ce2546c Add emoji picker and shortcode autocomplete to zap comment box
Extract shared useInsertText hook to DRY up the duplicated text
insertion logic across ComposeBox, DMChatArea, and ZapDialog.
Add EmojiPicker (GUI) and EmojiShortcodeAutocomplete (:shortcode
typing) to the zap comment textarea, and also add shortcode
autocomplete to the DM chat input which was previously missing it.

Closes #176
2026-03-27 17:46:16 -05:00

65 lines
2.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useCallback } from 'react';
interface InsertAtCursorParams {
start: number;
end: number;
replacement: string;
}
/**
* Shared hook for inserting text at the cursor position within a textarea.
*
* Returns two helpers:
* - `insertAtCursor` splice a replacement string between explicit start/end
* offsets (used by autocomplete components like EmojiShortcodeAutocomplete).
* - `insertEmoji` insert text at the textarea's *current* selection
* (used by the EmojiPicker GUI button).
*
* Both restore focus and cursor position after the insertion.
*/
export function useInsertText(
textareaRef: React.RefObject<HTMLTextAreaElement | null>,
content: string,
setContent: (value: string) => void,
) {
/** Insert a replacement between explicit `start` and `end` offsets. */
const insertAtCursor = useCallback(
({ start, end, replacement }: InsertAtCursorParams) => {
const newContent = content.slice(0, start) + replacement + content.slice(end);
setContent(newContent);
requestAnimationFrame(() => {
const textarea = textareaRef.current;
if (textarea) {
textarea.focus();
const pos = start + replacement.length;
textarea.setSelectionRange(pos, pos);
}
});
},
[content, setContent, textareaRef],
);
/** Insert text at the textarea's current selection (or append if no ref). */
const insertEmoji = useCallback(
(emoji: string) => {
const textarea = textareaRef.current;
if (textarea) {
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
const newContent = content.slice(0, start) + emoji + content.slice(end);
setContent(newContent);
requestAnimationFrame(() => {
textarea.focus();
const pos = start + emoji.length;
textarea.setSelectionRange(pos, pos);
});
} else {
setContent(content + emoji);
}
},
[content, setContent, textareaRef],
);
return { insertAtCursor, insertEmoji };
}