Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

MessageContainer.js 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // @flow
  2. import React from 'react';
  3. import { scrollIntoView } from 'seamless-scroll-polyfill';
  4. import { MESSAGE_TYPE_REMOTE } from '../../constants';
  5. import AbstractMessageContainer, { type Props }
  6. from '../AbstractMessageContainer';
  7. import ChatMessageGroup from './ChatMessageGroup';
  8. /**
  9. * Displays all received chat messages, grouped by sender.
  10. *
  11. * @augments AbstractMessageContainer
  12. */
  13. export default class MessageContainer extends AbstractMessageContainer<Props> {
  14. /**
  15. * Whether or not chat has been scrolled to the bottom of the screen. Used
  16. * to determine if chat should be scrolled automatically to the bottom when
  17. * the {@code ChatInput} resizes.
  18. */
  19. _isScrolledToBottom: boolean;
  20. /**
  21. * Reference to the HTML element at the end of the list of displayed chat
  22. * messages. Used for scrolling to the end of the chat messages.
  23. */
  24. _messagesListEndRef: Object;
  25. /**
  26. * A React ref to the HTML element containing all {@code ChatMessageGroup}
  27. * instances.
  28. */
  29. _messageListRef: Object;
  30. /**
  31. * Initializes a new {@code MessageContainer} instance.
  32. *
  33. * @param {Props} props - The React {@code Component} props to initialize
  34. * the new {@code MessageContainer} instance with.
  35. */
  36. constructor(props: Props) {
  37. super(props);
  38. this._isScrolledToBottom = true;
  39. this._messageListRef = React.createRef();
  40. this._messagesListEndRef = React.createRef();
  41. this._onChatScroll = this._onChatScroll.bind(this);
  42. }
  43. /**
  44. * Implements {@code Component#render}.
  45. *
  46. * @inheritdoc
  47. */
  48. render() {
  49. const groupedMessages = this._getMessagesGroupedBySender();
  50. const messages = groupedMessages.map((group, index) => {
  51. const messageType = group[0] && group[0].messageType;
  52. return (
  53. <ChatMessageGroup
  54. className = { messageType || MESSAGE_TYPE_REMOTE }
  55. key = { index }
  56. messages = { group } />
  57. );
  58. });
  59. return (
  60. <div
  61. aria-labelledby = 'chat-header'
  62. id = 'chatconversation'
  63. onScroll = { this._onChatScroll }
  64. ref = { this._messageListRef }
  65. role = 'log'
  66. tabIndex = { 0 }>
  67. { messages }
  68. <div ref = { this._messagesListEndRef } />
  69. </div>
  70. );
  71. }
  72. /**
  73. * Scrolls to the bottom again if the instance had previously been scrolled
  74. * to the bottom. This method is used when a resize has occurred below the
  75. * instance and bottom scroll needs to be maintained.
  76. *
  77. * @returns {void}
  78. */
  79. maybeUpdateBottomScroll() {
  80. if (this._isScrolledToBottom) {
  81. this.scrollToBottom(false);
  82. }
  83. }
  84. /**
  85. * Automatically scrolls the displayed chat messages down to the latest.
  86. *
  87. * @param {boolean} withAnimation - Whether or not to show a scrolling
  88. * animation.
  89. * @returns {void}
  90. */
  91. scrollToBottom(withAnimation: boolean) {
  92. scrollIntoView(this._messagesListEndRef.current, {
  93. behavior: withAnimation ? 'smooth' : 'auto',
  94. block: 'nearest'
  95. });
  96. }
  97. _getMessagesGroupedBySender: () => Array<Array<Object>>;
  98. _onChatScroll: () => void;
  99. /**
  100. * Callback invoked to listen to the current scroll location.
  101. *
  102. * @private
  103. * @returns {void}
  104. */
  105. _onChatScroll() {
  106. const element = this._messageListRef.current;
  107. this._isScrolledToBottom
  108. = element.scrollHeight - element.scrollTop === element.clientHeight;
  109. }
  110. }