index.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import React, { useMemo, useEffect, ReactElement } from 'react';
  2. import cls from 'classnames';
  3. import type { ChatBoxProps } from '../interface';
  4. import ChatBoxAvatar from './chatBoxAvatar';
  5. import ChatBoxTitle from './chatBoxTitle';
  6. import ChatBoxContent from './chatBoxContent';
  7. import ChatBoxAction from './chatBoxAction';
  8. import { cssClasses, strings } from '@douyinfe/semi-foundation/chat/constants';
  9. const { PREFIX_CHAT_BOX } = cssClasses;
  10. const { ROLE, CHAT_ALIGN } = strings;
  11. const ChatBox = React.memo((props: ChatBoxProps) => {
  12. const { message, lastChat, align, toast, mode,
  13. roleConfig,
  14. onMessageBadFeedback,
  15. onMessageGoodFeedback,
  16. onMessageCopy,
  17. onChatsChange,
  18. onMessageDelete,
  19. onMessageReset,
  20. chatBoxRenderConfig = {},
  21. customMarkDownComponents,
  22. previousMessage,
  23. } = props;
  24. const { renderChatBoxAvatar, renderChatBoxAction,
  25. renderChatBoxContent, renderChatBoxTitle,
  26. renderFullChatBox
  27. } = chatBoxRenderConfig;
  28. const continueSend = useMemo(() => {
  29. return message?.role === previousMessage?.role;
  30. }, [message.role, previousMessage])
  31. const info = useMemo(() => {
  32. let info = {};
  33. if (roleConfig) {
  34. info = roleConfig[message.role] ?? {};
  35. }
  36. return info;
  37. }, [message.role, roleConfig]);
  38. const avatarNode = useMemo(() => {
  39. return (<ChatBoxAvatar
  40. continueSend={continueSend}
  41. role={info}
  42. customRenderFunc={renderChatBoxAvatar}
  43. />);
  44. }, [info, renderChatBoxAvatar]);
  45. const titleNode = useMemo(() => {
  46. return (<ChatBoxTitle
  47. role={info}
  48. message={message}
  49. customRenderFunc={renderChatBoxTitle}
  50. />);
  51. }, [info, message, renderChatBoxTitle]);
  52. const contentNode = useMemo(() => {
  53. return (<ChatBoxContent
  54. mode={mode}
  55. role={info}
  56. message={message}
  57. customMarkDownComponents={customMarkDownComponents}
  58. customRenderFunc={renderChatBoxContent}
  59. />);
  60. }, [message, info, renderChatBoxContent]);
  61. const actionNode = useMemo(() => {
  62. return (<ChatBoxAction
  63. toast={toast}
  64. role={info}
  65. message={message}
  66. lastChat={lastChat}
  67. onMessageBadFeedback={onMessageBadFeedback}
  68. onMessageCopy={onMessageCopy}
  69. onChatsChange={onChatsChange}
  70. onMessageDelete={onMessageDelete}
  71. onMessageGoodFeedback={onMessageGoodFeedback}
  72. onMessageReset={onMessageReset}
  73. customRenderFunc={renderChatBoxAction}
  74. />);
  75. }, [message, info, lastChat, onMessageBadFeedback, onMessageGoodFeedback, onMessageCopy, onChatsChange, onMessageDelete, onMessageReset, renderChatBoxAction]);
  76. const containerCls = useMemo(() => cls(PREFIX_CHAT_BOX, {
  77. [`${PREFIX_CHAT_BOX}-right`]: message.role === ROLE.USER && align === CHAT_ALIGN.LEFT_RIGHT,
  78. }
  79. ), [message.role, align]);
  80. if (typeof renderFullChatBox !== 'function') {
  81. return (<div
  82. className={containerCls}
  83. >
  84. {avatarNode}
  85. <div
  86. className={`${PREFIX_CHAT_BOX}-wrap`}
  87. >
  88. {!continueSend && titleNode}
  89. {contentNode}
  90. {actionNode}
  91. </div>
  92. </div>);
  93. } else {
  94. return renderFullChatBox({
  95. message,
  96. role: info,
  97. defaultNodes: {
  98. avatar: avatarNode,
  99. title: titleNode,
  100. content: contentNode,
  101. action: actionNode,
  102. },
  103. className: containerCls
  104. }) as ReactElement;
  105. }
  106. });
  107. export default ChatBox;