{#if isShowDeleteConfirmation}
(isShowDeleteConfirmation = false)}
onConfirm={() => handlePromiseError(trashOrDelete(true))}
/>
{/if}
{#if showShortcuts}
(showShortcuts = !showShortcuts)} />
{/if}
{#if $assetStore.buckets.length > 0}
{/if}
{
if (!largeBucketMode && assetStore.maxBucketAssets >= LARGE_BUCKET_THRESHOLD) {
largeBucketMode = true;
// Each viewport update causes each asset to re-decode both the thumbhash and the thumbnail.
// This is because the thumbnail components are destroyed and re-mounted, possibly because of the intersection observer.
// For larger buckets, this can lead to freezing and a poor user experience.
// As a mitigation, we aggressively debounce the viewport update to reduce the number of these events.
updateViewport = debounce(() => $assetStore.updateViewport(safeViewport), LARGE_BUCKET_DEBOUNCE_MS, {
leading: false,
trailing: true,
});
}
safeViewport = { width, height, x: safeViewport.x, y: safeViewport.y };
void updateViewport();
}}
bind:this={element}
onscroll={() => ((assetStore.lastScrollTime = Date.now()), handleTimelineScroll())}
>
((topSectionHeight = height), (topSectionOffset = target.offsetTop))}
class:invisible={showSkeleton}
>
{@render children?.()}
{#if isEmpty}
{@render empty?.()}
{/if}
{#each $assetStore.buckets as bucket (bucket.viewId)}
{@const isPremeasure = preMeasure.includes(bucket)}
{@const display = bucket.intersecting || bucket === $assetStore.pendingScrollBucket || isPremeasure}