Fix chat scroll
This commit is contained in:
parent
6a9b9247ce
commit
25182c7dcf
3 changed files with 45 additions and 30 deletions
|
@ -74,15 +74,9 @@ export default function LivestreamChatLayout(props: Props) {
|
|||
const allCommentsElem = document.querySelectorAll('.livestream__comment');
|
||||
const lastCommentElem = allCommentsElem && allCommentsElem[allCommentsElem.length - 1];
|
||||
const minScrollPos =
|
||||
discussionElement && lastCommentElem && discussionElement.scrollHeight - lastCommentElem.offsetHeight;
|
||||
discussionElement && lastCommentElem && discussionElement.scrollHeight - lastCommentElem.offsetHeight * 2;
|
||||
const minOffset = discussionElement && minScrollPos && discussionElement.scrollHeight - minScrollPos;
|
||||
|
||||
const restoreScrollPos = React.useCallback(() => {
|
||||
if (discussionElement) discussionElement.scrollTop = !isMobile ? 0 : discussionElement.scrollHeight;
|
||||
}, [discussionElement, isMobile]);
|
||||
|
||||
const commentsRef = React.createRef();
|
||||
|
||||
const [viewMode, setViewMode] = React.useState(VIEW_MODES.CHAT);
|
||||
const [scrollPos, setScrollPos] = React.useState(0);
|
||||
const [showPinned, setShowPinned] = React.useState(true);
|
||||
|
@ -91,6 +85,7 @@ export default function LivestreamChatLayout(props: Props) {
|
|||
const [chatHidden, setChatHidden] = React.useState(false);
|
||||
const [didInitialScroll, setDidInitialScroll] = React.useState(false);
|
||||
const [bottomScrollTop, setBottomScrollTop] = React.useState(0);
|
||||
const [inputDrawerOpen, setInputDrawerOpen] = React.useState(false);
|
||||
|
||||
const recentScrollPos = isMobile ? (bottomScrollTop > 0 && minOffset ? bottomScrollTop - minOffset : 0) : 0;
|
||||
const claimId = claim && claim.claim_id;
|
||||
|
@ -98,6 +93,18 @@ export default function LivestreamChatLayout(props: Props) {
|
|||
const commentsLength = commentsToDisplay && commentsToDisplay.length;
|
||||
const pinnedComment = pinnedComments.length > 0 ? pinnedComments[0] : null;
|
||||
const { superChatsChannelUrls, superChatsFiatAmount, superChatsLBCAmount } = getTipValues(superChatsByAmount);
|
||||
const hasRecentComments = Boolean(
|
||||
scrollPos && (!isMobile || recentScrollPos) && scrollPos < recentScrollPos && viewMode === VIEW_MODES.CHAT
|
||||
);
|
||||
|
||||
const restoreScrollPos = React.useCallback(() => {
|
||||
if (discussionElement) {
|
||||
discussionElement.scrollTop = !isMobile ? 0 : discussionElement.scrollHeight;
|
||||
setBottomScrollTop(discussionElement.scrollTop);
|
||||
}
|
||||
}, [discussionElement, isMobile]);
|
||||
|
||||
const commentsRef = React.createRef();
|
||||
|
||||
function toggleSuperChat() {
|
||||
if (superChatsChannelUrls && superChatsChannelUrls.length > 0) {
|
||||
|
@ -129,14 +136,14 @@ export default function LivestreamChatLayout(props: Props) {
|
|||
isMobile &&
|
||||
discussionElement &&
|
||||
viewMode === VIEW_MODES.CHAT &&
|
||||
!didInitialScroll &&
|
||||
(!didInitialScroll || bottomScrollTop === 0) &&
|
||||
discussionElement.scrollTop < discussionElement.scrollHeight
|
||||
) {
|
||||
discussionElement.scrollTop = discussionElement.scrollHeight;
|
||||
setDidInitialScroll(true);
|
||||
setBottomScrollTop(discussionElement.scrollTop);
|
||||
}
|
||||
}, [didInitialScroll, discussionElement, isMobile, viewMode]);
|
||||
}, [bottomScrollTop, didInitialScroll, discussionElement, isMobile, viewMode]);
|
||||
|
||||
// Register scroll handler (TODO: Should throttle/debounce)
|
||||
React.useEffect(() => {
|
||||
|
@ -334,10 +341,15 @@ export default function LivestreamChatLayout(props: Props) {
|
|||
<Spinner />
|
||||
</div>
|
||||
) : (
|
||||
<LivestreamComments uri={uri} commentsToDisplay={commentsToDisplay} isMobile={isMobile} />
|
||||
<LivestreamComments
|
||||
uri={uri}
|
||||
commentsToDisplay={commentsToDisplay}
|
||||
isMobile={isMobile}
|
||||
restoreScrollPos={!hasRecentComments && !inputDrawerOpen && restoreScrollPos}
|
||||
/>
|
||||
)}
|
||||
|
||||
{scrollPos && (!isMobile || recentScrollPos) && scrollPos < recentScrollPos && viewMode === VIEW_MODES.CHAT ? (
|
||||
{hasRecentComments ? (
|
||||
<Button
|
||||
button="secondary"
|
||||
className="livestream-comments__scroll-to-recent"
|
||||
|
@ -354,13 +366,10 @@ export default function LivestreamChatLayout(props: Props) {
|
|||
embed={embed}
|
||||
uri={uri}
|
||||
onDoneReplying={restoreScrollPos}
|
||||
onSlimInputClick={
|
||||
scrollPos &&
|
||||
recentScrollPos &&
|
||||
scrollPos >= recentScrollPos &&
|
||||
viewMode === VIEW_MODES.CHAT &&
|
||||
restoreScrollPos
|
||||
}
|
||||
onSlimInputClick={() => {
|
||||
restoreScrollPos();
|
||||
setInputDrawerOpen(!inputDrawerOpen);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -28,10 +28,21 @@ type Props = {
|
|||
stakedLevel: number,
|
||||
isMobile?: boolean,
|
||||
handleDismissPin?: () => void,
|
||||
restoreScrollPos?: () => void,
|
||||
};
|
||||
|
||||
export default function LivestreamComment(props: Props) {
|
||||
const { comment, forceUpdate, uri, claim, myChannelIds, stakedLevel, isMobile, handleDismissPin } = props;
|
||||
const {
|
||||
comment,
|
||||
forceUpdate,
|
||||
uri,
|
||||
claim,
|
||||
myChannelIds,
|
||||
stakedLevel,
|
||||
isMobile,
|
||||
handleDismissPin,
|
||||
restoreScrollPos,
|
||||
} = props;
|
||||
|
||||
const {
|
||||
channel_url: authorUri,
|
||||
|
@ -46,8 +57,6 @@ export default function LivestreamComment(props: Props) {
|
|||
timestamp,
|
||||
} = comment;
|
||||
|
||||
const commentRef = React.useRef();
|
||||
|
||||
const [hasUserMention, setUserMention] = React.useState(false);
|
||||
|
||||
const isStreamer = claim && claim.signing_channel && claim.signing_channel.permanent_url === authorUri;
|
||||
|
@ -56,10 +65,6 @@ export default function LivestreamComment(props: Props) {
|
|||
const isSticker = Boolean(stickerUrlFromMessage);
|
||||
const timePosted = timestamp * 1000;
|
||||
const commentIsMine = comment.channel_id && isMyComment(comment.channel_id);
|
||||
const discussionElement = document.querySelector('.livestream__comments--mobile');
|
||||
const currentComment = commentRef && commentRef.current;
|
||||
const minScrollPos =
|
||||
discussionElement && currentComment && discussionElement.scrollHeight - currentComment.offsetHeight;
|
||||
|
||||
// todo: implement comment_list --mine in SDK so redux can grab with selectCommentIsMine
|
||||
function isMyComment(channelId: string) {
|
||||
|
@ -69,10 +74,10 @@ export default function LivestreamComment(props: Props) {
|
|||
// For every new <LivestreamComment /> component that is rendered on mobile view,
|
||||
// keep the scroll at the bottom (newest)
|
||||
React.useEffect(() => {
|
||||
if (isMobile && discussionElement && minScrollPos && discussionElement.scrollTop >= minScrollPos) {
|
||||
discussionElement.scrollTop = discussionElement.scrollHeight;
|
||||
if (isMobile && restoreScrollPos) {
|
||||
restoreScrollPos();
|
||||
}
|
||||
}, [discussionElement, isMobile, minScrollPos]);
|
||||
}, [isMobile, restoreScrollPos]);
|
||||
|
||||
return (
|
||||
<li
|
||||
|
@ -82,7 +87,6 @@ export default function LivestreamComment(props: Props) {
|
|||
'livestream__comment--mentioned': hasUserMention,
|
||||
'livestream__comment--mobile': isMobile,
|
||||
})}
|
||||
ref={commentRef}
|
||||
>
|
||||
{supportAmount > 0 && (
|
||||
<div className="livestreamComment__superchatBanner">
|
||||
|
|
|
@ -12,10 +12,11 @@ type Props = {
|
|||
fetchingComments: boolean,
|
||||
uri: string,
|
||||
isMobile?: boolean,
|
||||
restoreScrollPos?: () => void,
|
||||
};
|
||||
|
||||
export default function LivestreamComments(props: Props) {
|
||||
const { commentsToDisplay, fetchingComments, uri, isMobile } = props;
|
||||
const { commentsToDisplay, fetchingComments, uri, isMobile, restoreScrollPos } = props;
|
||||
|
||||
const [forceUpdate, setForceUpdate] = React.useState(0);
|
||||
|
||||
|
@ -56,6 +57,7 @@ export default function LivestreamComments(props: Props) {
|
|||
uri={uri}
|
||||
forceUpdate={forceUpdate}
|
||||
isMobile
|
||||
restoreScrollPos={restoreScrollPos}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue