UNPKG

@ant-design/pro-chat

Version:
219 lines (214 loc) 9.08 kB
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2"; import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime"; import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator"; import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray"; import _taggedTemplateLiteral from "@babel/runtime/helpers/esm/taggedTemplateLiteral"; var _templateObject, _templateObject2, _templateObject3, _templateObject4, _templateObject5; import { SendOutlined } from '@ant-design/icons'; import { Button, ConfigProvider } from 'antd'; import { createStyles, cx } from 'antd-style'; import { useContext, useEffect, useMemo, useRef, useState } from 'react'; import { Flexbox } from 'react-layout-kit'; import { useStore } from "../../store"; import useProChatLocale from "../../hooks/useProChatLocale"; import ActionBar from "./ActionBar"; import { AutoCompleteTextArea } from "./AutoCompleteTextArea"; import StopLoadingIcon from "./StopLoading"; import { jsx as _jsx } from "react/jsx-runtime"; import { jsxs as _jsxs } from "react/jsx-runtime"; var useStyles = createStyles(function (_ref) { var css = _ref.css, responsive = _ref.responsive, token = _ref.token; return { container: css(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n position: sticky;\n z-index: ", ";\n bottom: 0;\n\n padding-top: 12px;\n padding-bottom: 24px;\n\n background-image: linear-gradient(to top, ", " 88%, transparent 100%);\n\n ", " {\n width: 100%;\n }\n "])), token.zIndexPopupBase, token.colorBgLayout, responsive.mobile), boxShadow: css(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n position: relative;\n border-radius: 8px;\n box-shadow: ", ";\n "])), token.boxShadowSecondary), input: css(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n width: 100%;\n border: none;\n outline: none;\n border-radius: 8px;\n "]))), btn: css(_templateObject4 || (_templateObject4 = _taggedTemplateLiteral(["\n position: absolute;\n z-index: 10;\n right: 8px;\n bottom: 6px;\n\n color: ", ";\n &:hover {\n color: ", ";\n }\n "])), token.colorTextTertiary, token.colorTextSecondary), extra: css(_templateObject5 || (_templateObject5 = _taggedTemplateLiteral(["\n color: ", ";\n "])), token.colorTextTertiary) }; }); export var ChatInputArea = function ChatInputArea(props) { var _ref2 = props || {}, className = _ref2.className, onSend = _ref2.onSend, inputAreaRender = _ref2.inputAreaRender, inputRender = _ref2.inputRender, sendButtonRender = _ref2.sendButtonRender; var _useStore = useStore(function (s) { return [s.sendMessage, !!s.chatLoadingId, s.placeholder, s.inputAreaProps, s.clearMessage, s.stopGenerateMessage]; }), _useStore2 = _slicedToArray(_useStore, 6), sendMessage = _useStore2[0], isLoading = _useStore2[1], placeholder = _useStore2[2], inputAreaProps = _useStore2[3], clearMessage = _useStore2[4], stopGenerateMessage = _useStore2[5]; var _useContext = useContext(ConfigProvider.ConfigContext), getPrefixCls = _useContext.getPrefixCls; var isChineseInput = useRef(false); var _useStyles = useStyles(), styles = _useStyles.styles, theme = _useStyles.theme; var _useProChatLocale = useProChatLocale(), localeObject = _useProChatLocale.localeObject; var _ref3 = inputAreaProps || {}, value = _ref3.value, onChange = _ref3.onChange; var _useState = useState(''), _useState2 = _slicedToArray(_useState, 2), message = _useState2[0], setMessage = _useState2[1]; // 兼容中文的受控输入逻辑 useEffect(function () { if (!isChineseInput.current && onChange) { onChange(message); } }, [message]); useEffect(function () { if (value) { setMessage(value); } }, [value]); var send = /*#__PURE__*/function () { var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() { var success; return _regeneratorRuntime().wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: if (!onSend) { _context.next = 7; break; } _context.next = 3; return onSend(message); case 3: success = _context.sent; if (success) { sendMessage(message); setMessage(''); } _context.next = 9; break; case 7: sendMessage(message); setMessage(''); case 9: case "end": return _context.stop(); } }, _callee); })); return function send() { return _ref4.apply(this, arguments); }; }(); var prefixClass = getPrefixCls('pro-chat-input-area'); /** * 默认的自动完成文本区域属性 * * @property {string} placeholder - 输入框的占位符 * @property {Object} inputAreaProps - 输入框的其他属性 * @property {string} inputAreaProps.className - 输入框的类名 * @property {string} prefixClass - 输入框的前缀类名 * @property {string} value - 输入框的值 * @property {function} onChange - 输入框值改变时的回调函数 * @property {Object} autoSize - 输入框的自动调整大小配置 * @property {number} autoSize.maxRows - 输入框的最大行数 * @property {function} onCompositionStart - 输入法开始输入时的回调函数 * @property {function} onCompositionEnd - 输入法结束输入时的回调函数 * @property {function} onPressEnter - 按下回车键时的回调函数 */ var defaultAutoCompleteTextAreaProps = _objectSpread(_objectSpread({ placeholder: placeholder || localeObject.placeholder }, inputAreaProps), {}, { className: cx(styles.input, inputAreaProps === null || inputAreaProps === void 0 ? void 0 : inputAreaProps.className, "".concat(prefixClass, "-component")), value: message, onChange: function onChange(e) { setMessage(e.target.value); }, autoSize: { maxRows: 8 }, onCompositionStart: function onCompositionStart() { isChineseInput.current = true; }, onCompositionEnd: function onCompositionEnd(e) { isChineseInput.current = false; setMessage(e.target.value); }, onPressEnter: function onPressEnter(e) { if (!isLoading && !e.shiftKey && !isChineseInput.current) { e.preventDefault(); send(); } } }); var defaultInput = /*#__PURE__*/_jsx(AutoCompleteTextArea, _objectSpread({}, defaultAutoCompleteTextAreaProps)); /** * 支持下自定义输入框 */ var inputDom = inputRender ? inputRender === null || inputRender === void 0 ? void 0 : inputRender(defaultInput, function (message) { sendMessage(message); }, defaultAutoCompleteTextAreaProps) : defaultInput; /** * 根据 isLoading 状态返回默认的按钮道具。 * 如果 isLoading 为 true,则按钮将具有文本类型,即 stopGenerateMessage 点击处理程序, * 和 StopLoadingIcon 作为图标。 * 如果 isLoading 为 false,则按钮将具有文本类型、发送点击处理程序、 * 和 SendOutlined 图标作为图标。 * @returns The default button props. */ var defaultButtonProps = useMemo(function () { return isLoading ? { type: 'text', className: styles.btn, onClick: function onClick() { return stopGenerateMessage(); }, icon: /*#__PURE__*/_jsx(StopLoadingIcon, {}) } : { type: 'text', className: styles.btn, onClick: function onClick() { return send(); }, icon: /*#__PURE__*/_jsx(SendOutlined, {}) }; }, [isLoading, message]); var defaultButtonDom = /*#__PURE__*/_jsx(Button, _objectSpread({}, defaultButtonProps)); var buttonDom = sendButtonRender ? sendButtonRender(defaultButtonDom, defaultButtonProps) : defaultButtonDom; var defaultInputArea = /*#__PURE__*/_jsx(ConfigProvider, { theme: { token: { borderRadius: 4, colorBgContainer: theme.colorBgElevated, controlHeightLG: 48, colorBorder: 'transparent', colorPrimaryHover: 'transparent' } }, children: /*#__PURE__*/_jsxs(Flexbox, { gap: 8, padding: 16, className: cx(styles.container, "".concat(prefixClass), className), children: [/*#__PURE__*/_jsx(ActionBar, { className: "".concat(prefixClass, "-action-bar") }), /*#__PURE__*/_jsxs(Flexbox, { horizontal: true, gap: 8, align: 'center', className: cx(styles.boxShadow, "".concat(prefixClass, "-text-container")), children: [inputDom, buttonDom] })] }) }); if (inputAreaRender) { return inputAreaRender(defaultInputArea, function (message) { sendMessage(message); }, clearMessage); } return defaultInputArea; }; export default ChatInputArea;