fix(chat): debounce post-send action menu
This commit is contained in:
@@ -124,6 +124,36 @@ describe("ChatInputBar", () => {
|
||||
expect(getButton("Open chat actions")).not.toBeNull();
|
||||
});
|
||||
|
||||
it("suppresses the Facebook WebView click that follows a pointer send for 300ms", () => {
|
||||
const now = vi.spyOn(Date, "now").mockReturnValue(1_000);
|
||||
renderBar();
|
||||
setTextareaValue(getTextarea(), "Hello Maya");
|
||||
const sendButton = getButton("Send message");
|
||||
const pointerDown = new Event("pointerdown", {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
});
|
||||
Object.defineProperty(pointerDown, "pointerType", { value: "touch" });
|
||||
|
||||
act(() => sendButton.dispatchEvent(pointerDown));
|
||||
|
||||
expect(mocks.dispatch).toHaveBeenCalledTimes(1);
|
||||
expect(mocks.dispatch).toHaveBeenCalledWith({
|
||||
type: "ChatSendMessage",
|
||||
content: "Hello Maya",
|
||||
});
|
||||
expect(getTextarea().value).toBe("");
|
||||
expect(getButton("Open chat actions")).toBe(sendButton);
|
||||
|
||||
now.mockReturnValue(1_299);
|
||||
act(() => sendButton.click());
|
||||
expect(container.querySelector('[aria-label="Chat actions"]')).toBeNull();
|
||||
|
||||
now.mockReturnValue(1_300);
|
||||
act(() => sendButton.click());
|
||||
expect(container.querySelector('[aria-label="Chat actions"]')).not.toBeNull();
|
||||
});
|
||||
|
||||
it("closes the menu on outside interaction and when disabled", () => {
|
||||
renderBar();
|
||||
act(() => getButton("Open chat actions").click());
|
||||
|
||||
@@ -17,7 +17,7 @@ import { ChatSendButton } from "./chat-send-button";
|
||||
import styles from "./chat-input-bar.module.css";
|
||||
|
||||
const log = new Logger("AppChatComponentsChatInputBar");
|
||||
const POINTER_SEND_CLICK_DEDUPE_MS = 500;
|
||||
const POINTER_SEND_DEBOUNCE_MS = 300;
|
||||
const CHAT_ACTION_MENU_ID = "chat-composer-action-menu";
|
||||
|
||||
export interface ChatInputBarProps {
|
||||
@@ -82,7 +82,7 @@ export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
|
||||
const handleSend = (source: "click" | "keyboard" | "pointerdown") => {
|
||||
if (source === "click") {
|
||||
const elapsed = Date.now() - lastPointerSendAtRef.current;
|
||||
if (elapsed >= 0 && elapsed < POINTER_SEND_CLICK_DEDUPE_MS) {
|
||||
if (elapsed >= 0 && elapsed < POINTER_SEND_DEBOUNCE_MS) {
|
||||
log.debug("[chat-input-bar] suppress duplicate click", {
|
||||
elapsed,
|
||||
contentLength: input.length,
|
||||
@@ -115,6 +115,15 @@ export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
|
||||
|
||||
const handleMenuToggle = () => {
|
||||
if (disabled || hasContent) return;
|
||||
const elapsed = Date.now() - lastPointerSendAtRef.current;
|
||||
if (elapsed >= 0 && elapsed < POINTER_SEND_DEBOUNCE_MS) {
|
||||
log.debug("[chat-input-bar] suppress post-send menu toggle", {
|
||||
elapsed,
|
||||
disabled,
|
||||
isFocused,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!isActionMenuOpen) textareaRef.current?.blur();
|
||||
setIsActionMenuOpen((open) => !open);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user