@ant-design/x
Version:
Craft AI-driven interfaces effortlessly
159 lines (153 loc) • 4.44 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import pickAttrs from '@rc-component/util/lib/pickAttrs';
import getValue from '@rc-component/util/lib/utils/get';
import { Input } from 'antd';
import { clsx } from 'clsx';
import React from 'react';
import { SenderContext } from "../context";
function getComponent(components, path, defaultComponent) {
return getValue(components, path) || defaultComponent;
}
const TextArea = /*#__PURE__*/React.forwardRef((_, ref) => {
const {
value,
onChange,
onKeyUp,
onKeyDown,
onPaste,
onPasteFile,
disabled,
readOnly,
submitType = 'enter',
prefixCls,
styles = {},
classNames = {},
autoSize,
components,
triggerSend,
placeholder,
onFocus,
onBlur,
...restProps
} = React.useContext(SenderContext);
const inputRef = React.useRef(null);
const insert = (insertValue, positions = 'cursor') => {
const textArea = inputRef.current?.resizableTextArea?.textArea;
// 获取当前文本内容
const currentText = textArea.value;
let startPos = currentText.length;
let endPos = currentText.length;
if (positions === 'cursor') {
startPos = textArea?.selectionStart;
endPos = textArea?.selectionEnd;
}
if (positions === 'start') {
startPos = 0;
endPos = 0;
}
// 在光标位置插入新文本
textArea.value = currentText.substring(0, startPos) + insertValue + currentText.substring(endPos, currentText.length);
// 设置新的光标位置
textArea.selectionStart = startPos + insertValue.length;
textArea.selectionEnd = startPos + insertValue.length;
// 重新聚焦到textarea
textArea.focus();
onChange?.(textArea.value);
};
const clear = () => {
onChange?.('');
};
const getValue = () => {
return {
value: value || '',
slotConfig: []
};
};
React.useImperativeHandle(ref, () => {
return {
nativeElement: inputRef.current?.resizableTextArea?.textArea,
focus: inputRef.current?.focus,
blur: inputRef.current?.blur,
insert,
clear,
getValue
};
});
// ============================ Submit ============================
const isCompositionRef = React.useRef(false);
const onInternalCompositionStart = () => {
isCompositionRef.current = true;
};
const onInternalCompositionEnd = () => {
isCompositionRef.current = false;
};
const onInternalKeyDown = e => {
const eventRes = onKeyDown?.(e);
const {
key,
shiftKey,
ctrlKey,
altKey,
metaKey
} = e;
if (isCompositionRef.current || key !== 'Enter' || eventRes === false) {
return;
}
// 处理Enter键提交
if (key === 'Enter') {
const isModifierPressed = ctrlKey || altKey || metaKey;
const shouldSubmit = submitType === 'enter' && !shiftKey && !isModifierPressed || submitType === 'shiftEnter' && shiftKey && !isModifierPressed;
if (shouldSubmit) {
e.preventDefault();
triggerSend?.();
return;
}
}
};
// ============================ Paste =============================
const onInternalPaste = e => {
// Get files
const files = e.clipboardData?.files;
const text = e.clipboardData?.getData('text/plain');
if (!text && files?.length && onPasteFile) {
onPasteFile(files);
e.preventDefault();
}
onPaste?.(e);
};
const InputTextArea = getComponent(components, ['input'], Input.TextArea);
const domProps = pickAttrs(restProps, {
attr: true,
aria: true,
data: true
});
const inputProps = {
...domProps,
ref: inputRef
};
const mergeOnChange = event => {
onChange?.(event.target.value, event);
};
return /*#__PURE__*/React.createElement(InputTextArea, _extends({}, inputProps, {
disabled: disabled,
style: styles.input,
className: clsx(`${prefixCls}-input`, classNames.input),
autoSize: autoSize,
value: value,
onChange: mergeOnChange,
onKeyUp: onKeyUp,
onCompositionStart: onInternalCompositionStart,
onCompositionEnd: onInternalCompositionEnd,
onKeyDown: onInternalKeyDown,
onPaste: onInternalPaste,
variant: "borderless",
readOnly: readOnly,
placeholder: placeholder,
onFocus: onFocus,
onBlur: onBlur
}));
});
if (process.env.NODE_ENV !== 'production') {
TextArea.displayName = 'TextArea';
}
export default TextArea;