Fix keyboard & comment selectors open affecting scroll
This commit is contained in:
parent
e42090d3b6
commit
dae0f9c3d5
5 changed files with 57 additions and 10 deletions
|
@ -54,6 +54,7 @@ type Props = {
|
||||||
supportDisabled: boolean,
|
supportDisabled: boolean,
|
||||||
uri: string,
|
uri: string,
|
||||||
disableInput?: boolean,
|
disableInput?: boolean,
|
||||||
|
onSlimInputClose?: () => void,
|
||||||
setQuickReply: (any) => void,
|
setQuickReply: (any) => void,
|
||||||
onCancelReplying?: () => void,
|
onCancelReplying?: () => void,
|
||||||
onDoneReplying?: () => void,
|
onDoneReplying?: () => void,
|
||||||
|
@ -89,6 +90,7 @@ export function CommentCreate(props: Props) {
|
||||||
supportDisabled,
|
supportDisabled,
|
||||||
uri,
|
uri,
|
||||||
disableInput,
|
disableInput,
|
||||||
|
onSlimInputClose,
|
||||||
doCommentCreate,
|
doCommentCreate,
|
||||||
doFetchCreatorSettings,
|
doFetchCreatorSettings,
|
||||||
doToast,
|
doToast,
|
||||||
|
@ -177,6 +179,8 @@ export function CommentCreate(props: Props) {
|
||||||
} else {
|
} else {
|
||||||
setTipSelector(true);
|
setTipSelector(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (onSlimInputClose) onSlimInputClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleStickerComment() {
|
function handleStickerComment() {
|
||||||
|
@ -198,6 +202,9 @@ export function CommentCreate(props: Props) {
|
||||||
setTipAmount(sticker.price || 0);
|
setTipAmount(sticker.price || 0);
|
||||||
setShowSelectors({ tab: showSelectors.tab || undefined, open: false });
|
setShowSelectors({ tab: showSelectors.tab || undefined, open: false });
|
||||||
|
|
||||||
|
// added this here since selecting a sticker can cause scroll issues
|
||||||
|
if (onSlimInputClose) onSlimInputClose();
|
||||||
|
|
||||||
if (sticker.price && sticker.price > 0) {
|
if (sticker.price && sticker.price > 0) {
|
||||||
setActiveTab(canReceiveFiatTip ? TAB_FIAT : TAB_LBC);
|
setActiveTab(canReceiveFiatTip ? TAB_FIAT : TAB_LBC);
|
||||||
setTipSelector(true);
|
setTipSelector(true);
|
||||||
|
@ -207,6 +214,8 @@ export function CommentCreate(props: Props) {
|
||||||
function handleCancelSticker() {
|
function handleCancelSticker() {
|
||||||
setReviewingStickerComment(false);
|
setReviewingStickerComment(false);
|
||||||
setSelectedSticker(null);
|
setSelectedSticker(null);
|
||||||
|
|
||||||
|
if (onSlimInputClose) onSlimInputClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCancelSupport() {
|
function handleCancelSupport() {
|
||||||
|
@ -218,6 +227,8 @@ export function CommentCreate(props: Props) {
|
||||||
setShowSelectors({ tab: showSelectors.tab || undefined, open: false });
|
setShowSelectors({ tab: showSelectors.tab || undefined, open: false });
|
||||||
setSelectedSticker(null);
|
setSelectedSticker(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (onSlimInputClose) onSlimInputClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSupportComment() {
|
function handleSupportComment() {
|
||||||
|
@ -574,6 +585,7 @@ export function CommentCreate(props: Props) {
|
||||||
handleSubmit={handleCreateComment}
|
handleSubmit={handleCreateComment}
|
||||||
slimInput={isMobile && uri} // "uri": make sure it's on a file page
|
slimInput={isMobile && uri} // "uri": make sure it's on a file page
|
||||||
slimInputButtonRef={slimInputButtonRef}
|
slimInputButtonRef={slimInputButtonRef}
|
||||||
|
onSlimInputClose={onSlimInputClose}
|
||||||
commentSelectorsProps={commentSelectorsProps}
|
commentSelectorsProps={commentSelectorsProps}
|
||||||
submitButtonRef={buttonRef}
|
submitButtonRef={buttonRef}
|
||||||
setShowSelectors={setShowSelectors}
|
setShowSelectors={setShowSelectors}
|
||||||
|
@ -633,7 +645,10 @@ export function CommentCreate(props: Props) {
|
||||||
disabled={disabled || tipSelectorError || !minAmountMet}
|
disabled={disabled || tipSelectorError || !minAmountMet}
|
||||||
icon={activeTab === TAB_LBC ? ICONS.LBC : ICONS.FINANCE}
|
icon={activeTab === TAB_LBC ? ICONS.LBC : ICONS.FINANCE}
|
||||||
label={__('Review')}
|
label={__('Review')}
|
||||||
onClick={() => setReviewingSupportComment(true)}
|
onClick={() => {
|
||||||
|
setReviewingSupportComment(true);
|
||||||
|
if (onSlimInputClose) onSlimInputClose();
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
(!isMobile || selectedSticker) &&
|
(!isMobile || selectedSticker) &&
|
||||||
|
|
|
@ -53,6 +53,7 @@ type Props = {
|
||||||
submitButtonRef?: any,
|
submitButtonRef?: any,
|
||||||
tipModalOpen?: boolean,
|
tipModalOpen?: boolean,
|
||||||
noticeLabel?: any,
|
noticeLabel?: any,
|
||||||
|
onSlimInputClose?: () => void,
|
||||||
onChange?: (any) => any,
|
onChange?: (any) => any,
|
||||||
setShowSelectors?: ({ tab?: string, open: boolean }) => void,
|
setShowSelectors?: ({ tab?: string, open: boolean }) => void,
|
||||||
quickActionHandler?: (any) => any,
|
quickActionHandler?: (any) => any,
|
||||||
|
@ -116,6 +117,7 @@ export class FormField extends React.PureComponent<Props, State> {
|
||||||
submitButtonRef,
|
submitButtonRef,
|
||||||
tipModalOpen,
|
tipModalOpen,
|
||||||
noticeLabel,
|
noticeLabel,
|
||||||
|
onSlimInputClose,
|
||||||
quickActionHandler,
|
quickActionHandler,
|
||||||
setShowSelectors,
|
setShowSelectors,
|
||||||
render,
|
render,
|
||||||
|
@ -277,6 +279,7 @@ export class FormField extends React.PureComponent<Props, State> {
|
||||||
showSelectors={Boolean(showSelectors && showSelectors.open)}
|
showSelectors={Boolean(showSelectors && showSelectors.open)}
|
||||||
slimInput={slimInput}
|
slimInput={slimInput}
|
||||||
slimInputButtonRef={slimInputButtonRef}
|
slimInputButtonRef={slimInputButtonRef}
|
||||||
|
onSlimInputClose={onSlimInputClose}
|
||||||
tipModalOpen={tipModalOpen}
|
tipModalOpen={tipModalOpen}
|
||||||
>
|
>
|
||||||
{(!slimInput || this.state.drawerOpen) && label && (
|
{(!slimInput || this.state.drawerOpen) && label && (
|
||||||
|
|
|
@ -11,6 +11,7 @@ type TextareaWrapperProps = {
|
||||||
showSelectors?: boolean,
|
showSelectors?: boolean,
|
||||||
commentSelectorsProps?: any,
|
commentSelectorsProps?: any,
|
||||||
tipModalOpen?: boolean,
|
tipModalOpen?: boolean,
|
||||||
|
onSlimInputClose?: () => void,
|
||||||
toggleDrawer: () => void,
|
toggleDrawer: () => void,
|
||||||
closeSelector?: () => void,
|
closeSelector?: () => void,
|
||||||
};
|
};
|
||||||
|
@ -24,6 +25,7 @@ export const TextareaWrapper = (wrapperProps: TextareaWrapperProps) => {
|
||||||
commentSelectorsProps,
|
commentSelectorsProps,
|
||||||
showSelectors,
|
showSelectors,
|
||||||
tipModalOpen,
|
tipModalOpen,
|
||||||
|
onSlimInputClose,
|
||||||
toggleDrawer,
|
toggleDrawer,
|
||||||
closeSelector,
|
closeSelector,
|
||||||
} = wrapperProps;
|
} = wrapperProps;
|
||||||
|
@ -31,6 +33,7 @@ export const TextareaWrapper = (wrapperProps: TextareaWrapperProps) => {
|
||||||
function handleCloseAll() {
|
function handleCloseAll() {
|
||||||
toggleDrawer();
|
toggleDrawer();
|
||||||
if (closeSelector) closeSelector();
|
if (closeSelector) closeSelector();
|
||||||
|
if (onSlimInputClose) onSlimInputClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
return slimInput ? (
|
return slimInput ? (
|
||||||
|
|
|
@ -82,6 +82,7 @@ export default function LivestreamChatLayout(props: Props) {
|
||||||
const [chatHidden, setChatHidden] = React.useState(false);
|
const [chatHidden, setChatHidden] = React.useState(false);
|
||||||
const [didInitialScroll, setDidInitialScroll] = React.useState(false);
|
const [didInitialScroll, setDidInitialScroll] = React.useState(false);
|
||||||
const [minScrollHeight, setMinScrollHeight] = React.useState(0);
|
const [minScrollHeight, setMinScrollHeight] = React.useState(0);
|
||||||
|
const [keyboardOpened, setKeyboardOpened] = React.useState(false);
|
||||||
|
|
||||||
const claimId = claim && claim.claim_id;
|
const claimId = claim && claim.claim_id;
|
||||||
const commentsToDisplay = viewMode === VIEW_MODES.CHAT ? commentsByChronologicalOrder : superChatsByAmount;
|
const commentsToDisplay = viewMode === VIEW_MODES.CHAT ? commentsByChronologicalOrder : superChatsByAmount;
|
||||||
|
@ -89,10 +90,7 @@ export default function LivestreamChatLayout(props: Props) {
|
||||||
const pinnedComment = pinnedComments.length > 0 ? pinnedComments[0] : null;
|
const pinnedComment = pinnedComments.length > 0 ? pinnedComments[0] : null;
|
||||||
const { superChatsChannelUrls, superChatsFiatAmount, superChatsLBCAmount } = getTipValues(superChatsByAmount);
|
const { superChatsChannelUrls, superChatsFiatAmount, superChatsLBCAmount } = getTipValues(superChatsByAmount);
|
||||||
const scrolledPastRecent = Boolean(
|
const scrolledPastRecent = Boolean(
|
||||||
(scrollPos || scrollPos === 0) &&
|
viewMode === VIEW_MODES.CHAT && !isMobile ? scrollPos < 0 : scrollPos < minScrollHeight
|
||||||
(!isMobile || minScrollHeight) &&
|
|
||||||
scrollPos < minScrollHeight &&
|
|
||||||
viewMode === VIEW_MODES.CHAT
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const restoreScrollPos = React.useCallback(() => {
|
const restoreScrollPos = React.useCallback(() => {
|
||||||
|
@ -149,7 +147,7 @@ export default function LivestreamChatLayout(props: Props) {
|
||||||
if (discussionElement) {
|
if (discussionElement) {
|
||||||
const scrollTop = discussionElement.scrollTop;
|
const scrollTop = discussionElement.scrollTop;
|
||||||
|
|
||||||
if (!scrollPos || scrollTop !== scrollPos) {
|
if (scrollTop !== scrollPos) {
|
||||||
setScrollPos(scrollTop);
|
setScrollPos(scrollTop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,7 +169,11 @@ export default function LivestreamChatLayout(props: Props) {
|
||||||
// -ve scrollPos: user scrolled.
|
// -ve scrollPos: user scrolled.
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
// Use a timer here to ensure we reset after the new comment has been rendered.
|
// Use a timer here to ensure we reset after the new comment has been rendered.
|
||||||
restoreScrollPos();
|
if (!isMobile) {
|
||||||
|
discussionElement.scrollTop = 0;
|
||||||
|
} else {
|
||||||
|
restoreScrollPos();
|
||||||
|
}
|
||||||
}, COMMENT_SCROLL_TIMEOUT);
|
}, COMMENT_SCROLL_TIMEOUT);
|
||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
}
|
}
|
||||||
|
@ -179,6 +181,18 @@ export default function LivestreamChatLayout(props: Props) {
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [commentsLength]); // (Just respond to 'commentsLength' updates and nothing else)
|
}, [commentsLength]); // (Just respond to 'commentsLength' updates and nothing else)
|
||||||
|
|
||||||
|
// Restore Scroll Pos after mobile input opens keyboard and avoid scroll height conflicts
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (keyboardOpened) {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
restoreScrollPos();
|
||||||
|
setKeyboardOpened(false);
|
||||||
|
}, 300);
|
||||||
|
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}
|
||||||
|
}, [keyboardOpened, restoreScrollPos]);
|
||||||
|
|
||||||
// Stop spinner for resolving superchats
|
// Stop spinner for resolving superchats
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (resolvingSuperChats) {
|
if (resolvingSuperChats) {
|
||||||
|
@ -359,7 +373,14 @@ export default function LivestreamChatLayout(props: Props) {
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<div className="livestream__comment-create">
|
<div className="livestream__comment-create">
|
||||||
<CommentCreate isLivestream bottom embed={embed} uri={uri} onDoneReplying={restoreScrollPos} />
|
<CommentCreate
|
||||||
|
isLivestream
|
||||||
|
bottom
|
||||||
|
embed={embed}
|
||||||
|
uri={uri}
|
||||||
|
onDoneReplying={restoreScrollPos}
|
||||||
|
onSlimInputClose={!scrolledPastRecent && isMobile ? () => setKeyboardOpened(true) : undefined}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,6 +7,7 @@ import LivestreamLayout from 'component/livestreamLayout';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import Page from 'component/page';
|
import Page from 'component/page';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useIsMobile } from 'effects/use-screensize';
|
||||||
|
|
||||||
const LivestreamChatLayout = lazyImport(() => import('component/livestreamChatLayout' /* webpackChunkName: "chat" */));
|
const LivestreamChatLayout = lazyImport(() => import('component/livestreamChatLayout' /* webpackChunkName: "chat" */));
|
||||||
|
|
||||||
|
@ -41,6 +42,8 @@ export default function LivestreamPage(props: Props) {
|
||||||
doUserSetReferrer,
|
doUserSetReferrer,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
const isMobile = useIsMobile();
|
||||||
|
|
||||||
const [activeStreamUri, setActiveStreamUri] = React.useState(false);
|
const [activeStreamUri, setActiveStreamUri] = React.useState(false);
|
||||||
const [showLivestream, setShowLivestream] = React.useState(false);
|
const [showLivestream, setShowLivestream] = React.useState(false);
|
||||||
const [showScheduledInfo, setShowScheduledInfo] = React.useState(false);
|
const [showScheduledInfo, setShowScheduledInfo] = React.useState(false);
|
||||||
|
@ -145,8 +148,10 @@ export default function LivestreamPage(props: Props) {
|
||||||
// This can be removed when we start using the app video player, not a LIVESTREAM iframe
|
// This can be removed when we start using the app video player, not a LIVESTREAM iframe
|
||||||
doSetPlayingUri({ uri: null });
|
doSetPlayingUri({ uri: null });
|
||||||
|
|
||||||
return () => doSetPlayingUri({ uri: null });
|
return () => {
|
||||||
}, [doSetPlayingUri]);
|
if (isMobile) doSetPlayingUri({ uri: null });
|
||||||
|
};
|
||||||
|
}, [doSetPlayingUri, isMobile]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page
|
<Page
|
||||||
|
|
Loading…
Reference in a new issue