Skip to content

Commit

Permalink
Refactor scroll normalization
Browse files Browse the repository at this point in the history
  • Loading branch information
inokawa committed Jan 16, 2024
1 parent 5625d81 commit 4f1511d
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 25 deletions.
2 changes: 1 addition & 1 deletion e2e/VList.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ test.describe("check if scrollToIndex works", () => {
// Check if scrolled precisely
const lastItem = await getLastItem(component);
await expect(lastItem.text).toEqual("999");
expectInRange(lastItem.bottom, { min: 0, max: 1 });
expectInRange(lastItem.bottom, { min: -1, max: 1 });

// Check if unnecessary items are not rendered
await expect(await component.innerText()).not.toContain("949");
Expand Down
5 changes: 4 additions & 1 deletion src/core/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import { computeStyle, once } from "./utils";
*/
export const isBrowser = typeof window !== "undefined";

const getDocumentElement = () => document.documentElement;
/**
* @internal
*/
export const getDocumentElement = () => document.documentElement;

/**
* The scroll position may be negative value in rtl direction.
Expand Down
45 changes: 24 additions & 21 deletions src/core/scroller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
getDocumentElement,
hasNegativeOffsetInRTL,
isIOSWebKit,
isRTLDocument,
Expand All @@ -16,17 +17,21 @@ import {
import { ScrollToIndexOpts } from "./types";
import { debounce, timeout, clamp } from "./utils";

const normalizeRTLOffset = (
const normalizeHorizontalOffset = (
scrollable: HTMLElement,
store: VirtualStore,
offset: number,
diff?: boolean
): number => {
if (hasNegativeOffsetInRTL(scrollable)) {
return -offset;
} else {
return diff ? -offset : store._getMaxScrollOffset() - offset;
if (isRTLDocument()) {
if (hasNegativeOffsetInRTL(scrollable)) {
return -offset;
} else {
return diff
? -offset
: scrollable.scrollWidth - scrollable.clientWidth - offset;
}
}
return offset;
};

const createScrollObserver = (
Expand Down Expand Up @@ -155,14 +160,15 @@ export const createScroller = (
const overflowKey = isHorizontal ? "overflowX" : "overflowY";

const normalizeOffset = (offset: number, diff?: boolean): number => {
if (isHorizontal && isRTLDocument()) {
return normalizeRTLOffset(viewportElement!, store, offset, diff);
}
return offset;
return isHorizontal
? normalizeHorizontalOffset(viewportElement!, offset, diff)
: offset;
};

// The given offset will be clamped by browser
// https://drafts.csswg.org/cssom-view/#dom-element-scrolltop
const scheduleImperativeScroll = async (
getOffset: () => number,
getTargetOffset: () => number,
smooth?: boolean
) => {
if (!viewportElement) return;
Expand All @@ -172,11 +178,6 @@ export const createScroller = (
cancelScroll();
}

const getTargetOffset = (): number => {
// Adjust if the offset is over the end, to get correct startIndex.
return clamp(getOffset(), 0, store._getMaxScrollOffset());
};

const waitForMeasurement = (): [Promise<void>, () => void] => {
// Wait for the scroll destination items to be measured.
// The measurement will be done asynchronously and the timing is not predictable so we use promise.
Expand Down Expand Up @@ -364,11 +365,13 @@ export const createWindowScroller = (
_observe(container) {
const scrollToKey = isHorizontal ? "scrollX" : "scrollY";

const documentRoot = getDocumentElement();
const documentBody = document.body;

const normalizeOffset = (offset: number, diff?: boolean): number => {
if (isHorizontal && isRTLDocument()) {
return normalizeRTLOffset(container, store, offset, diff);
}
return offset;
return isHorizontal
? normalizeHorizontalOffset(documentRoot, offset, diff)
: offset;
};

scrollObserver = createScrollObserver(
Expand All @@ -377,7 +380,7 @@ export const createWindowScroller = (
isHorizontal,
() =>
normalizeOffset(window[scrollToKey]) -
calcOffsetToViewport(container, document.body, isHorizontal),
calcOffsetToViewport(container, documentBody, isHorizontal),
(jump) => {
// TODO support case two window scrollers exist in the same view
window.scrollBy(
Expand Down
2 changes: 0 additions & 2 deletions src/core/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ export type VirtualStore = {
_getItemSize(index: number): number;
_getItemsLength(): number;
_getScrollOffset(): number;
_getMaxScrollOffset(): number;
_getScrollDirection(): ScrollDirection;
_getViewportSize(): number;
_getStartSpacerSize(): number;
Expand Down Expand Up @@ -265,7 +264,6 @@ export const createVirtualStore = (
_getScrollOffset() {
return scrollOffset;
},
_getMaxScrollOffset: getMaxScrollOffset,
_getScrollDirection() {
return _scrollDirection;
},
Expand Down

0 comments on commit 4f1511d

Please sign in to comment.