Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

102 lines
2.9 KiB
TypeScript

import { useCallback, useEffect, type RefObject } from "react";
import type {
AgentRichTextEditorHandle,
AgentRichTextPastedImage
} from "../agentRichText/AgentRichTextEditor";
import { useComposerFileDrop } from "./useComposerFileDrop";
interface Input {
composerControlsHardDisabled: boolean;
inputDisabled: boolean;
editorHandleRef: RefObject<AgentRichTextEditorHandle | null>;
composerRef: RefObject<HTMLFormElement | null>;
wasActiveRef: RefObject<boolean>;
lastComposerFocusRequestRef: RefObject<number | null>;
isActive: boolean;
composerFocusRequestSequence: number | null;
promptFilesSupported: boolean;
promptImagesSupported: boolean;
addDraftImages: (images: AgentRichTextPastedImage[]) => void;
addDraftFiles: (files: readonly File[]) => void;
onPromptImagesUnsupported?: () => void;
}
export function useComposerFocusAndDrop(input: Input) {
const {
composerControlsHardDisabled,
inputDisabled,
editorHandleRef,
composerRef,
wasActiveRef,
lastComposerFocusRequestRef,
isActive,
composerFocusRequestSequence,
promptFilesSupported,
promptImagesSupported,
addDraftImages,
addDraftFiles,
onPromptImagesUnsupported
} = input;
const handleMentionPaletteButton = useCallback((): void => {
if (composerControlsHardDisabled || inputDisabled) {
return;
}
editorHandleRef.current?.openMentionPalette();
}, [composerControlsHardDisabled, inputDisabled]);
const scheduleComposerFocus = useCallback(() => {
if (inputDisabled) {
return;
}
window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => {
editorHandleRef.current?.focusAtEnd();
});
});
}, [inputDisabled]);
const handlePastedImages = useCallback(
(images: AgentRichTextPastedImage[]): void => {
addDraftImages(images);
scheduleComposerFocus();
},
[addDraftImages, scheduleComposerFocus]
);
const { fileDropOverlayActive, fileDropOverlayHost } = useComposerFileDrop({
composerRef,
editorHandleRef,
inputDisabled,
promptFilesSupported,
promptImagesSupported,
addDraftImages,
addDraftFiles,
scheduleComposerFocus,
onPromptImagesUnsupported
});
useEffect(() => {
if (!isActive) {
wasActiveRef.current = false;
return;
}
if (!wasActiveRef.current) {
scheduleComposerFocus();
}
wasActiveRef.current = true;
}, [isActive, scheduleComposerFocus]);
useEffect(() => {
if (
composerFocusRequestSequence === null ||
composerFocusRequestSequence === lastComposerFocusRequestRef.current
) {
return;
}
lastComposerFocusRequestRef.current = composerFocusRequestSequence;
scheduleComposerFocus();
}, [composerFocusRequestSequence, scheduleComposerFocus]);
return {
fileDropOverlayActive,
fileDropOverlayHost,
handleMentionPaletteButton,
handlePastedImages
};
}