Fix fastSmoothScroll path function
This commit is contained in:
parent
22054c4416
commit
2688314c84
@ -4,7 +4,8 @@ import { useLayoutEffect, useMemo } from '../../../../lib/teact/teact';
|
|||||||
import fastSmoothScroll from '../../../../util/fastSmoothScroll';
|
import fastSmoothScroll from '../../../../util/fastSmoothScroll';
|
||||||
|
|
||||||
// This is used when the viewport was replaced.
|
// This is used when the viewport was replaced.
|
||||||
const RELOCATED_FOCUS_OFFSET = 1000;
|
const BOTTOM_FOCUS_OFFSET = 500;
|
||||||
|
const RELOCATED_FOCUS_OFFSET = 750;
|
||||||
const FOCUS_MARGIN = 20;
|
const FOCUS_MARGIN = 20;
|
||||||
|
|
||||||
export default function useFocusMessage(
|
export default function useFocusMessage(
|
||||||
@ -29,14 +30,15 @@ export default function useFocusMessage(
|
|||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (isFocused && elementRef.current) {
|
if (isFocused && elementRef.current) {
|
||||||
const messagesContainer = elementRef.current.closest<HTMLDivElement>('.MessageList')!;
|
const messagesContainer = elementRef.current.closest<HTMLDivElement>('.MessageList')!;
|
||||||
|
// `noFocusHighlight` is always called with “scroll-to-bottom” buttons
|
||||||
|
const isToBottom = noFocusHighlight;
|
||||||
|
|
||||||
fastSmoothScroll(
|
fastSmoothScroll(
|
||||||
messagesContainer,
|
messagesContainer,
|
||||||
elementRef.current,
|
elementRef.current,
|
||||||
// `noFocusHighlight` always called from “scroll-to-bottom” buttons
|
isToBottom ? 'end' : 'centerOrTop',
|
||||||
noFocusHighlight ? 'end' : 'centerOrTop',
|
|
||||||
FOCUS_MARGIN,
|
FOCUS_MARGIN,
|
||||||
focusDirection !== undefined ? RELOCATED_FOCUS_OFFSET : undefined,
|
focusDirection !== undefined ? (isToBottom ? BOTTOM_FOCUS_OFFSET : RELOCATED_FOCUS_OFFSET) : undefined,
|
||||||
focusDirection,
|
focusDirection,
|
||||||
undefined,
|
undefined,
|
||||||
isResizingContainer,
|
isResizingContainer,
|
||||||
|
|||||||
@ -146,7 +146,7 @@ export const ANIMATION_END_DELAY = 100;
|
|||||||
export const FAST_SMOOTH_MAX_DISTANCE = 1500;
|
export const FAST_SMOOTH_MAX_DISTANCE = 1500;
|
||||||
export const FAST_SMOOTH_MIN_DURATION = 250;
|
export const FAST_SMOOTH_MIN_DURATION = 250;
|
||||||
export const FAST_SMOOTH_MAX_DURATION = 600;
|
export const FAST_SMOOTH_MAX_DURATION = 600;
|
||||||
export const FAST_SMOOTH_SHORT_TRANSITION_MAX_DISTANCE = 500; // px
|
export const FAST_SMOOTH_SHORT_TRANSITION_MAX_DISTANCE = 750; // px
|
||||||
|
|
||||||
// Average duration of message sending animation
|
// Average duration of message sending animation
|
||||||
export const API_UPDATE_THROTTLE = Math.round((FAST_SMOOTH_MIN_DURATION + FAST_SMOOTH_MAX_DURATION) / 2);
|
export const API_UPDATE_THROTTLE = Math.round((FAST_SMOOTH_MIN_DURATION + FAST_SMOOTH_MAX_DURATION) / 2);
|
||||||
|
|||||||
@ -24,88 +24,45 @@ export default function fastSmoothScroll(
|
|||||||
forceDuration?: number,
|
forceDuration?: number,
|
||||||
forceNormalContainerHeight?: boolean,
|
forceNormalContainerHeight?: boolean,
|
||||||
) {
|
) {
|
||||||
const scrollFrom = calculateScrollFrom(container, element, maxDistance, forceDirection);
|
if (
|
||||||
|
forceDirection === FocusDirection.Static
|
||||||
if (forceDirection === FocusDirection.Static) {
|
|| getGlobal().settings.byKey.animationLevel === ANIMATION_LEVEL_MIN
|
||||||
scrollWithJs(container, element, scrollFrom, position, margin, 0);
|
) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getGlobal().settings.byKey.animationLevel === ANIMATION_LEVEL_MIN) {
|
|
||||||
forceDuration = 0;
|
forceDuration = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollWithJs(container, element, scrollFrom, position, margin, forceDuration, forceNormalContainerHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isAnimatingScroll() {
|
|
||||||
return isAnimating;
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculateScrollFrom(
|
|
||||||
container: HTMLElement,
|
|
||||||
element: HTMLElement,
|
|
||||||
maxDistance = FAST_SMOOTH_MAX_DISTANCE,
|
|
||||||
forceDirection?: FocusDirection,
|
|
||||||
) {
|
|
||||||
const { offsetTop: elementTop } = element;
|
|
||||||
const { scrollTop } = container;
|
|
||||||
|
|
||||||
if (forceDirection === undefined) {
|
|
||||||
const offset = elementTop - container.scrollTop;
|
|
||||||
|
|
||||||
if (offset < -maxDistance) {
|
|
||||||
return scrollTop + (offset + maxDistance);
|
|
||||||
} else if (offset > maxDistance) {
|
|
||||||
return scrollTop + (offset - maxDistance);
|
|
||||||
}
|
|
||||||
} else if (forceDirection === FocusDirection.Up) {
|
|
||||||
return elementTop + maxDistance;
|
|
||||||
} else if (forceDirection === FocusDirection.Down) {
|
|
||||||
return Math.max(0, elementTop - maxDistance);
|
|
||||||
}
|
|
||||||
|
|
||||||
return scrollTop;
|
|
||||||
}
|
|
||||||
|
|
||||||
function scrollWithJs(
|
|
||||||
container: HTMLElement,
|
|
||||||
element: HTMLElement,
|
|
||||||
scrollFrom: number,
|
|
||||||
position: ScrollLogicalPosition | 'centerOrTop',
|
|
||||||
margin = 0,
|
|
||||||
forceDuration?: number,
|
|
||||||
forceNormalContainerHeight?: boolean,
|
|
||||||
) {
|
|
||||||
const { offsetTop: elementTop, offsetHeight: elementHeight } = element;
|
const { offsetTop: elementTop, offsetHeight: elementHeight } = element;
|
||||||
const { scrollTop: currentScrollTop, offsetHeight: containerHeight, scrollHeight } = container;
|
const { scrollTop: currentScrollTop, offsetHeight: containerHeight, scrollHeight } = container;
|
||||||
const targetContainerHeight = forceNormalContainerHeight && container.dataset.normalHeight
|
const targetContainerHeight = forceNormalContainerHeight && container.dataset.normalHeight
|
||||||
? Number(container.dataset.normalHeight)
|
? Number(container.dataset.normalHeight)
|
||||||
: containerHeight;
|
: containerHeight;
|
||||||
|
|
||||||
if (currentScrollTop !== scrollFrom) {
|
let scrollTo!: number;
|
||||||
container.scrollTop = scrollFrom;
|
|
||||||
}
|
|
||||||
|
|
||||||
let path!: number;
|
|
||||||
|
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case 'start':
|
case 'start':
|
||||||
path = (elementTop - margin) - scrollFrom + (IS_ANDROID ? 1 : 0);
|
scrollTo = (elementTop - margin) + (IS_ANDROID ? 1 : 0);
|
||||||
break;
|
break;
|
||||||
case 'end':
|
case 'end':
|
||||||
path = (elementTop + elementHeight + margin) - (scrollFrom + targetContainerHeight);
|
scrollTo = (elementTop + elementHeight + margin) - targetContainerHeight;
|
||||||
break;
|
break;
|
||||||
// 'nearest' is not supported yet
|
// 'nearest' is not supported yet
|
||||||
case 'nearest':
|
case 'nearest':
|
||||||
case 'center':
|
case 'center':
|
||||||
case 'centerOrTop':
|
case 'centerOrTop':
|
||||||
path = elementHeight < targetContainerHeight
|
scrollTo = elementHeight < targetContainerHeight
|
||||||
? (elementTop + elementHeight / 2) - (scrollFrom + targetContainerHeight / 2)
|
? (elementTop + elementHeight / 2 - targetContainerHeight / 2)
|
||||||
: (elementTop - margin) - scrollFrom;
|
: (elementTop - margin);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scrollFrom = calculateScrollFrom(container, scrollTo, maxDistance, forceDirection);
|
||||||
|
|
||||||
|
if (currentScrollTop !== scrollFrom) {
|
||||||
|
container.scrollTop = scrollFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = scrollTo - scrollFrom;
|
||||||
|
|
||||||
if (path < 0) {
|
if (path < 0) {
|
||||||
const remainingPath = -scrollFrom;
|
const remainingPath = -scrollFrom;
|
||||||
path = Math.max(path, remainingPath);
|
path = Math.max(path, remainingPath);
|
||||||
@ -128,7 +85,7 @@ function scrollWithJs(
|
|||||||
isAnimating = true;
|
isAnimating = true;
|
||||||
|
|
||||||
const absPath = Math.abs(path);
|
const absPath = Math.abs(path);
|
||||||
const transition = absPath < FAST_SMOOTH_SHORT_TRANSITION_MAX_DISTANCE ? shortTransition : longTransition;
|
const transition = absPath <= FAST_SMOOTH_SHORT_TRANSITION_MAX_DISTANCE ? shortTransition : longTransition;
|
||||||
const duration = forceDuration || (
|
const duration = forceDuration || (
|
||||||
FAST_SMOOTH_MIN_DURATION
|
FAST_SMOOTH_MIN_DURATION
|
||||||
+ (absPath / FAST_SMOOTH_MAX_DISTANCE) * (FAST_SMOOTH_MAX_DURATION - FAST_SMOOTH_MIN_DURATION)
|
+ (absPath / FAST_SMOOTH_MAX_DISTANCE) * (FAST_SMOOTH_MAX_DURATION - FAST_SMOOTH_MIN_DURATION)
|
||||||
@ -154,6 +111,35 @@ function scrollWithJs(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isAnimatingScroll() {
|
||||||
|
return isAnimating;
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateScrollFrom(
|
||||||
|
container: HTMLElement,
|
||||||
|
scrollTo: number,
|
||||||
|
maxDistance = FAST_SMOOTH_MAX_DISTANCE,
|
||||||
|
forceDirection?: FocusDirection,
|
||||||
|
) {
|
||||||
|
const { scrollTop } = container;
|
||||||
|
|
||||||
|
if (forceDirection === undefined) {
|
||||||
|
const offset = scrollTo - scrollTop;
|
||||||
|
|
||||||
|
if (offset < -maxDistance) {
|
||||||
|
return scrollTop + (offset + maxDistance);
|
||||||
|
} else if (offset > maxDistance) {
|
||||||
|
return scrollTop + (offset - maxDistance);
|
||||||
|
}
|
||||||
|
} else if (forceDirection === FocusDirection.Up) {
|
||||||
|
return scrollTo + maxDistance;
|
||||||
|
} else if (forceDirection === FocusDirection.Down) {
|
||||||
|
return Math.max(0, scrollTo - maxDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return scrollTop;
|
||||||
|
}
|
||||||
|
|
||||||
function longTransition(t: number) {
|
function longTransition(t: number) {
|
||||||
return 1 - ((1 - t) ** 5);
|
return 1 - ((1 - t) ** 5);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user