|
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