index.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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. markdownRenderProps
  24. } = props;
  25. const { renderChatBoxAvatar, renderChatBoxAction,
  26. renderChatBoxContent, renderChatBoxTitle,
  27. renderFullChatBox
  28. } = chatBoxRenderConfig;
  29. const continueSend = useMemo(() => {
  30. return message?.role === previousMessage?.role;
  31. }, [message.role, previousMessage]);
  32. const info = useMemo(() => {
  33. let info = {};
  34. if (roleConfig) {
  35. info = roleConfig[message.role] ?? {};
  36. }
  37. return info;
  38. }, [message.role, roleConfig]);
  39. const avatarNode = useMemo(() => {
  40. return (<ChatBoxAvatar
  41. continueSend={continueSend}
  42. role={info}
  43. message={message}
  44. customRenderFunc={renderChatBoxAvatar}
  45. />);
  46. }, [info, message, renderChatBoxAvatar]);
  47. const titleNode = useMemo(() => {
  48. return (<ChatBoxTitle
  49. role={info}
  50. message={message}
  51. customRenderFunc={renderChatBoxTitle}
  52. />);
  53. }, [info, message, renderChatBoxTitle]);
  54. const contentNode = useMemo(() => {
  55. return (<ChatBoxContent
  56. mode={mode}
  57. role={info}
  58. message={message}
  59. customMarkDownComponents={customMarkDownComponents}
  60. customRenderFunc={renderChatBoxContent}
  61. markdownRenderProps={markdownRenderProps}
  62. />);
  63. }, [message, info, renderChatBoxContent, mode]);
  64. const actionNode = useMemo(() => {
  65. return (<ChatBoxAction
  66. toast={toast}
  67. role={info}
  68. message={message}
  69. lastChat={lastChat}
  70. onMessageBadFeedback={onMessageBadFeedback}
  71. onMessageCopy={onMessageCopy}
  72. onChatsChange={onChatsChange}
  73. onMessageDelete={onMessageDelete}
  74. onMessageGoodFeedback={onMessageGoodFeedback}
  75. onMessageReset={onMessageReset}
  76. customRenderFunc={renderChatBoxAction}
  77. />);
  78. }, [message, info, lastChat, onMessageBadFeedback, onMessageGoodFeedback, onMessageCopy, onChatsChange, onMessageDelete, onMessageReset, renderChatBoxAction]);
  79. const containerCls = useMemo(() => cls(PREFIX_CHAT_BOX, {
  80. [`${PREFIX_CHAT_BOX}-right`]: message.role === ROLE.USER && align === CHAT_ALIGN.LEFT_RIGHT,
  81. }
  82. ), [message.role, align]);
  83. if (typeof renderFullChatBox !== 'function') {
  84. return (<div
  85. className={containerCls}
  86. >
  87. {avatarNode}
  88. <div
  89. className={`${PREFIX_CHAT_BOX}-wrap`}
  90. >
  91. {!continueSend && titleNode}
  92. {contentNode}
  93. {actionNode}
  94. </div>
  95. </div>);
  96. } else {
  97. return renderFullChatBox({
  98. message,
  99. role: info,
  100. defaultNodes: {
  101. avatar: avatarNode,
  102. title: titleNode,
  103. content: contentNode,
  104. action: actionNode,
  105. },
  106. className: containerCls
  107. }) as ReactElement;
  108. }
  109. });
  110. export default ChatBox;