|
1 | 1 | <script>
|
| 2 | + import { tick } from 'svelte'; |
| 3 | +
|
2 | 4 | import { spring } from 'svelte/motion';
|
3 | 5 | import { derived, writable } from 'svelte/store';
|
4 | 6 |
|
|
9 | 11 | export let get;
|
10 | 12 | export let stiffness = 0.065;
|
11 | 13 | export let damping = 0.9;
|
| 14 | + export let useCache = true; |
| 15 | + export let idKey = undefined; |
12 | 16 |
|
13 | 17 | export const move = (amount) => {
|
14 | 18 | index = Math.max(0, Math.min(itemCount - 1, index + amount));
|
15 | 19 | };
|
16 | 20 |
|
| 21 | + const forceUpdate = writable(false); |
| 22 | + export const triggerUpdate = async () => { |
| 23 | + await tick(); |
| 24 | + forceUpdate.set(true); |
| 25 | + await tick(); |
| 26 | + forceUpdate.set(false); |
| 27 | + }; |
| 28 | +
|
17 | 29 | const getCached = (index) => $visibleData.find(({ index: i }) => i === index)?.data || get(index);
|
18 | 30 |
|
19 | 31 | let inRange = [-Infinity, Infinity];
|
20 | 32 | const initialized = writable(false);
|
21 | 33 | const dim = writable({ w: 0, h: 0 });
|
22 | 34 | const offset = spring(0, { stiffness, damping });
|
23 |
| -
|
24 | 35 | export const visibleData = derived(
|
25 |
| - [dim, offset, initialized], |
26 |
| - ([{ w, h }, $o, $initialized]) => { |
| 36 | + [dim, offset, initialized, forceUpdate], |
| 37 | + ([{ w, h }, $o, $initialized, $force]) => { |
27 | 38 | if (!w || !h || !$initialized) return [];
|
28 | 39 | if ($o < inRange[0] || $o > inRange[1]) return $visibleData;
|
| 40 | + const divisibleHeight = cellCount > 1 ? h + (cellCount - (h % cellCount)) : h; |
29 | 41 | const cellHeight = h / cellCount;
|
30 | 42 | const start = Math.max(-1, Math.floor((-1 * $o) / cellHeight) - 1);
|
31 | 43 | const baseOffset = $o % cellHeight;
|
|
35 | 47 | const index = i + start;
|
36 | 48 | const pos = baseOffset + (i - 1) * cellHeight;
|
37 | 49 | if (index < 0 || index >= itemCount) return undefined;
|
38 |
| - return { data: getCached(index), pos, index }; |
| 50 | + const data = $force || !useCache ? get(index) : getCached(index); |
| 51 | + return { data, pos, index }; |
39 | 52 | })
|
40 | 53 | .filter(Boolean);
|
41 | 54 | },
|
|
51 | 64 | $: gridStyle = `grid-template-${type}: repeat(${cellCount}, 1fr);`;
|
52 | 65 | $: {
|
53 | 66 | if ($dim.w && $dim.h) {
|
54 |
| - const newOffset = ($dim.h / cellCount) * index * -1; |
55 |
| - updateOffset(+newOffset.toFixed(3)); |
| 67 | + updateOffset(($dim.h / cellCount) * index * -1); |
56 | 68 | if (!$initialized) initialized.set(true);
|
57 | 69 | }
|
58 | 70 | }
|
59 | 71 | </script>
|
60 | 72 |
|
61 | 73 | <div class="grid" style={gridStyle} bind:clientHeight={$dim.h} bind:clientWidth={$dim.w}>
|
62 |
| - {#each $visibleData as obj (obj.index)} |
| 74 | + {#each $visibleData as obj (obj.data?.[idKey] || obj.index)} |
63 | 75 | <div style="transform: translateY({obj.pos}px)">
|
64 | 76 | <slot {...obj.data} index={obj.index} />
|
65 | 77 | </div>
|
|
0 commit comments