From 40efd8367a85e3333e9b7cc45c390259d412088c Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Tue, 13 Jun 2017 14:35:45 -0400 Subject: PLT-6127/PLT-6135/PLT-6137 Added EmojiPickerOverlay component to better position emoji picker (#6352) * Cleaned up emoji picker CSS * Fixed border of emoji picker when reacting to comments in the RHS * PLT-6135 Made EmojiPicker automatically position itself above/below the [...] menu * PLT-6135 Changed post textbox emoji picker to use a RootCloseWrapper * PLT-6135 Changed comment textbox emoji picker to use a RootCloseWrapper * PLT-6135 Changed RHS post components to use EmojiPickerOverlay * Removed react-outside-event package * Fixed merge conflict * Fixed emoji picker position on posts in RHS * Removed unused CSS classes * Fixed not being able to react to posts with emoji picker --- webapp/components/create_comment.jsx | 60 +++++-------------- webapp/components/create_post.jsx | 44 +++++--------- webapp/components/emoji_picker/emoji_picker.jsx | 58 ++++++++----------- .../emoji_picker/emoji_picker_overlay.jsx | 62 ++++++++++++++++++++ webapp/components/post_view/components/post.jsx | 4 +- .../post_view/components/post_header.jsx | 4 +- .../components/post_view/components/post_info.jsx | 56 +++++++++--------- .../components/post_view/components/post_list.jsx | 5 ++ webapp/components/rhs_comment.jsx | 67 ++++++++-------------- webapp/components/rhs_root_post.jsx | 57 ++++++++---------- webapp/components/rhs_thread.jsx | 8 ++- 11 files changed, 213 insertions(+), 212 deletions(-) create mode 100644 webapp/components/emoji_picker/emoji_picker_overlay.jsx (limited to 'webapp/components') diff --git a/webapp/components/create_comment.jsx b/webapp/components/create_comment.jsx index 0389af0a2..e2ea84c46 100644 --- a/webapp/components/create_comment.jsx +++ b/webapp/components/create_comment.jsx @@ -24,6 +24,7 @@ import * as PostActions from 'actions/post_actions.jsx'; import Constants from 'utils/constants.jsx'; import {FormattedMessage} from 'react-intl'; +import {RootCloseWrapper} from 'react-overlays'; import {browserHistory} from 'react-router/es6'; const ActionTypes = Constants.ActionTypes; @@ -58,10 +59,7 @@ export default class CreateComment extends React.Component { this.showPostDeletedModal = this.showPostDeletedModal.bind(this); this.hidePostDeletedModal = this.hidePostDeletedModal.bind(this); this.handlePostError = this.handlePostError.bind(this); - this.handleEmojiPickerClick = this.handleEmojiPickerClick.bind(this); this.handleEmojiClick = this.handleEmojiClick.bind(this); - this.onKeyPress = this.onKeyPress.bind(this); - this.closeEmoji = this.closeEmoji.bind(this); PostStore.clearCommentDraftUploads(); MessageHistoryStore.resetHistoryIndex('comment'); @@ -77,38 +75,14 @@ export default class CreateComment extends React.Component { showPostDeletedModal: false, enableAddButton, showEmojiPicker: false, - emojiOffset: 0, emojiPickerEnabled: Utils.isFeatureEnabled(Constants.PRE_RELEASE_FEATURES.EMOJI_PICKER_PREVIEW) }; this.lastBlurAt = 0; } - closeEmoji(clickEvent) { - /* - if the user clicked something outside the component, except the RHS emojipicker icon - and the picker is open, then close it - */ - if (clickEvent && clickEvent.srcElement && - clickEvent.srcElement.className !== '' && - clickEvent.srcElement.className.indexOf('emoji-rhs') === -1 && - this.state.showEmojiPicker) { - this.setState({showEmojiPicker: !this.state.showEmojiPicker}); - } - } - - handleEmojiPickerClick() { - const threadHeight = document.getElementById('thread--root') ? document.getElementById('thread--root').offsetHeight : 0; - const messagesHeight = document.querySelector('div.post-right-comments-container') ? document.querySelector('div.post-right-comments-container').offsetHeight : 0; - - const totalHeight = threadHeight + messagesHeight; - let pickerOffset = 0; - if (totalHeight > 361) { - pickerOffset = -361; - } else { - pickerOffset = -1 * totalHeight; - } - this.setState({showEmojiPicker: !this.state.showEmojiPicker, emojiOffset: pickerOffset}); + toggleEmojiPicker = () => { + this.setState({showEmojiPicker: !this.state.showEmojiPicker}); } handleEmojiClick(emoji) { @@ -120,34 +94,28 @@ export default class CreateComment extends React.Component { } if (this.state.message === '') { - this.setState({message: ':' + emojiAlias + ': ', showEmojiPicker: false}); + this.setState({message: ':' + emojiAlias + ': '}); } else { //check whether there is already a blank at the end of the current message const newMessage = (/\s+$/.test(this.state.message)) ? this.state.message + ':' + emojiAlias + ': ' : this.state.message + ' :' + emojiAlias + ': '; - this.setState({message: newMessage, showEmojiPicker: false}); + this.setState({message: newMessage}); } + this.setState({showEmojiPicker: false}); + this.focusTextbox(); } componentDidMount() { PreferenceStore.addChangeListener(this.onPreferenceChange); - document.addEventListener('keydown', this.onKeyPress); this.focusTextbox(); } componentWillUnmount() { PreferenceStore.removeChangeListener(this.onPreferenceChange); - document.removeEventListener('keydown', this.onKeyPress); - } - - onKeyPress(e) { - if (e.which === Constants.KeyCodes.ESCAPE && this.state.showEmojiPicker === true) { - this.setState({showEmojiPicker: !this.state.showEmojiPicker}); - } } onPreferenceChange() { @@ -584,12 +552,12 @@ export default class CreateComment extends React.Component { let emojiPicker = null; if (this.state.showEmojiPicker) { emojiPicker = ( - + + + ); } @@ -625,7 +593,7 @@ export default class CreateComment extends React.Component { onUploadError={this.handleUploadError} postType='comment' channelId={this.props.channelId} - onEmojiClick={this.handleEmojiPickerClick} + onEmojiClick={this.toggleEmojiPicker} emojiEnabled={this.state.emojiPickerEnabled} navBarName='rhs' /> diff --git a/webapp/components/create_post.jsx b/webapp/components/create_post.jsx index 31c19bd5c..09741706c 100644 --- a/webapp/components/create_post.jsx +++ b/webapp/components/create_post.jsx @@ -28,6 +28,7 @@ import ConfirmModal from './confirm_modal.jsx'; import Constants from 'utils/constants.jsx'; import {FormattedHTMLMessage, FormattedMessage} from 'react-intl'; +import {RootCloseWrapper} from 'react-overlays'; import {browserHistory} from 'react-router/es6'; const Preferences = Constants.Preferences; @@ -67,9 +68,7 @@ export default class CreatePost extends React.Component { this.hidePostDeletedModal = this.hidePostDeletedModal.bind(this); this.showShortcuts = this.showShortcuts.bind(this); this.handleEmojiClick = this.handleEmojiClick.bind(this); - this.handleEmojiPickerClick = this.handleEmojiPickerClick.bind(this); this.handlePostError = this.handlePostError.bind(this); - this.closeEmoji = this.closeEmoji.bind(this); this.hideNotifyAllModal = this.hideNotifyAllModal.bind(this); this.showNotifyAllModal = this.showNotifyAllModal.bind(this); this.handleNotifyModalCancel = this.handleNotifyModalCancel.bind(this); @@ -107,16 +106,8 @@ export default class CreatePost extends React.Component { this.setState({postError}); } - closeEmoji(clickEvent) { - /* - if the user clicked something outside the component, except the main emojipicker icon - and the picker is open, then close it - */ - if (clickEvent && clickEvent.srcElement && - clickEvent.srcElement.className.indexOf('emoji-main') === -1 && - this.state.showEmojiPicker) { - this.setState({showEmojiPicker: !this.state.showEmojiPicker}); - } + toggleEmojiPicker = () => { + this.setState({showEmojiPicker: !this.state.showEmojiPicker}); } doSubmit(e) { @@ -446,10 +437,6 @@ export default class CreatePost extends React.Component { } showShortcuts(e) { - if (e.which === Constants.KeyCodes.ESCAPE && this.state.showEmojiPicker === true) { - this.setState({showEmojiPicker: !this.state.showEmojiPicker}); - } - if ((e.ctrlKey || e.metaKey) && e.keyCode === Constants.KeyCodes.FORWARD_SLASH) { e.preventDefault(); const args = {}; @@ -580,20 +567,18 @@ export default class CreatePost extends React.Component { } if (this.state.message === '') { - this.setState({message: ':' + emojiAlias + ': ', showEmojiPicker: false}); + this.setState({message: ':' + emojiAlias + ': '}); } else { //check whether there is already a blank at the end of the current message const newMessage = (/\s+$/.test(this.state.message)) ? this.state.message + ':' + emojiAlias + ': ' : this.state.message + ' :' + emojiAlias + ': '; - this.setState({message: newMessage, showEmojiPicker: false}); + this.setState({message: newMessage}); } - this.focusTextbox(); - } + this.setState({showEmojiPicker: false}); - handleEmojiPickerClick() { - this.setState({showEmojiPicker: !this.state.showEmojiPicker}); + this.focusTextbox(); } createTutorialTip() { @@ -692,15 +677,16 @@ export default class CreatePost extends React.Component { if (!this.state.enableSendButton) { sendButtonClass += ' disabled'; } + let emojiPicker = null; if (this.state.showEmojiPicker) { emojiPicker = ( - + + + ); } @@ -743,7 +729,7 @@ export default class CreatePost extends React.Component { onUploadError={this.handleUploadError} postType='post' channelId='' - onEmojiClick={this.handleEmojiPickerClick} + onEmojiClick={this.toggleEmojiPicker} emojiEnabled={this.state.emojiPickerEnabled} navBarName='main' /> diff --git a/webapp/components/emoji_picker/emoji_picker.jsx b/webapp/components/emoji_picker/emoji_picker.jsx index e9cddce34..cbb388a10 100644 --- a/webapp/components/emoji_picker/emoji_picker.jsx +++ b/webapp/components/emoji_picker/emoji_picker.jsx @@ -1,15 +1,13 @@ -import PropTypes from 'prop-types'; - // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. // See License.txt for license information. import React from 'react'; +import PropTypes from 'prop-types'; import * as Emoji from 'utils/emoji.jsx'; import EmojiStore from 'stores/emoji_store.jsx'; import PureRenderMixin from 'react-addons-pure-render-mixin'; import * as Utils from 'utils/utils.jsx'; -import ReactOutsideEvent from 'react-outside-event'; import {FormattedMessage} from 'react-intl'; import EmojiPickerCategory from './components/emoji_picker_category.jsx'; @@ -30,13 +28,12 @@ const CATEGORIES = [ 'custom' ]; -class EmojiPicker extends React.Component { +export default class EmojiPicker extends React.Component { static propTypes = { + style: PropTypes.object, + placement: PropTypes.oneOf(['top', 'bottom', 'left']), customEmojis: PropTypes.object, - onEmojiClick: PropTypes.func.isRequired, - pickerLocation: PropTypes.string.isRequired, - emojiOffset: PropTypes.number, - outsideClick: PropTypes.func + onEmojiClick: PropTypes.func.isRequired } constructor(props) { @@ -53,7 +50,6 @@ class EmojiPicker extends React.Component { this.handleScroll = this.handleScroll.bind(this); this.handleItemUnmount = this.handleItemUnmount.bind(this); this.renderCategory = this.renderCategory.bind(this); - this.onOutsideEvent = this.onOutsideEvent.bind(this); this.state = { category: 'recent', @@ -63,14 +59,11 @@ class EmojiPicker extends React.Component { } componentDidMount() { - this.searchInput.focus(); - } - - onOutsideEvent = (event) => { - // Handle the event. - if (this.props.outsideClick) { - this.props.outsideClick(event); - } + // Delay taking focus because this briefly renders offscreen when using an Overlay + // so focusing it immediately on mount can cause weird scrolling + requestAnimationFrame(() => { + this.searchInput.focus(); + }); } handleCategoryClick(category) { @@ -99,7 +92,7 @@ class EmojiPicker extends React.Component { } handleItemUnmount(emoji) { - //Prevent emoji preview from showing emoji which is not present anymore (due to filter) + // Prevent emoji preview from showing emoji which is not present anymore (due to filter) if (this.state.selected === emoji) { this.setState({selected: null}); } @@ -292,22 +285,25 @@ class EmojiPicker extends React.Component { items.push(this.renderCategory(category, this.state.filter)); } } - let cssclass = 'emoji-picker '; - if (this.props.pickerLocation === 'top') { - cssclass += 'emoji-picker-top'; - } else if (this.props.pickerLocation === 'bottom') { - cssclass += 'emoji-picker-bottom'; - } else if (this.props.pickerLocation === 'react') { - cssclass = 'emoji-picker-react'; - } else if (this.props.pickerLocation === 'react-rhs-comment') { - cssclass = 'emoji-picker-react-rhs-comment'; + + let pickerStyle; + if (this.props.style && !(this.props.style.left === 0 || this.props.style.top === 0)) { + if (this.props.placement === 'top' || this.props.placement === 'bottom') { + // Only take the top/bottom position passed by React Bootstrap since we want to be right-aligned + pickerStyle = { + top: this.props.style.top, + bottom: this.props.style.bottom, + right: 1 + }; + } else { + pickerStyle = this.props.style; + } } - const pickerStyle = this.props.emojiOffset ? {top: this.props.emojiOffset} : {}; return (
spaceRequiredAbove) { + placement = 'top'; + } else if (window.innerHeight - targetBounds.bottom > spaceRequiredBelow) { + placement = 'bottom'; + } else { + placement = 'left'; + } + + this.setState({placement}); + } + } + + render() { + return ( + + + + ); + } +} diff --git a/webapp/components/post_view/components/post.jsx b/webapp/components/post_view/components/post.jsx index c1b932774..b9823396d 100644 --- a/webapp/components/post_view/components/post.jsx +++ b/webapp/components/post_view/components/post.jsx @@ -38,7 +38,8 @@ export default class Post extends Component { isFlagged: PropTypes.bool, status: PropTypes.string, isBusy: PropTypes.bool, - childComponentDidUpdateFunction: PropTypes.func + childComponentDidUpdateFunction: PropTypes.func, + getPostList: PropTypes.func.isRequired }; constructor(props) { @@ -308,6 +309,7 @@ export default class Post extends Component { isFlagged={this.props.isFlagged} status={this.props.status} isBusy={this.props.isBusy} + getPostList={this.props.getPostList} />
@@ -119,5 +120,6 @@ PostHeader.propTypes = { useMilitaryTime: PropTypes.bool.isRequired, isFlagged: PropTypes.bool.isRequired, status: PropTypes.string, - isBusy: PropTypes.bool + isBusy: PropTypes.bool, + getPostList: PropTypes.func.isRequired }; diff --git a/webapp/components/post_view/components/post_info.jsx b/webapp/components/post_view/components/post_info.jsx index 39a0b1fec..45c716ad0 100644 --- a/webapp/components/post_view/components/post_info.jsx +++ b/webapp/components/post_view/components/post_info.jsx @@ -2,7 +2,6 @@ // See License.txt for license information. import $ from 'jquery'; -import ReactDOM from 'react-dom'; import PostTime from './post_time.jsx'; import PostFlagIcon from 'components/common/post_flag_icon.jsx'; @@ -15,8 +14,7 @@ import * as Utils from 'utils/utils.jsx'; import * as PostUtils from 'utils/post_utils.jsx'; import Constants from 'utils/constants.jsx'; import DelayedAction from 'utils/delayed_action.jsx'; -import {Overlay} from 'react-bootstrap'; -import EmojiPicker from 'components/emoji_picker/emoji_picker.jsx'; +import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx'; import ChannelStore from 'stores/channel_store.jsx'; import PropTypes from 'prop-types'; @@ -36,7 +34,6 @@ export default class PostInfo extends React.Component { this.pinPost = this.pinPost.bind(this); this.unpinPost = this.unpinPost.bind(this); this.reactEmojiClick = this.reactEmojiClick.bind(this); - this.emojiPickerClick = this.emojiPickerClick.bind(this); this.canEdit = false; this.canDelete = false; @@ -280,8 +277,16 @@ export default class PostInfo extends React.Component { GlobalActions.showGetPostLinkModal(this.props.post); } - emojiPickerClick() { - this.setState({showEmojiPicker: !this.state.showEmojiPicker}); + toggleEmojiPicker = () => { + const showEmojiPicker = !this.state.showEmojiPicker; + + this.setState({showEmojiPicker}); + this.props.handleDropdownOpened(showEmojiPicker); + } + + hideEmojiPicker = () => { + this.setState({showEmojiPicker: false}); + this.props.handleDropdownOpened(false); } removePost() { @@ -328,6 +333,10 @@ export default class PostInfo extends React.Component { PostActions.addReaction(this.props.post.channel_id, this.props.post.id, emojiName); } + getDotMenu = () => { + return this.refs.dotMenu; + } + render() { var post = this.props.post; @@ -359,30 +368,21 @@ export default class PostInfo extends React.Component { if (Utils.isFeatureEnabled(Constants.PRE_RELEASE_FEATURES.EMOJI_PICKER_PREVIEW)) { react = ( - this.setState({showEmojiPicker: false})} - target={() => ReactDOM.findDOMNode(this.refs['reactIcon_' + post.id])} - animation={false} - > - - + container={this.props.getPostList} + target={this.getDotMenu} + onHide={this.hideEmojiPicker} + onEmojiClick={this.reactEmojiClick} + /> + onClick={this.toggleEmojiPicker} + > + - ); } } @@ -399,7 +399,10 @@ export default class PostInfo extends React.Component { if (dropdown) { options = ( -
+
); @@ -562,6 +563,10 @@ export default class PostList extends React.Component { this.checkAndUpdateScrolling(); } + getPostList = () => { + return this.refs.postlist; + } + render() { // Create intro message or top loadmore link let moreMessagesTop; diff --git a/webapp/components/rhs_comment.jsx b/webapp/components/rhs_comment.jsx index b7e82d903..20734c4f4 100644 --- a/webapp/components/rhs_comment.jsx +++ b/webapp/components/rhs_comment.jsx @@ -20,12 +20,10 @@ import * as PostUtils from 'utils/post_utils.jsx'; import Constants from 'utils/constants.jsx'; import DelayedAction from 'utils/delayed_action.jsx'; -import {Overlay} from 'react-bootstrap'; import {FormattedMessage} from 'react-intl'; -import EmojiPicker from 'components/emoji_picker/emoji_picker.jsx'; -import ReactDOM from 'react-dom'; +import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx'; import loadingGif from 'images/load.gif'; @@ -45,7 +43,6 @@ export default class RhsComment extends React.Component { this.pinPost = this.pinPost.bind(this); this.unpinPost = this.unpinPost.bind(this); this.reactEmojiClick = this.reactEmojiClick.bind(this); - this.emojiPickerClick = this.emojiPickerClick.bind(this); this.handleDropdownOpened = this.handleDropdownOpened.bind(this); this.canEdit = false; @@ -56,8 +53,7 @@ export default class RhsComment extends React.Component { currentTeamDisplayName: TeamStore.getCurrent().name, width: '', height: '', - showReactEmojiPicker: false, - reactPickerOffset: 15, + showEmojiPicker: false, dropdownOpened: false }; } @@ -129,7 +125,7 @@ export default class RhsComment extends React.Component { return true; } - if (this.state.showReactEmojiPicker !== nextState.showReactEmojiPicker) { + if (this.state.showEmojiPicker !== nextState.showEmojiPicker) { return true; } @@ -356,22 +352,17 @@ export default class RhsComment extends React.Component { ); } - emojiPickerClick() { - // set default offset - let reactOffset = 15; - const reactSelectorHeight = 360; - const reactionIconY = ReactDOM.findDOMNode(this).getBoundingClientRect().top; - const rhsMinHeight = 700; + toggleEmojiPicker = () => { + const showEmojiPicker = !this.state.showEmojiPicker; - const spaceAvail = rhsMinHeight - reactionIconY; - if (spaceAvail < reactSelectorHeight) { - reactOffset = (spaceAvail - reactSelectorHeight); - } - this.setState({showReactEmojiPicker: !this.state.showReactEmojiPicker, reactPickerOffset: reactOffset}); + this.setState({ + showEmojiPicker, + dropdownOpened: showEmojiPicker + }); } reactEmojiClick(emoji) { - this.setState({showReactEmojiPicker: false}); + this.setState({showEmojiPicker: false}); const emojiName = emoji.name || emoji.aliases[0]; addReaction(this.props.post.channel_id, this.props.post.id, emojiName); } @@ -554,39 +545,26 @@ export default class RhsComment extends React.Component { } let react; - let reactOverlay; - if (!isEphemeral && !isPending && !isSystemMessage && Utils.isFeatureEnabled(Constants.PRE_RELEASE_FEATURES.EMOJI_PICKER_PREVIEW)) { react = ( + this.refs.dotMenu} + container={this.props.getPostList} + onEmojiClick={this.reactEmojiClick} + /> ); - reactOverlay = ( - this.setState({showReactEmojiPicker: false})} - target={() => ReactDOM.findDOMNode(this.refs['rhs_reacticon_' + post.id])} - animation={false} - > - - - ); } let options; @@ -598,8 +576,10 @@ export default class RhsComment extends React.Component { ); } else if (!isSystemMessage) { options = ( -
- {reactOverlay} +
{this.createDropdown(isSystemMessage)} {react}
@@ -674,5 +654,6 @@ RhsComment.propTypes = { useMilitaryTime: PropTypes.bool.isRequired, isFlagged: PropTypes.bool, status: PropTypes.string, - isBusy: PropTypes.bool + isBusy: PropTypes.bool, + getPostList: PropTypes.func.isRequired }; diff --git a/webapp/components/rhs_root_post.jsx b/webapp/components/rhs_root_post.jsx index c00022e9e..e77fb7992 100644 --- a/webapp/components/rhs_root_post.jsx +++ b/webapp/components/rhs_root_post.jsx @@ -20,12 +20,10 @@ import {flagPost, unflagPost, pinPost, unpinPost, addReaction} from 'actions/pos import * as Utils from 'utils/utils.jsx'; import * as PostUtils from 'utils/post_utils.jsx'; -import EmojiPicker from 'components/emoji_picker/emoji_picker.jsx'; -import ReactDOM from 'react-dom'; +import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx'; import Constants from 'utils/constants.jsx'; import DelayedAction from 'utils/delayed_action.jsx'; -import {Overlay} from 'react-bootstrap'; import {FormattedMessage} from 'react-intl'; @@ -44,7 +42,6 @@ export default class RhsRootPost extends React.Component { this.pinPost = this.pinPost.bind(this); this.unpinPost = this.unpinPost.bind(this); this.reactEmojiClick = this.reactEmojiClick.bind(this); - this.emojiPickerClick = this.emojiPickerClick.bind(this); this.handleDropdownOpened = this.handleDropdownOpened.bind(this); this.canEdit = false; @@ -55,7 +52,7 @@ export default class RhsRootPost extends React.Component { currentTeamDisplayName: TeamStore.getCurrent().name, width: '', height: '', - showRHSEmojiPicker: false, + showEmojiPicker: false, testStateObj: true, dropdownOpened: false }; @@ -119,7 +116,7 @@ export default class RhsRootPost extends React.Component { return true; } - if (this.state.showRHSEmojiPicker !== nextState.showRHSEmojiPicker) { + if (this.state.showEmojiPicker !== nextState.showEmojiPicker) { return true; } @@ -175,12 +172,17 @@ export default class RhsRootPost extends React.Component { unpinPost(this.props.post.channel_id, this.props.post.id); } - emojiPickerClick() { - this.setState({showRHSEmojiPicker: !this.state.showRHSEmojiPicker}); + toggleEmojiPicker = () => { + const showEmojiPicker = !this.state.showEmojiPicker; + + this.setState({ + showEmojiPicker, + dropdownOpened: showEmojiPicker + }); } reactEmojiClick(emoji) { - this.setState({showRHSEmojiPicker: false}); + this.setState({showEmojiPicker: false}); const emojiName = emoji.name || emoji.aliases[0]; addReaction(this.props.post.channel_id, this.props.post.id, emojiName); } @@ -250,38 +252,26 @@ export default class RhsRootPost extends React.Component { } let react; - let reactOverlay; - if (!isEphemeral && !isPending && !isSystemMessage && Utils.isFeatureEnabled(Constants.PRE_RELEASE_FEATURES.EMOJI_PICKER_PREVIEW)) { react = ( + this.refs.dotMenu} + container={this.props.getPostList} + onEmojiClick={this.reactEmojiClick} + /> ); - reactOverlay = ( - this.setState({showRHSEmojiPicker: false})} - target={() => ReactDOM.findDOMNode(this.refs.rhs_root_reacticon)} - animation={false} - > - - - ); } var dropdownContents = []; @@ -590,8 +580,10 @@ export default class RhsRootPost extends React.Component { isFlagged={this.props.isFlagged} />
-
- {reactOverlay} +
{rootOptions} {react}
@@ -628,5 +620,6 @@ RhsRootPost.propTypes = { isFlagged: PropTypes.bool, status: PropTypes.string, previewCollapsed: PropTypes.string, - isBusy: PropTypes.bool + isBusy: PropTypes.bool, + getPostList: PropTypes.func.isRequired }; diff --git a/webapp/components/rhs_thread.jsx b/webapp/components/rhs_thread.jsx index bcb8a715f..a532119b8 100644 --- a/webapp/components/rhs_thread.jsx +++ b/webapp/components/rhs_thread.jsx @@ -338,6 +338,10 @@ export default class RhsThread extends React.Component { }); } + getPostListContainer = () => { + return this.refs.postListContainer; + } + render() { if (this.state.postsArray == null || this.state.selected == null) { return ( @@ -414,6 +418,7 @@ export default class RhsThread extends React.Component { isFlagged={isFlagged} status={status} isBusy={this.state.isBusy} + getPostList={this.getPostListContainer} />
); @@ -446,7 +451,7 @@ export default class RhsThread extends React.Component { onScroll={this.handleScroll} >