Fix prompt placeholder overlap during IME input
This commit is contained in:
parent
f1535a94c2
commit
f254551522
@ -49,15 +49,16 @@ export function PlaygroundPromptMentionInput(props: {
|
||||
const editableRef = useRef<HTMLDivElement>(null);
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
const blurTimerRef = useRef<number | undefined>(undefined);
|
||||
const isComposingRef = useRef(false);
|
||||
const [text, setText] = useState(props.value);
|
||||
const [focused, setFocused] = useState(false);
|
||||
const [isComposing, setIsComposing] = useState(false);
|
||||
const [hasEditableContent, setHasEditableContent] = useState(() => promptTextHasContent(props.value));
|
||||
const [mentionOpen, setMentionOpen] = useState(false);
|
||||
const [mentionAtIndex, setMentionAtIndex] = useState(-1);
|
||||
const [mentionSearch, setMentionSearch] = useState('');
|
||||
const [highlightIndex, setHighlightIndex] = useState(0);
|
||||
const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0, placement: 'bottom' as 'bottom' | 'top' });
|
||||
const showPlaceholder = text.trim().length === 0;
|
||||
const showPlaceholder = !hasEditableContent;
|
||||
|
||||
const uploadSignature = useMemo(
|
||||
() => props.uploads.map((item) => `${item.id}:${item.kind}:${item.name}:${item.url}`).join('|'),
|
||||
@ -78,8 +79,12 @@ export function PlaygroundPromptMentionInput(props: {
|
||||
}, [mentionItems, mentionSearch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.value === text) return;
|
||||
if (props.value === text) {
|
||||
setHasEditableContent(promptTextHasContent(props.value));
|
||||
return;
|
||||
}
|
||||
setText(props.value);
|
||||
setHasEditableContent(promptTextHasContent(props.value));
|
||||
if (!focused) {
|
||||
requestAnimationFrame(() => renderToEditable(props.value));
|
||||
}
|
||||
@ -89,6 +94,7 @@ export function PlaygroundPromptMentionInput(props: {
|
||||
const cleaned = removeInvalidPlaygroundResourceTokens(text, props.uploads);
|
||||
if (cleaned !== text) {
|
||||
setText(cleaned);
|
||||
setHasEditableContent(promptTextHasContent(cleaned));
|
||||
props.onChange(cleaned);
|
||||
requestAnimationFrame(() => renderToEditable(cleaned));
|
||||
return;
|
||||
@ -149,6 +155,7 @@ export function PlaygroundPromptMentionInput(props: {
|
||||
const editable = editableRef.current;
|
||||
if (!editable) return;
|
||||
editable.innerHTML = textToHtml(nextText, props.uploads);
|
||||
setHasEditableContent(promptTextHasContent(nextText));
|
||||
if (typeof caret === 'number') {
|
||||
editable.focus();
|
||||
setCaretOffset(editable, caret);
|
||||
@ -157,8 +164,10 @@ export function PlaygroundPromptMentionInput(props: {
|
||||
|
||||
function commitFromEditable(shouldInspectMention: boolean, event?: InputEvent) {
|
||||
const editable = editableRef.current;
|
||||
if (!editable || props.disabled || isComposing) return;
|
||||
if (!editable || props.disabled) return;
|
||||
const nextText = serializeEditableToPlainText(editable);
|
||||
setHasEditableContent(promptTextHasContent(nextText));
|
||||
if (isComposingRef.current || event?.isComposing) return;
|
||||
setText(nextText);
|
||||
props.onChange(nextText);
|
||||
if (!shouldInspectMention) return;
|
||||
@ -206,6 +215,7 @@ export function PlaygroundPromptMentionInput(props: {
|
||||
const nextText = `${before}${token} ${after}`;
|
||||
const nextCaret = before.length + token.length + 1;
|
||||
setText(nextText);
|
||||
setHasEditableContent(promptTextHasContent(nextText));
|
||||
props.onChange(nextText);
|
||||
closeMention();
|
||||
requestAnimationFrame(() => renderToEditable(nextText, nextCaret));
|
||||
@ -257,10 +267,13 @@ export function PlaygroundPromptMentionInput(props: {
|
||||
}, 120);
|
||||
}}
|
||||
onCompositionEnd={() => {
|
||||
setIsComposing(false);
|
||||
isComposingRef.current = false;
|
||||
setHasEditableContent(editablePromptTextHasContent(editableRef.current));
|
||||
requestAnimationFrame(() => commitFromEditable(true));
|
||||
}}
|
||||
onCompositionStart={() => setIsComposing(true)}
|
||||
onCompositionStart={() => {
|
||||
isComposingRef.current = true;
|
||||
}}
|
||||
onFocus={() => {
|
||||
setFocused(true);
|
||||
if (blurTimerRef.current) window.clearTimeout(blurTimerRef.current);
|
||||
@ -313,6 +326,14 @@ export function PlaygroundPromptMentionInput(props: {
|
||||
);
|
||||
}
|
||||
|
||||
function promptTextHasContent(raw: string) {
|
||||
return raw.trim().length > 0;
|
||||
}
|
||||
|
||||
function editablePromptTextHasContent(editable: HTMLElement | null) {
|
||||
return editable ? promptTextHasContent(serializeEditableToPlainText(editable)) : false;
|
||||
}
|
||||
|
||||
function MentionThumb(props: { item: PlaygroundMentionUpload }) {
|
||||
if (props.item.kind === 'image') {
|
||||
return <img className="promptMentionThumb" src={props.item.url} alt="" draggable={false} />;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user