File size: 3,501 Bytes
3d700dd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | import { useCallback } from "react";
import { isMobileUserAgent } from "#/utils/utils";
import {
ensureCursorVisible,
clearEmptyContent,
getClipboardFiles,
} from "#/components/features/chat/utils/chat-input.utils";
/**
* Hook for handling chat input events
*/
export const useChatInputEvents = (
chatInputRef: React.RefObject<HTMLDivElement | null>,
smartResize: () => void,
increaseHeightForEmptyContent: () => void,
checkIsContentEmpty: () => boolean,
clearEmptyContentHandler: () => void,
onFocus?: () => void,
onBlur?: () => void,
) => {
// Handle input events
const handleInput = useCallback(() => {
smartResize();
// Clear empty content to ensure placeholder shows
if (chatInputRef.current) {
clearEmptyContent(chatInputRef.current);
}
// Ensure cursor stays visible when content is scrollable
ensureCursorVisible(chatInputRef.current);
}, [smartResize, chatInputRef]);
// Handle paste events to clean up formatting and handle files
const handlePaste = useCallback(
(e: React.ClipboardEvent) => {
e.preventDefault();
const files = getClipboardFiles(e.clipboardData);
const hasFiles = files.length > 0;
if (hasFiles) {
// Handle file paste - let the file handling system process the files
// We'll trigger a custom event that the file handling system can listen to
const customEvent = new CustomEvent("pasteFiles", {
detail: { files },
});
document.dispatchEvent(customEvent);
return;
}
// Handle text paste as before
const text = e.clipboardData.getData("text/plain");
if (text) {
// Insert plain text
document.execCommand("insertText", false, text);
// Trigger resize
setTimeout(smartResize, 0);
}
},
[smartResize],
);
// Handle key events
const handleKeyDown = useCallback(
(e: React.KeyboardEvent, disabled: boolean, handleSubmit: () => void) => {
if (e.key !== "Enter") {
return;
}
// Ignore Enter key during IME composition (e.g., Chinese, Japanese, Korean input)
// When using IME, Enter is used to confirm the composition, not to submit
if (e.nativeEvent.isComposing) {
return;
}
if (checkIsContentEmpty()) {
e.preventDefault();
increaseHeightForEmptyContent();
return;
}
// Submit on Enter for everything except phones/tablets (where Enter
// inserts a newline and the user taps the send button). We gate on the
// user agent rather than touch capability so a desktop OS with a
// touchscreen (e.g. a Windows 2-in-1) still submits on Enter.
if (!isMobileUserAgent() && !e.shiftKey && !disabled) {
e.preventDefault();
handleSubmit();
}
},
[checkIsContentEmpty, increaseHeightForEmptyContent],
);
// Handle blur events to ensure placeholder shows when empty
const handleBlur = useCallback(() => {
// Clear empty content to ensure placeholder shows
if (chatInputRef.current) {
clearEmptyContent(chatInputRef.current);
}
// Call the original onBlur callback if provided
if (onBlur) {
onBlur();
}
}, [chatInputRef, onBlur]);
// Handle focus events
const handleFocus = useCallback(() => {
if (onFocus) {
onFocus();
}
}, [onFocus]);
return {
handleInput,
handlePaste,
handleKeyDown,
handleBlur,
handleFocus,
};
};
|