114 lines
3.2 KiB
TypeScript
114 lines
3.2 KiB
TypeScript
import {
|
|
type ClipboardEventHandler,
|
|
type KeyboardEvent,
|
|
useLayoutEffect,
|
|
useRef,
|
|
} from 'react';
|
|
|
|
const DRAFT_MIN_HEIGHT_PX = 40;
|
|
const DRAFT_MAX_HEIGHT_PX = 128;
|
|
|
|
// for fallback on some browser
|
|
function supportsNativeFieldSizing() {
|
|
return (
|
|
typeof CSS !== 'undefined' &&
|
|
typeof CSS.supports === 'function' &&
|
|
CSS.supports('field-sizing', 'content')
|
|
);
|
|
}
|
|
|
|
function resizeFallbackTextarea(textarea: HTMLTextAreaElement) {
|
|
textarea.style.height = 'auto';
|
|
const contentHeight = textarea.scrollHeight;
|
|
const borderHeight = Math.max(
|
|
0,
|
|
textarea.offsetHeight - textarea.clientHeight,
|
|
);
|
|
const borderBoxContentHeight = contentHeight + borderHeight;
|
|
const nextHeight = Math.min(
|
|
Math.max(borderBoxContentHeight, DRAFT_MIN_HEIGHT_PX),
|
|
DRAFT_MAX_HEIGHT_PX,
|
|
);
|
|
textarea.style.height = `${nextHeight}px`;
|
|
textarea.style.overflowY =
|
|
borderBoxContentHeight > DRAFT_MAX_HEIGHT_PX ? 'auto' : 'hidden';
|
|
}
|
|
|
|
export function EditorAgentDraftTextarea({
|
|
value,
|
|
onChange,
|
|
onPaste,
|
|
}: {
|
|
value: string;
|
|
onChange: (value: string) => void;
|
|
onPaste?: ClipboardEventHandler<HTMLTextAreaElement>;
|
|
}) {
|
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
|
|
|
useLayoutEffect(() => {
|
|
const textarea = textareaRef.current;
|
|
if (!textarea || supportsNativeFieldSizing()) {
|
|
return;
|
|
}
|
|
resizeFallbackTextarea(textarea);
|
|
}, [value]);
|
|
|
|
useLayoutEffect(() => {
|
|
const textarea = textareaRef.current;
|
|
if (!textarea || supportsNativeFieldSizing()) {
|
|
return undefined;
|
|
}
|
|
|
|
let previousWidth = textarea.getBoundingClientRect().width;
|
|
const resizeWhenWidthChanges = (nextWidth: number) => {
|
|
if (Math.abs(nextWidth - previousWidth) < 0.5) {
|
|
return;
|
|
}
|
|
previousWidth = nextWidth;
|
|
resizeFallbackTextarea(textarea);
|
|
};
|
|
|
|
if (typeof ResizeObserver !== 'undefined') {
|
|
const observer = new ResizeObserver((entries) => {
|
|
const entry = entries[0];
|
|
if (entry) {
|
|
resizeWhenWidthChanges(entry.contentRect.width);
|
|
}
|
|
});
|
|
observer.observe(textarea);
|
|
return () => observer.disconnect();
|
|
}
|
|
|
|
const handleWindowResize = () => {
|
|
resizeWhenWidthChanges(textarea.getBoundingClientRect().width);
|
|
};
|
|
window.addEventListener('resize', handleWindowResize);
|
|
return () => window.removeEventListener('resize', handleWindowResize);
|
|
}, []);
|
|
|
|
const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {
|
|
if (
|
|
event.key === 'Enter' &&
|
|
!event.shiftKey &&
|
|
!event.nativeEvent.isComposing &&
|
|
event.nativeEvent.keyCode !== 229
|
|
) {
|
|
event.preventDefault();
|
|
event.currentTarget.form?.requestSubmit();
|
|
}
|
|
};
|
|
|
|
return (
|
|
<textarea
|
|
ref={textareaRef}
|
|
className="editor-agent-conversation__draft-input max-h-32 min-h-10 min-w-0 flex-1 resize-none overflow-x-hidden overflow-y-auto overscroll-contain rounded-3xl border border-slate-200 bg-slate-50 px-3 py-2 text-sm text-slate-800 outline-none [field-sizing:content] focus:border-slate-400"
|
|
aria-label="发送给画布 Agent"
|
|
value={value}
|
|
rows={1}
|
|
onChange={(event) => onChange(event.currentTarget.value)}
|
|
onPaste={onPaste}
|
|
onKeyDown={handleKeyDown}
|
|
/>
|
|
);
|
|
}
|