UNPKG

@douyinfe/semi-ui

Version:

A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.

422 lines (421 loc) 15.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _exportNames = {}; exports.default = void 0; var React = _interopRequireWildcard(require("react")); var _baseComponent = _interopRequireDefault(require("../_base/baseComponent")); var _propTypes = _interopRequireDefault(require("prop-types")); var _classnames = _interopRequireDefault(require("classnames")); require("@douyinfe/semi-foundation/lib/cjs/aiChatDialogue/aiChatDialogue.css"); var _reasoning = require("./widgets/contentItem/reasoning"); var _dialogueStep = require("./widgets/contentItem/dialogueStep"); var _annotation = require("./widgets/contentItem/annotation"); var _code = _interopRequireDefault(require("./widgets/contentItem/code")); var _Dialogue = _interopRequireDefault(require("./Dialogue")); var _foundation = _interopRequireWildcard(require("@douyinfe/semi-foundation/lib/cjs/aiChatDialogue/foundation")); Object.keys(_foundation).forEach(function (key) { if (key === "default" || key === "__esModule") return; if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return; if (key in exports && exports[key] === _foundation[key]) return; Object.defineProperty(exports, key, { enumerable: true, get: function () { return _foundation[key]; } }); }); var _utils = require("../_utils"); var _constants = require("@douyinfe/semi-foundation/lib/cjs/aiChatDialogue/constants"); var _dialogueHint = _interopRequireDefault(require("./widgets/dialogueHint")); var _index = require("../index"); var _semiIcons = require("@douyinfe/semi-icons"); var _interface = require("./interface"); Object.keys(_interface).forEach(function (key) { if (key === "default" || key === "__esModule") return; if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return; if (key in exports && exports[key] === _interface[key]) return; Object.defineProperty(exports, key, { enumerable: true, get: function () { return _interface[key]; } }); }); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } var __rest = void 0 && (void 0).__rest || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; const { DIALOGUE_ALIGN, MODE } = _constants.strings; const { PREFIX } = _constants.cssClasses; class AIChatDialogue extends _baseComponent.default { constructor(props) { super(props); this.selectAll = () => { this.foundation.handleSelectAll(); }; this.deselectAll = () => { this.foundation.handleDeselectAll(); }; this.scrollToBottom = animation => { if (animation) { this.foundation.scrollToBottomWithAnimation(); } else { this.foundation.scrollToBottomImmediately(); } }; this.scrollToTop = animation => { if (animation) { this.foundation.scrollToTopWithAnimation(); } else { this.foundation.scrollToTopImmediately(); } }; this.containerScroll = e => { this.scrollTargetRef.current = e.target; if (e.target !== e.currentTarget) { return; } this.foundation.containerScroll(e); }; this.foundation = new _foundation.default(this.adapter); this.containerRef = /*#__PURE__*/React.createRef(); this.scrollTargetRef = /*#__PURE__*/React.createRef(); this.wheelEventHandler = null; this.state = { cacheHints: [], selectedIds: new Set(), chats: [], backBottomVisible: false, wheelScroll: false }; this.onSelectOrRemove = this.onSelectOrRemove.bind(this); } get adapter() { return Object.assign(Object.assign({}, super.adapter), { getContainerRef: () => { var _a; return (_a = this.containerRef) === null || _a === void 0 ? void 0 : _a.current; }, setWheelScroll: flag => { this.setState({ wheelScroll: flag }); }, updateSelected: selectedIds => { this.setState({ selectedIds }); }, notifySelect: selectedIds => { const { onSelect } = this.props; onSelect && onSelect(selectedIds); }, notifyChatsChange: chats => { const { onChatsChange } = this.props; onChatsChange && onChatsChange(chats); }, notifyCopyMessage: message => { const { onMessageCopy } = this.props; onMessageCopy && onMessageCopy(message); }, notifyLikeMessage: message => { const { onMessageGoodFeedback } = this.props; onMessageGoodFeedback && onMessageGoodFeedback(message); }, notifyDislikeMessage: message => { const { onMessageBadFeedback } = this.props; onMessageBadFeedback && onMessageBadFeedback(message); }, notifyEditMessage: message => { const { onMessageEdit } = this.props; onMessageEdit && onMessageEdit(message); }, notifyHintClick: hint => { const { onHintClick } = this.props; onHintClick && onHintClick(hint); }, setBackBottomVisible: visible => { this.setState(state => { if (state.backBottomVisible !== visible) { return { backBottomVisible: visible }; } return null; }); }, registerWheelEvent: () => { this.adapter.unRegisterWheelEvent(); const containerElement = this.containerRef.current; if (!containerElement) { return; } this.wheelEventHandler = e => { var _a; /** * Why use this.scrollTargetRef.current and wheel's currentTarget target comparison? * Both scroll and wheel events are on the container * his.scrollTargetRef.current is the object where scrolling actually occurs * wheel's currentTarget is the container, * Only when the wheel event occurs and there is scroll, the following logic(show scroll bar) needs to be executed */ if (((_a = this.scrollTargetRef) === null || _a === void 0 ? void 0 : _a.current) !== e.currentTarget) { return; } this.adapter.setWheelScroll(true); this.adapter.unRegisterWheelEvent(); }; containerElement.addEventListener('wheel', this.wheelEventHandler); }, unRegisterWheelEvent: () => { if (this.wheelEventHandler) { const containerElement = this.containerRef.current; if (!containerElement) { return; } else { containerElement.removeEventListener('wheel', this.wheelEventHandler); } this.wheelEventHandler = null; } } }); } static getDerivedStateFromProps(nextProps, prevState) { const { chats, hints } = nextProps; const newState = {}; if (chats !== prevState.chats) { newState.chats = chats !== null && chats !== void 0 ? chats : []; } if (hints !== prevState.cacheHints) { newState.cacheHints = hints; } if (Object.keys(newState).length) { return newState; } return null; } componentDidMount() { this.foundation.init(); } componentDidUpdate(prevProps, prevState, snapshot) { const { chats: newChats, hints: newHints } = this.props; const { chats: oldChats, cacheHints } = prevState; const { wheelScroll } = this.state; let shouldScroll = false; if (newChats.length > oldChats.length) { this.adapter.setWheelScroll(false); this.adapter.registerWheelEvent(); this.foundation.scrollToBottomImmediately(); } if (newChats !== oldChats) { this.foundation.handleChatsChange(newChats); if (Array.isArray(newChats) && Array.isArray(oldChats)) { const newLastChat = newChats[newChats.length - 1]; const oldLastChat = oldChats[oldChats.length - 1]; if (newChats.length > oldChats.length) { if (oldChats.length === 0 || newLastChat.id !== oldLastChat.id) { shouldScroll = true; } } else if (newChats.length === oldChats.length && newChats.length && (newLastChat.status !== 'completed' || newLastChat.status !== oldLastChat.status)) { shouldScroll = true; } } } if (newHints !== cacheHints) { if (newHints.length > cacheHints.length) { shouldScroll = true; } } if (!wheelScroll && shouldScroll) { this.foundation.scrollToBottomImmediately(); } } componentWillUnmount() { this.foundation.destroy(); } onSelectOrRemove(isChecked, item) { this.foundation.handleSelectOrRemove(isChecked, item); } render() { const _a = this.props, { roleConfig, onMessageBadFeedback, onMessageGoodFeedback, onMessageReset, onMessageEdit, onMessageDelete, onHintClick, selecting, hintCls, hintStyle, hints, renderHintBox, style, className } = _a, restProps = __rest(_a, ["roleConfig", "onMessageBadFeedback", "onMessageGoodFeedback", "onMessageReset", "onMessageEdit", "onMessageDelete", "onHintClick", "selecting", "hintCls", "hintStyle", "hints", "renderHintBox", "style", "className"]); const { selectedIds, chats, backBottomVisible, wheelScroll } = this.state; return /*#__PURE__*/React.createElement("div", { className: (0, _classnames.default)(`${PREFIX}`, className), style: style }, /*#__PURE__*/React.createElement("div", { className: (0, _classnames.default)(`${PREFIX}-list`, { [`${PREFIX}-list-scroll-hidden`]: !wheelScroll }), onScroll: this.containerScroll, ref: this.containerRef }, chats.map((chat, index) => { var _a; const isLastChat = index === chats.length - 1; const continueSend = index > 0 && (chat === null || chat === void 0 ? void 0 : chat.role) === ((_a = chats[index - 1]) === null || _a === void 0 ? void 0 : _a.role); return /*#__PURE__*/React.createElement(_Dialogue.default, Object.assign({ key: chat.id, message: chat, role: roleConfig[chat.role], onSelectChange: this.onSelectOrRemove, isSelected: selectedIds.has(chat.id), roleConfig: roleConfig, onMessageBadFeedback: this.foundation.dislikeMessage, onMessageGoodFeedback: this.foundation.likeMessage, onMessageReset: this.foundation.resetMessage, onMessageEdit: this.foundation.editMessage, onMessageDelete: this.foundation.deleteMessage, isLastChat: isLastChat, // todo: 不太确定用户的需求场景,暂时设置成 false,如果用户有相关需求,转为一个对外提供的 api // todo: Not sure about the user's demand scenario, temporarily set it to false. // If the user has relevant needs, turn it into an external API continueSend: false, selecting: selecting }, restProps)); }), !!(hints === null || hints === void 0 ? void 0 : hints.length) && /*#__PURE__*/React.createElement(_dialogueHint.default, { className: hintCls, style: hintStyle, hints: hints, onHintClick: this.foundation.onHintClick, renderHintBox: renderHintBox, selecting: selecting })), backBottomVisible && (/*#__PURE__*/React.createElement("span", { className: `${PREFIX}-backBottom` }, /*#__PURE__*/React.createElement(_index.Button, { className: `${PREFIX}-backBottom-button`, icon: /*#__PURE__*/React.createElement(_semiIcons.IconChevronDown, { size: "extra-large" }), type: "tertiary", onClick: this.foundation.scrollToBottomWithAnimation })))); } } AIChatDialogue.__SemiComponentName__ = "AIChatDialogue"; AIChatDialogue.Reasoning = _reasoning.ReasoningWidget; AIChatDialogue.Step = _dialogueStep.DialogueStepWidget; AIChatDialogue.Annotation = _annotation.AnnotationWidget; AIChatDialogue.defaultComponents = { code: _code.default }; AIChatDialogue.propTypes = { align: _propTypes.default.oneOf(['leftRight', 'leftAlign']), chats: _propTypes.default.arrayOf(_propTypes.default.shape({ id: _propTypes.default.string.isRequired, content: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.array]), output_text: _propTypes.default.string, role: _propTypes.default.string.isRequired, name: _propTypes.default.string, createdAt: _propTypes.default.number, updatedAt: _propTypes.default.number, model: _propTypes.default.string, status: _propTypes.default.string })), className: _propTypes.default.string, disabledFileItemClick: _propTypes.default.bool, hints: _propTypes.default.arrayOf(_propTypes.default.string), hintCls: _propTypes.default.string, hintStyle: _propTypes.default.object, selecting: _propTypes.default.bool, markdownRenderProps: _propTypes.default.object, messageEditRender: _propTypes.default.func, mode: _propTypes.default.oneOf(['bubble', 'noBubble', 'userBubble']), roleConfig: _propTypes.default.object, style: _propTypes.default.object, dialogueRenderConfig: _propTypes.default.shape({ renderDialogueAction: _propTypes.default.func, renderDialogueAvatar: _propTypes.default.func, renderDialogueContent: _propTypes.default.func, renderDialogueTitle: _propTypes.default.func, renderFullDialogue: _propTypes.default.func }), renderHintBox: _propTypes.default.func, renderDialogueContentItem: _propTypes.default.object, onAnnotationClick: _propTypes.default.func, onChatsChange: _propTypes.default.func, onFileClick: _propTypes.default.func, onImageClick: _propTypes.default.func, onHintClick: _propTypes.default.func, onMessageBadFeedback: _propTypes.default.func, onMessageCopy: _propTypes.default.func, onMessageDelete: _propTypes.default.func, onMessageEdit: _propTypes.default.func, onMessageGoodFeedback: _propTypes.default.func, onMessageReset: _propTypes.default.func, onMessageShare: _propTypes.default.func, onReferenceClick: _propTypes.default.func, onSelect: _propTypes.default.func, showReset: _propTypes.default.bool, showReference: _propTypes.default.bool, escapeHtml: _propTypes.default.bool }; AIChatDialogue.defaultProps = (0, _utils.getDefaultPropsFromGlobalConfig)(AIChatDialogue.__SemiComponentName__, { align: DIALOGUE_ALIGN.LEFT_RIGHT, mode: MODE.BUBBLE, selecting: false, disabledFileItemClick: false, showReset: true, showReference: false, escapeHtml: true }); var _default = exports.default = AIChatDialogue;