Skip to content

Commit

Permalink
feat: major rework
Browse files Browse the repository at this point in the history
  • Loading branch information
orefalo committed Oct 13, 2024
1 parent 111f758 commit 936bfd6
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 47 deletions.
38 changes: 13 additions & 25 deletions src/lib/VirtualList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
scrollToBehaviour?: SCROLL_BEHAVIOR;
// snippets
header?: Snippet;
slot: Snippet<[VirtualListModel<any>]>;
slot: Snippet<[VirtualListModel]>;
footer?: Snippet;
// events
onVisibleRangeUpdate?: (range: VirtualRangeEvent) => void;
Expand Down Expand Up @@ -135,7 +135,7 @@
let mounted: boolean = false;
let container: HTMLDivElement;
let visibleItems: Array<VirtualListModel<any>> = $state([]);
let visibleItems: Array<VirtualListModel> = $state([]);
let curState: VState = $state({
offset:
Expand Down Expand Up @@ -170,11 +170,17 @@
});
$effect(() => {
// listen to updates:
curState;
const { offset, scrollChangeReason } = curState;
// on update:
stateUpdated();
if (prevState.offset !== offset || prevState.scrollChangeReason !== scrollChangeReason) {
refresh();
}
if (prevState.offset !== offset && scrollChangeReason === SCROLL_CHANGE_REASON.REQUESTED) {
scrollTo(offset);
}
prevState = curState;
});
$effect(() => {
Expand Down Expand Up @@ -215,7 +221,7 @@
if (!mounted) return;
if (scrollToIndex && scrollOffset) {
console.log('VirtualList: scrollToIndex and scrollOffset shall not be used together.');
console.log('VirtualList: scrollToIndex and scrollOffset MUST NOT be used together.');
}
const scrollPropsHaveChanged =
Expand All @@ -228,7 +234,6 @@
if (itemPropsHaveChanged) {
sizeAndPositionManager.updateConfig(itemSize, modelCount, estimatedItemSize);
recomputeSizes();
}
Expand Down Expand Up @@ -259,23 +264,6 @@
};
}
// updates component state and triggers refresh or scrollto accotdingly
function stateUpdated() {
if (!mounted) return;
const { offset, scrollChangeReason } = curState;
if (prevState.offset !== offset || prevState.scrollChangeReason !== scrollChangeReason) {
refresh();
}
if (prevState.offset !== offset && scrollChangeReason === SCROLL_CHANGE_REASON.REQUESTED) {
scrollTo(offset);
}
prevState = curState;
}
function refresh() {
const { offset } = curState;
let { start, end } = sizeAndPositionManager.getVisibleRange(
Expand Down
92 changes: 80 additions & 12 deletions src/lib/VirtualList2.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -105,21 +105,42 @@
style?: string;
} = $props();
enum SCROLL_CHANGE_REASON {
OBSERVED = 0,
REQUESTED = 1
}
interface VState {
offset: number;
scrollChangeReason: number;
}
let mounted: boolean = false;
let listContainer: HTMLDivElement;
// svelte-ignore non_reactive_update
let listInner: HTMLDivElement;
let clientHeight: number = $state(0);
let clientWidth: number = $state(0);
let buffer: number = 100;
let prevScroll: number;
// let prevScroll: number;
let itemKey: 'index' | ((item: any, index: number) => any);
let start = $state(0);
let end = $state(firstRender - 1);
let avgSize = $state(0);
let curState: VState = $state({
offset:
scrollOffset ||
(scrollToIndex !== undefined /*&& modelCount && getOffsetForIndex(scrollToIndex)*/ && 1) ||
0,
scrollChangeReason: SCROLL_CHANGE_REASON.REQUESTED
});
let prevState: VState | undefined;
const end2 = $derived.by(() => {
const max = (items?.length || 1) - 1;
return end < max ? end : max;
Expand Down Expand Up @@ -158,7 +179,7 @@
onMount(() => {
listContainer.addEventListener('scroll', onscroll, thirdEventArg);
mounted = true;
update();
updatePositions();
});
onDestroy(() => {
Expand Down Expand Up @@ -192,21 +213,55 @@
)
);
//TODO see if effect.pre not a better option
$effect(() => {
// items, clientWidth, clientHeight;
update();
const { offset, scrollChangeReason } = curState;
if (prevState?.offset !== offset || prevState?.scrollChangeReason !== scrollChangeReason) {
// refresh();
updatePositions();
}
if (prevState?.offset !== offset && scrollChangeReason === SCROLL_CHANGE_REASON.REQUESTED) {
scrollTo(offset);
}
prevState = curState;
});
function onscroll() {
// tracks the scroll position
const currentScroll = getScroll(listContainer);
if (prevScroll != null && buffer - Math.abs(currentScroll - prevScroll) >= 10) {
function onscroll(event: Event) {
const offset = getScroll(listContainer);
if (
offset < 0 ||
curState.offset === offset ||
event.target !== listContainer ||
buffer - Math.abs(offset - curState.offset) >= 1
)
return;
curState = {
offset,
scrollChangeReason: SCROLL_CHANGE_REASON.OBSERVED
};
if (onAfterScroll) {
onAfterScroll({ type: 'scroll.update', offset, event });
}
prevScroll = currentScroll;
update();
// updatePositions();
}
// function onscroll() {
// // tracks the scroll position
// const currentScroll = getScroll(listContainer);
// if (prevScroll != null && buffer - Math.abs(currentScroll - prevScroll) >= 10) {
// return;
// }
// prevScroll = currentScroll;
// updatePositions();
// }
function getStart() {
const startPosition = getScroll(listContainer) - getPaddingStart(listContainer) - buffer;
const r = binarySearch(positions, mid => mid - startPosition, {
Expand All @@ -225,7 +280,8 @@
return r.index;
}
function update() {
function updatePositions() {
console.log('updatePositions');
if (!avgSize) {
avgSize = getAvgSize();
}
Expand Down Expand Up @@ -330,6 +386,19 @@
return !isHorizontal ? parseFloat(style.paddingTop) : parseFloat(style.paddingLeft);
}
// scrolls the contrainer to
// TODO: How is this going to work with the onscoll hook?
function scrollTo(value: number) {
if ('scroll' in listContainer) {
const p: Record<string, any> = { behavior: scrollToBehaviour };
p[!isHorizontal ? 'top' : 'left'] = value;
listContainer.scroll(p);
} else {
//@ts-expect-error no index signature
listContainer[!isHorizontal ? scrollTop : scrollLeft] = value;

Check failure on line 398 in src/lib/VirtualList2.svelte

View workflow job for this annotation

GitHub Actions / tests

'scrollTop' is not defined

Check failure on line 398 in src/lib/VirtualList2.svelte

View workflow job for this annotation

GitHub Actions / tests

'scrollLeft' is not defined
}
}
function getItemKey(item: any, index: number) {

Check warning on line 402 in src/lib/VirtualList2.svelte

View workflow job for this annotation

GitHub Actions / tests

'getItemKey' is defined but never used. Allowed unused vars must match /^_/u
if (itemKey) {
if (/*typeof itemKey === 'string' &&*/ itemKey === 'index') {
Expand All @@ -352,7 +421,6 @@
{#if header}
{@render header()}
{/if}
<!-- svelte-ignore node_invalid_placement_ssr -->
<tbody>
{#if isDisabled}
{#each items as item, index}
Expand Down
3 changes: 2 additions & 1 deletion src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@
{ title: 'Table', path: '/examples/table' },
{ title: 'Variable Sizing', path: '/examples/variablesizing' },
{ title: 'Positioning', path: '/examples/positioning' },
{ title: 'OLDPositioning', path: '/examples/positioning2' },
{ title: 'Partial Loader', path: '/examples/partialloader' },
{ title: 'Events', path: '/examples/events' },
{ title: 'Events', path: '/examples/events' }
]
}
];
Expand Down
2 changes: 1 addition & 1 deletion src/routes/examples/horizontal/code.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import VirtualList from '$lib/VirtualList2.svelte';
const myModel = new Array(10000).fill(1).map((v, i) => {
return { text: 'ITEM ' + i +' - Item ' + i };
return { text: 'ITEM ' + i + ' - Item ' + i };
});
</script>

Expand Down
5 changes: 3 additions & 2 deletions src/routes/examples/positioning/code.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,9 @@
{scrollToBehaviour}
onVisibleRangeUpdate={handleMessage}>
{#snippet vl_slot({ item, index })}
<div style="border: 1px solid rgb(204, 204, 204); line-height: {rowHeights(item, index)}px;" class:highlighted={index === scrollToIndex}>
<div
style="border: 1px solid rgb(204, 204, 204); line-height: {rowHeights(item, index)}px;"
class:highlighted={index === scrollToIndex}>
{item.text}
</div>
{/snippet}
Expand All @@ -155,7 +157,6 @@
</div>

<style>
.highlighted {
background: #efefef;
}
Expand Down
4 changes: 2 additions & 2 deletions src/routes/examples/variablesizing/code.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
rowHeights = (item: any, index: number) => 25;
}
randomize()
randomize();
</script>

<h2>Horizontal</h2>
Expand All @@ -32,7 +32,7 @@

<VirtualList items={myModel} style="height:600px">
{#snippet vl_slot({ item, index })}
<div style="border: 1px solid rgb(204, 204, 204); line-height: {rowHeights(item,index)}px;">
<div style="border: 1px solid rgb(204, 204, 204); line-height: {rowHeights(item, index)}px;">
{item.text}
</div>
{/snippet}
Expand Down
5 changes: 1 addition & 4 deletions src/routes/examples/vertical/code.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@
import VirtualList from '$lib/VirtualList2.svelte';
const myModel = new Array(10000).fill(1).map((v, i) => {
return { text: 'ITEM ' + i +' - Item ' + i };
return { text: 'ITEM ' + i + ' - Item ' + i };
});
console.log(myModel);
// let itemSize = () => 25;
</script>

<VirtualList items={myModel} style="height:600px">
Expand Down

0 comments on commit 936bfd6

Please sign in to comment.