-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add new option
infiniteScroll
auto-scroll back to top (#224)
- when reaching the end of the list, it will automatically reset it back to the top of the list - the scroll can also be activated by using arrow down (highlight) to scroll 1 item at a time - this is not to be confused with Virtual Scroll which is similar but only renders a subset of large collection until we reach the end at which point it will stop, however the infinite scroll never stops (at least not until the user stops scrolling)
- Loading branch information
1 parent
764aedc
commit fb74e74
Showing
9 changed files
with
201 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<div class="row mb-2"> | ||
<div class="col-md-12 title-desc"> | ||
<h2 class="bd-title"> | ||
Infinite Scroll | ||
<span class="float-end links"> | ||
Code <span class="fa fa-link"></span> | ||
<span class="small"> | ||
<a | ||
target="_blank" | ||
href="https://github.com/ghiscoding/multiple-select-vanilla/blob/main/packages/demo/src/options/options36.html" | ||
>html</a | ||
> | ||
| | ||
<a target="_blank" href="https://github.com/ghiscoding/multiple-select-vanilla/blob/main/packages/demo/src/options/options36.ts" | ||
>ts</a | ||
> | ||
</span> | ||
</span> | ||
</h2> | ||
<div class="demo-subtitle"> | ||
Enabling <code>infiniteScroll</code> will automatically scroll back to the top whenever reaching the end of the list (scrolling through either the mouse and/or arrow down). Note that this is not to be confused | ||
with Virtual Scroll which itself is enabled by default whenever the list is bigger than 200 items (the last list select below does use Virtual Scroll) | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<div> | ||
<div class="mb-3 row"> | ||
<label class="col-sm-2"> | ||
Short List (25) | ||
</label> | ||
|
||
<div class="col-sm-10"> | ||
<select data-test="select1" id="select1" class="full-width"></select> | ||
</div> | ||
</div> | ||
|
||
<div class="mb-3 row"> | ||
<label class="col-sm-2 col-form-label">Large List (2,000)</label> | ||
|
||
<div class="col-sm-10"> | ||
<select multiple="multiple" data-test="select2" id="select2" class="full-width"></select> | ||
</div> | ||
</div> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { type MultipleSelectInstance, multipleSelect } from 'multiple-select-vanilla'; | ||
|
||
export default class Example { | ||
ms1?: MultipleSelectInstance; | ||
ms2?: MultipleSelectInstance; | ||
|
||
mount() { | ||
const data1 = []; | ||
const data2 = []; | ||
for (let i = 0; i < 25; i++) { | ||
data1.push({ text: `Title ${i}`, value: i }); | ||
} | ||
for (let i = 0; i < 2000; i++) { | ||
data2.push({ text: `<i class="fa fa-star"></i> Task ${i}`, value: i }); | ||
} | ||
|
||
this.ms1 = multipleSelect('#select1', { | ||
data: data1, | ||
infiniteScroll: true, | ||
}) as MultipleSelectInstance; | ||
|
||
this.ms2 = multipleSelect('#select2', { | ||
filter: true, | ||
data: data2, | ||
showSearchClear: true, | ||
useSelectOptionLabelToHtml: true, | ||
infiniteScroll: true, | ||
}) as MultipleSelectInstance; | ||
} | ||
|
||
unmount() { | ||
// destroy ms instance(s) to avoid DOM leaks | ||
this.ms1?.destroy(); | ||
this.ms2?.destroy(); | ||
this.ms1 = undefined; | ||
this.ms2 = undefined; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { test, expect } from '@playwright/test'; | ||
|
||
test.describe('Options 36 - Infinite Scroll', () => { | ||
test('select should use infinite scroll', async ({ page }) => { | ||
await page.goto('#/options36'); | ||
|
||
// -- 1st Select | ||
await page.locator('[data-test="select1"].ms-parent').click(); | ||
|
||
const ulElm1 = await page.locator('[data-test="select1"] .ms-drop ul'); | ||
const liElms1 = await page.locator('[data-test="select1"] .ms-drop ul li'); | ||
await expect(liElms1.nth(0)).toContainText('Title 0'); | ||
await liElms1.nth(0).click(); | ||
await expect(page.locator('[data-test=select1].ms-parent .ms-choice span')).toHaveText('Title 0'); | ||
|
||
// scroll near the end of the list | ||
await page.locator('[data-test="select1"].ms-parent').click(); | ||
await ulElm1.evaluate(e => (e.scrollTop = e.scrollHeight - 10)); | ||
await page.locator('[data-test="select1"] .ms-drop label').filter({ hasText: 'Title 24' }).click(); | ||
|
||
// scroll completely to the end of the list & expect scrolling back to top | ||
await page.locator('[data-test="select1"].ms-parent').click(); | ||
await ulElm1.evaluate(e => (e.scrollTop = e.scrollHeight)); | ||
const firstTitleLoc = await page.locator('div[data-test=select1] .ms-drop li:nth-of-type(1)'); | ||
await expect(firstTitleLoc).toContainText('Title 0'); | ||
await expect(firstTitleLoc).toHaveClass('hide-radio highlighted'); | ||
await page.keyboard.press('Enter'); | ||
|
||
// -- 2nd Select | ||
await page.locator('[data-test=select2].ms-parent').click(); | ||
const ulElm2 = await page.locator('[data-test="select2"] .ms-drop ul'); | ||
const liElms2 = await page.locator('[data-test="select2"] .ms-drop ul li'); | ||
await expect(await liElms2.nth(4).locator('span').innerHTML()).toBe('<i class="fa fa-star"></i> Task 4'); | ||
await liElms2.nth(4).click(); | ||
await expect(await liElms2.nth(5).locator('span').innerHTML()).toBe('<i class="fa fa-star"></i> Task 5'); | ||
await liElms2.nth(5).click(); | ||
await page.getByRole('button', { name: '4, 5' }).click(); | ||
|
||
// scroll to the middle and click 1003 | ||
await page.locator('[data-test="select2"].ms-parent').click(); | ||
await ulElm2.evaluate(e => (e.scrollTop = e.scrollHeight / 2)); | ||
await page.locator('[data-test="select2"] .ms-drop label').filter({ hasText: '1003' }).click(); | ||
await page.getByRole('button', { name: '4, 5, 1003' }); | ||
|
||
// scroll to near the end and select last 2 labels | ||
await ulElm2.evaluate(e => (e.scrollTop = e.scrollHeight - 300)); | ||
await expect(await page.locator('[data-test="select2"] .ms-drop li[data-key=option_1995] label span').innerHTML()).toBe( | ||
'<i class="fa fa-star"></i> Task 1995', | ||
); | ||
await expect(await page.locator('[data-test="select2"] .ms-drop li[data-key=option_1996] label span').innerHTML()).toBe( | ||
'<i class="fa fa-star"></i> Task 1996', | ||
); | ||
await page.locator('[data-test="select2"] .ms-drop label').filter({ hasText: '1995' }).click(); | ||
await page.locator('[data-test="select2"] .ms-drop label').filter({ hasText: '1996' }).click(); | ||
await page.getByRole('button', { name: '5 of 2000 selected' }); | ||
|
||
// pressing arrow down until we reach the end will scroll back to top of the list | ||
page.keyboard.press('ArrowDown'); | ||
page.keyboard.press('ArrowDown'); | ||
page.keyboard.press('ArrowDown'); | ||
await expect(await page.locator('[data-test="select2"] .ms-drop li[data-key=option_1999]')).toHaveClass('highlighted'); | ||
|
||
page.keyboard.press('ArrowDown'); // Task 0 (scrolled back to top) | ||
|
||
const firstTaskLoc = await page.locator('div[data-test=select2] .ms-drop li:nth-of-type(1)'); | ||
await expect(firstTaskLoc).toContainText('Task 0'); | ||
// await expect(await page.locator('[data-test="select2"] .ms-drop li[data-key=option_0]')).toHaveClass('highlighted'); | ||
}); | ||
}); |