-
-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WindowScroller imperative scrolling #540
base: main
Are you sure you want to change the base?
WindowScroller imperative scrolling #540
Conversation
That issue was requesting a two-dimensional windowscroller with imperative scrolling--which you said presents problems. This PR doesn't solve that problem but currently there's not even a one dimensional window scroller with imperative scrolling, so this is surely an improvement? (If you're likely to merge I'll fix the errors) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, could you add some e2e tests for scrollToIndex like this?
Lines 596 to 868 in 231fb7e
test.describe("check if scrollToIndex works", () => { | |
test.beforeEach(async ({ page }) => { | |
await page.goto(storyUrl("basics-vlist--scroll-to")); | |
}); | |
test.describe("align start", () => { | |
test("mid", async ({ page }) => { | |
const component = await getScrollable(page); | |
await component.waitForElementState("stable"); | |
// check if start is displayed | |
await expect((await getFirstItem(component)).text).toEqual("0"); | |
const button = page.getByRole("button", { name: "scroll to index" }); | |
const input = await button.evaluateHandle( | |
(el) => el.previousSibling as HTMLInputElement | |
); | |
await clearInput(input); | |
await input.fill("700"); | |
await button.click(); | |
await component.waitForElementState("stable"); | |
// Check if scrolled precisely | |
const firstItem = await getFirstItem(component); | |
await expect(firstItem.text).toEqual("700"); | |
await expect(firstItem.top).toEqual(0); | |
// Check if unnecessary items are not rendered | |
await expect(await component.innerText()).not.toContain("650"); | |
await expect(await component.innerText()).not.toContain("750"); | |
}); | |
test("start", async ({ page }) => { | |
const component = await getScrollable(page); | |
await component.waitForElementState("stable"); | |
// check if start is displayed | |
await expect((await getFirstItem(component)).text).toEqual("0"); | |
const button = page.getByRole("button", { name: "scroll to index" }); | |
const input = await button.evaluateHandle( | |
(el) => el.previousSibling as HTMLInputElement | |
); | |
await clearInput(input); | |
await input.fill("500"); | |
await button.click(); | |
await component.waitForElementState("stable"); | |
await expect(await component.innerText()).toContain("500"); | |
await clearInput(input); | |
await input.fill("0"); | |
await button.click(); | |
await component.waitForElementState("stable"); | |
// Check if scrolled precisely | |
const firstItem = await getFirstItem(component); | |
await expect(firstItem.text).toEqual("0"); | |
await expect(firstItem.top).toEqual(0); | |
// Check if unnecessary items are not rendered | |
await expect(await component.innerText()).not.toContain("50\n"); | |
}); | |
test("end", async ({ page }) => { | |
const component = await getScrollable(page); | |
await component.waitForElementState("stable"); | |
// check if start is displayed | |
await expect((await getFirstItem(component)).text).toEqual("0"); | |
const button = page.getByRole("button", { name: "scroll to index" }); | |
const input = await button.evaluateHandle( | |
(el) => el.previousSibling as HTMLInputElement | |
); | |
await clearInput(input); | |
await input.fill("999"); | |
await button.click(); | |
await component.waitForElementState("stable"); | |
// Check if scrolled precisely | |
const lastItem = await getLastItem(component); | |
await expect(lastItem.text).toEqual("999"); | |
expectInRange(lastItem.bottom, { min: -0.9, max: 1 }); | |
// Check if unnecessary items are not rendered | |
await expect(await component.innerText()).not.toContain("949"); | |
}); | |
test("mid smooth", async ({ page, browserName }) => { | |
const component = await getScrollable(page); | |
await component.waitForElementState("stable"); | |
// check if start is displayed | |
await expect((await getFirstItem(component)).text).toEqual("0"); | |
await page.getByRole("checkbox", { name: "smooth" }).click(); | |
const button = page.getByRole("button", { name: "scroll to index" }); | |
const input = await button.evaluateHandle( | |
(el) => el.previousSibling as HTMLInputElement | |
); | |
const scrollListener = listenScrollCount(component); | |
await clearInput(input); | |
await input.fill("700"); | |
await button.click(); | |
await page.waitForTimeout(500); | |
const called = await scrollListener; | |
// Check if this is smooth scrolling | |
await expect(called).toBeGreaterThanOrEqual( | |
// TODO find better way to check in webkit | |
browserName === "webkit" ? 2 : 10 | |
); | |
// Check if scrolled precisely | |
const firstItem = await getFirstItem(component); | |
await expect(firstItem.text).toEqual("700"); | |
expectInRange(firstItem.top, { min: 0, max: 1 }); | |
// Check if unnecessary items are not rendered | |
await expect(await component.innerText()).not.toContain("650"); | |
await expect(await component.innerText()).not.toContain("750"); | |
}); | |
}); | |
test.describe("align end", () => { | |
test.beforeEach(async ({ page }) => { | |
await page.getByRole("radio", { name: "end" }).click(); | |
}); | |
test("mid", async ({ page }) => { | |
const component = await getScrollable(page); | |
await component.waitForElementState("stable"); | |
// check if start is displayed | |
await expect((await getFirstItem(component)).text).toEqual("0"); | |
const button = page.getByRole("button", { name: "scroll to index" }); | |
const input = await button.evaluateHandle( | |
(el) => el.previousSibling as HTMLInputElement | |
); | |
await clearInput(input); | |
await input.fill("700"); | |
await button.click(); | |
await component.waitForElementState("stable"); | |
// Check if scrolled precisely | |
const lastItem = await getLastItem(component); | |
await expect(lastItem.text).toEqual("700"); | |
expectInRange(lastItem.bottom, { min: 0, max: 1 }); | |
// Check if unnecessary items are not rendered | |
await expect(await component.innerText()).not.toContain("650"); | |
await expect(await component.innerText()).not.toContain("750"); | |
}); | |
test("start", async ({ page }) => { | |
const component = await getScrollable(page); | |
await component.waitForElementState("stable"); | |
// check if start is displayed | |
await expect((await getFirstItem(component)).text).toEqual("0"); | |
const button = page.getByRole("button", { name: "scroll to index" }); | |
const input = await button.evaluateHandle( | |
(el) => el.previousSibling as HTMLInputElement | |
); | |
await clearInput(input); | |
await input.fill("500"); | |
await button.click(); | |
await component.waitForElementState("stable"); | |
await expect(await component.innerText()).toContain("500"); | |
await clearInput(input); | |
await input.fill("0"); | |
await button.click(); | |
await component.waitForElementState("stable"); | |
// Check if scrolled precisely | |
const firstItem = await getFirstItem(component); | |
await expect(firstItem.text).toEqual("0"); | |
await expect(firstItem.top).toEqual(0); | |
// Check if unnecessary items are not rendered | |
await expect(await component.innerText()).not.toContain("50\n"); | |
}); | |
test("end", async ({ page }) => { | |
const component = await getScrollable(page); | |
await component.waitForElementState("stable"); | |
// check if start is displayed | |
await expect((await getFirstItem(component)).text).toEqual("0"); | |
const button = page.getByRole("button", { name: "scroll to index" }); | |
const input = await button.evaluateHandle( | |
(el) => el.previousSibling as HTMLInputElement | |
); | |
await clearInput(input); | |
await input.fill("999"); | |
await button.click(); | |
await component.waitForElementState("stable"); | |
// Check if scrolled precisely | |
const lastItem = await getLastItem(component); | |
await expect(lastItem.text).toEqual("999"); | |
expectInRange(lastItem.bottom, { min: 0, max: 1 }); | |
// Check if unnecessary items are not rendered | |
await expect(await component.innerText()).not.toContain("949"); | |
}); | |
test("mid smooth", async ({ page, browserName }) => { | |
const component = await getScrollable(page); | |
await component.waitForElementState("stable"); | |
// check if start is displayed | |
await expect((await getFirstItem(component)).text).toEqual("0"); | |
await page.getByRole("checkbox", { name: "smooth" }).click(); | |
const button = page.getByRole("button", { name: "scroll to index" }); | |
const input = await button.evaluateHandle( | |
(el) => el.previousSibling as HTMLInputElement | |
); | |
const scrollListener = listenScrollCount(component); | |
await clearInput(input); | |
await input.fill("700"); | |
await button.click(); | |
await page.waitForTimeout(500); | |
const called = await scrollListener; | |
// Check if this is smooth scrolling | |
await expect(called).toBeGreaterThanOrEqual( | |
// TODO find better way to check in webkit | |
browserName === "webkit" ? 2 : 10 | |
); | |
// Check if scrolled precisely | |
const lastItem = await getLastItem(component); | |
await expect(lastItem.text).toEqual("700"); | |
expectInRange(lastItem.bottom, { min: 0, max: 1 }); | |
// Check if unnecessary items are not rendered | |
await expect(await component.innerText()).not.toContain("650"); | |
await expect(await component.innerText()).not.toContain("750"); | |
}); | |
}); | |
}); |
/** | ||
* If you put an element before virtualizer, you have to define its height with this prop. | ||
*/ | ||
startMargin: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This prop is not required by WindowVirtualizer, because it is automatically calculated from DOM.
/** | |
* If you put an element before virtualizer, you have to define its height with this prop. | |
*/ | |
startMargin: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seemed like this was necessary, as in, without it my scrolls were off, but I might have been confused. will check.
Co-authored-by: inokawa <[email protected]>
Adds imperative scrolling api to WindowScroller. Only react bindings implemented, also no tests written.