From 3563d2c51c84115f48b62e8e897b964e2503432c Mon Sep 17 00:00:00 2001 From: midzelis Date: Sat, 14 Mar 2026 14:08:41 +0000 Subject: [PATCH] refactor(web): rename intersecting/actuallyIntersecting to nearby/intersecting Change-Id: Id6f63247441fe290e7732e489f73e8c16a6a6964 --- .../assets/thumbnail/thumbnail.svelte | 6 +- .../gallery-viewer/gallery-viewer.svelte | 10 +- .../components/timeline/AssetLayout.svelte | 13 +-- web/src/lib/components/timeline/Month.svelte | 14 +-- .../lib/components/timeline/Timeline.svelte | 8 +- .../timeline-manager/day-group.svelte.ts | 4 +- .../intersection-support.svelte.spec.ts | 80 +++++++++++--- .../internal/intersection-support.svelte.ts | 102 +++++++++--------- .../timeline-manager/month-group.svelte.ts | 23 ++-- .../timeline-manager.svelte.ts | 2 +- .../managers/timeline-manager/utils.svelte.ts | 4 + .../timeline-manager/viewer-asset.svelte.ts | 17 +-- 12 files changed, 170 insertions(+), 113 deletions(-) diff --git a/web/src/lib/components/assets/thumbnail/thumbnail.svelte b/web/src/lib/components/assets/thumbnail/thumbnail.svelte index d3e2a1ec18..6aa72dba74 100644 --- a/web/src/lib/components/assets/thumbnail/thumbnail.svelte +++ b/web/src/lib/components/assets/thumbnail/thumbnail.svelte @@ -34,7 +34,7 @@ thumbnailSize?: number; thumbnailWidth?: number; thumbnailHeight?: number; - actuallyIntersecting?: boolean; + intersecting?: boolean; selected?: boolean; selectionCandidate?: boolean; disabled?: boolean; @@ -57,7 +57,7 @@ thumbnailSize = undefined, thumbnailWidth = undefined, thumbnailHeight = undefined, - actuallyIntersecting = true, + intersecting = true, selected = false, selectionCandidate = false, disabled = false, @@ -89,7 +89,7 @@ $effect(() => { if (loaded && !loadedEffectRan) { loadedEffectRan = true; - if (!actuallyIntersecting) { + if (!intersecting) { skipFade = true; } } diff --git a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte index 713e09976f..badf6d3557 100644 --- a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte +++ b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte @@ -14,7 +14,6 @@ import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { showDeleteModal } from '$lib/stores/preferences.store'; import { handlePromiseError } from '$lib/utils'; - import { TUNABLES } from '$lib/utils/tunables'; import { deleteAssets } from '$lib/utils/actions'; import { archiveAssets, @@ -28,6 +27,7 @@ import { getJustifiedLayoutFromAssets } from '$lib/utils/layout-utils'; import { navigate } from '$lib/utils/navigation'; import { isTimelineAsset, toTimelineAsset } from '$lib/utils/timeline-util'; + import { TUNABLES } from '$lib/utils/tunables'; import { AssetVisibility, type AssetResponseDto } from '@immich/sdk'; import { modalManager } from '@immich/ui'; import { debounce } from 'lodash-es'; @@ -82,14 +82,14 @@ return `top: ${geo.getTop(i)}px; left: ${geo.getLeft(i)}px; width: ${geo.getWidth(i)}px; height: ${geo.getHeight(i)}px;`; }; - const isIntersecting = (i: number) => { + const isRenderable = (i: number) => { const geo = geometry; const window = slidingWindow; const top = geo.getTop(i); return top + pageHeaderOffset < window.bottom && top + geo.getHeight(i) > window.top; }; - const isActuallyIntersecting = (i: number) => { + const isIntersecting = (i: number) => { const geo = geometry; const top = geo.getTop(i) + pageHeaderOffset; const bottom = top + geo.getHeight(i); @@ -387,7 +387,7 @@ style:width={geometry.containerWidth + 'px'} > {#each assets as asset, i (asset.id + '-' + i)} - {#if isIntersecting(i)} + {#if isRenderable(i)} {@const currentAsset = toTimelineAsset(asset)}
diff --git a/web/src/lib/components/timeline/AssetLayout.svelte b/web/src/lib/components/timeline/AssetLayout.svelte index cf4090bc1f..c80ac01760 100644 --- a/web/src/lib/components/timeline/AssetLayout.svelte +++ b/web/src/lib/components/timeline/AssetLayout.svelte @@ -1,5 +1,6 @@
- {#each filterIntersecting(viewerAssets) as viewerAsset (viewerAsset.id)} + {#each filterRenderable(viewerAssets) as viewerAsset (viewerAsset.id)} {@const position = viewerAsset.position!} {@const asset = viewerAsset.asset!} - {@const actuallyIntersecting = viewerAsset.actuallyIntersecting!} + {@const intersecting = viewerAsset.intersecting!}
- {@render thumbnail({ asset, position, actuallyIntersecting })} + {@render thumbnail({ asset, position, intersecting })} {@render customThumbnailLayout?.(asset)}
{/each} diff --git a/web/src/lib/components/timeline/Month.svelte b/web/src/lib/components/timeline/Month.svelte index b6c4e50a1e..013d620df1 100644 --- a/web/src/lib/components/timeline/Month.svelte +++ b/web/src/lib/components/timeline/Month.svelte @@ -3,7 +3,7 @@ import { DayGroup } from '$lib/managers/timeline-manager/day-group.svelte'; import type { MonthGroup } from '$lib/managers/timeline-manager/month-group.svelte'; import type { TimelineAsset } from '$lib/managers/timeline-manager/types'; - import { assetsSnapshot } from '$lib/managers/timeline-manager/utils.svelte'; + import { assetsSnapshot, filterRenderable } from '$lib/managers/timeline-manager/utils.svelte'; import type { VirtualScrollManager } from '$lib/managers/VirtualScrollManager/VirtualScrollManager.svelte'; import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; import { uploadAssetsStore } from '$lib/stores/upload'; @@ -21,7 +21,7 @@ position: CommonPosition; dayGroup: DayGroup; groupIndex: number; - actuallyIntersecting: boolean; + intersecting: boolean; }, ] >; @@ -47,10 +47,6 @@ const transitionDuration = $derived(monthGroup.timelineManager.suspendTransitions && !$isUploading ? 0 : 150); - const filterIntersecting = (intersectables: T[]) => { - return intersectables.filter(({ intersecting }) => intersecting); - }; - const getDayGroupFullDate = (dayGroup: DayGroup): string => { const { month, year } = dayGroup.monthGroup.yearMonth; const date = fromTimelinePlainDate({ @@ -62,7 +58,7 @@ }; -{#each filterIntersecting(monthGroup.dayGroups) as dayGroup, groupIndex (dayGroup.day)} +{#each filterRenderable(monthGroup.dayGroups) as dayGroup, groupIndex (dayGroup.day)} {@const isDayGroupSelected = assetInteraction.selectedGroup.has(dayGroup.groupTitle)}
- {#snippet thumbnail({ asset, position, actuallyIntersecting })} - {@render thumbnailWithGroup({ asset, position, dayGroup, groupIndex, actuallyIntersecting })} + {#snippet thumbnail({ asset, position, intersecting })} + {@render thumbnailWithGroup({ asset, position, dayGroup, groupIndex, intersecting })} {/snippet}
diff --git a/web/src/lib/components/timeline/Timeline.svelte b/web/src/lib/components/timeline/Timeline.svelte index cafd867295..431034492f 100644 --- a/web/src/lib/components/timeline/Timeline.svelte +++ b/web/src/lib/components/timeline/Timeline.svelte @@ -645,7 +645,7 @@ {#each timelineManager.months as monthGroup (monthGroup.viewId)} - {@const display = monthGroup.intersecting} + {@const renderable = monthGroup.renderable} {@const absoluteHeight = monthGroup.top} {#if !monthGroup.isLoaded} @@ -657,7 +657,7 @@ >
- {:else if display} + {:else if renderable}
- {#snippet thumbnail({ asset, position, dayGroup, groupIndex, actuallyIntersecting })} + {#snippet thumbnail({ asset, position, dayGroup, groupIndex, intersecting })} {@const isAssetSelectionCandidate = assetInteraction.hasSelectionCandidate(asset.id)} {@const isAssetSelected = assetInteraction.hasSelectedAsset(asset.id) || timelineManager.albumAssets.has(asset.id)} @@ -684,7 +684,7 @@ {asset} {albumUsers} {groupIndex} - {actuallyIntersecting} + {intersecting} onClick={(asset) => { if (typeof onThumbnailClick === 'function') { onThumbnailClick(asset, timelineManager, dayGroup, _onClick); diff --git a/web/src/lib/managers/timeline-manager/day-group.svelte.ts b/web/src/lib/managers/timeline-manager/day-group.svelte.ts index 75793f598e..f331613e68 100644 --- a/web/src/lib/managers/timeline-manager/day-group.svelte.ts +++ b/web/src/lib/managers/timeline-manager/day-group.svelte.ts @@ -18,7 +18,7 @@ export class DayGroup { height = $state(0); width = $state(0); - intersecting = $derived.by(() => this.viewerAssets.some((viewAsset) => viewAsset.intersecting)); + renderable = $derived.by(() => this.viewerAssets.some((viewAsset) => viewAsset.renderable)); #top: number = $state(0); #start: number = $state(0); @@ -137,7 +137,7 @@ export class DayGroup { } layout(options: CommonLayoutOptions, noDefer: boolean) { - if (!noDefer && !this.monthGroup.intersecting && !this.monthGroup.timelineManager.isScrollingOnLoad) { + if (!noDefer && !this.monthGroup.renderable && !this.monthGroup.timelineManager.isScrollingOnLoad) { this.#deferredLayout = true; return; } diff --git a/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.spec.ts b/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.spec.ts index 4b2a7aa460..dd7699cfe1 100644 --- a/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.spec.ts +++ b/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.spec.ts @@ -1,6 +1,12 @@ import { describe, expect, it } from 'vitest'; import type { TimelineManager } from '../timeline-manager.svelte'; -import { Intersection, calculateViewerAssetIntersecting, isIntersecting } from './intersection-support.svelte'; +import { + IntersectionFlags, + calculateViewerAssetIntersecting, + isIntersecting, + isRenderable, + isVisible, +} from './intersection-support.svelte'; function createMockTimelineManager(windowTop: number, windowBottom: number, headerHeight: number = 0): TimelineManager { return { @@ -51,45 +57,87 @@ describe('calculateViewerAssetIntersecting', () => { // viewport 0-1000, no header, default expand margins 500/500 const manager = createMockTimelineManager(0, 1000); - it('should return ACTUAL when asset is within viewport', () => { - expect(calculateViewerAssetIntersecting(manager, 100, 50)).toBe(Intersection.ACTUAL); + it('should return VISIBLE when asset is within viewport', () => { + expect(calculateViewerAssetIntersecting(manager, 100, 50)).toBe(IntersectionFlags.VISIBLE); }); - it('should return ACTUAL when asset is at viewport top edge', () => { - expect(calculateViewerAssetIntersecting(manager, 0, 50)).toBe(Intersection.ACTUAL); + it('should return VISIBLE when asset is at viewport top edge', () => { + expect(calculateViewerAssetIntersecting(manager, 0, 50)).toBe(IntersectionFlags.VISIBLE); }); - it('should return ACTUAL when asset partially overlaps viewport bottom', () => { - expect(calculateViewerAssetIntersecting(manager, 980, 50)).toBe(Intersection.ACTUAL); + it('should return VISIBLE when asset partially overlaps viewport bottom', () => { + expect(calculateViewerAssetIntersecting(manager, 980, 50)).toBe(IntersectionFlags.VISIBLE); }); - it('should return PRE when asset is just above viewport within expand margin', () => { - expect(calculateViewerAssetIntersecting(manager, -200, 50)).toBe(Intersection.PRE); + it('should return NEARBY when asset is just above viewport within expand margin', () => { + expect(calculateViewerAssetIntersecting(manager, -200, 50)).toBe(IntersectionFlags.NEARBY); }); - it('should return PRE when asset is just below viewport within expand margin', () => { - expect(calculateViewerAssetIntersecting(manager, 1200, 50)).toBe(Intersection.PRE); + it('should return NEARBY when asset is just below viewport within expand margin', () => { + expect(calculateViewerAssetIntersecting(manager, 1200, 50)).toBe(IntersectionFlags.NEARBY); }); it('should return NONE when asset is far above viewport', () => { - expect(calculateViewerAssetIntersecting(manager, -1000, 50)).toBe(Intersection.NONE); + expect(calculateViewerAssetIntersecting(manager, -1000, 50)).toBe(IntersectionFlags.NONE); }); it('should return NONE when asset is far below viewport', () => { - expect(calculateViewerAssetIntersecting(manager, 2000, 50)).toBe(Intersection.NONE); + expect(calculateViewerAssetIntersecting(manager, 2000, 50)).toBe(IntersectionFlags.NONE); }); it('should account for header height in viewport bounds', () => { const managerWithHeader = createMockTimelineManager(100, 500, 50); // viewport effectively becomes (100-50)=50 to (500+50)=550 // asset at 40-90 overlaps the effective viewport - expect(calculateViewerAssetIntersecting(managerWithHeader, 40, 50)).toBe(Intersection.ACTUAL); + expect(calculateViewerAssetIntersecting(managerWithHeader, 40, 50)).toBe(IntersectionFlags.VISIBLE); }); - it('should return PRE not ACTUAL for asset outside viewport but within header-adjusted expand', () => { + it('should return NEARBY not VISIBLE for asset outside viewport but within header-adjusted expand', () => { const managerWithHeader = createMockTimelineManager(100, 500, 50); // effective viewport: 50-550, expand: 500 each way -> -450 to 1050 // asset at -400 to -350 is outside viewport but within expand - expect(calculateViewerAssetIntersecting(managerWithHeader, -400, 50)).toBe(Intersection.PRE); + expect(calculateViewerAssetIntersecting(managerWithHeader, -400, 50)).toBe(IntersectionFlags.NEARBY); + }); +}); + +describe('Intersection flags', () => { + it('RENDERABLE should be NEARBY | VISIBLE', () => { + expect(IntersectionFlags.RENDERABLE).toBe(IntersectionFlags.NEARBY | IntersectionFlags.VISIBLE); + }); +}); + +describe('isVisible', () => { + it('should return true for VISIBLE', () => { + expect(isVisible(IntersectionFlags.VISIBLE)).toBe(true); + }); + + it('should return true for RENDERABLE', () => { + expect(isVisible(IntersectionFlags.RENDERABLE)).toBe(true); + }); + + it('should return false for NEARBY', () => { + expect(isVisible(IntersectionFlags.NEARBY)).toBe(false); + }); + + it('should return false for NONE', () => { + expect(isVisible(IntersectionFlags.NONE)).toBe(false); + }); +}); + +describe('isRenderable', () => { + it('should return true for VISIBLE', () => { + expect(isRenderable(IntersectionFlags.VISIBLE)).toBe(true); + }); + + it('should return true for NEARBY', () => { + expect(isRenderable(IntersectionFlags.NEARBY)).toBe(true); + }); + + it('should return true for RENDERABLE', () => { + expect(isRenderable(IntersectionFlags.RENDERABLE)).toBe(true); + }); + + it('should return false for NONE', () => { + expect(isRenderable(IntersectionFlags.NONE)).toBe(false); }); }); diff --git a/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.ts b/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.ts index 3810942d81..7fa629bb5f 100644 --- a/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.ts +++ b/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.ts @@ -1,3 +1,4 @@ +/* eslint-disable unicorn/prefer-math-trunc */ import { TUNABLES } from '$lib/utils/tunables'; import type { MonthGroup } from '../month-group.svelte'; import { TimelineManager } from '../timeline-manager.svelte'; @@ -7,75 +8,72 @@ const { } = TUNABLES; /** - * General function to check if a rectangular region intersects with a window. + * General function to check if a rectangular region intersects with another regtangular region. */ -export function isIntersecting(regionTop: number, regionBottom: number, windowTop: number, windowBottom: number) { +export function isIntersecting(regionTop: number, regionBottom: number, otherTop: number, otherBottom: number) { return ( - (regionTop >= windowTop && regionTop < windowBottom) || - (regionBottom >= windowTop && regionBottom < windowBottom) || - (regionTop < windowTop && regionBottom >= windowBottom) + (regionTop >= otherTop && regionTop < otherBottom) || + (regionBottom >= otherTop && regionBottom < otherBottom) || + (regionTop < otherTop && regionBottom >= otherBottom) ); } -export function updateIntersectionMonthGroup(timelineManager: TimelineManager, month: MonthGroup) { - const monthGroupTop = month.top; - const monthGroupBottom = monthGroupTop + month.height; - const windowTop = timelineManager.visibleWindow.top; - const windowBottom = timelineManager.visibleWindow.bottom; +const NEARBY = 1 << 0; +const VISIBLE = 1 << 1; - const actuallyIntersecting = isIntersecting(monthGroupTop, monthGroupBottom, windowTop, windowBottom); +export const IntersectionFlags = { + NONE: 0, + NEARBY, + VISIBLE, + RENDERABLE: NEARBY | VISIBLE, +} as const; - let intersecting = actuallyIntersecting; - if (!actuallyIntersecting) { - intersecting = isIntersecting( - monthGroupTop, - monthGroupBottom, - windowTop - INTERSECTION_EXPAND_TOP, - windowBottom + INTERSECTION_EXPAND_BOTTOM, - ); +export type IntersectionFlag = (typeof IntersectionFlags)[keyof typeof IntersectionFlags]; + +export function isVisible(flag: number): boolean { + return (flag & IntersectionFlags.VISIBLE) !== 0; +} + +export function isRenderable(flag: number): boolean { + return (flag & IntersectionFlags.RENDERABLE) !== 0; +} + +function calculateIntersection(regionTop: number, regionBottom: number, windowTop: number, windowBottom: number) { + if (regionBottom < windowTop - INTERSECTION_EXPAND_TOP || regionTop >= windowBottom + INTERSECTION_EXPAND_BOTTOM) { + return IntersectionFlags.NONE; } - month.intersecting = intersecting; - month.actuallyIntersecting = actuallyIntersecting; - if (intersecting) { + if (regionBottom < windowTop || regionTop >= windowBottom) { + return IntersectionFlags.NEARBY; + } + + return IntersectionFlags.VISIBLE; +} + +export function updateIntersectionMonthGroup(timelineManager: TimelineManager, month: MonthGroup) { + const intersection = calculateIntersection( + month.top, + month.top + month.height, + timelineManager.visibleWindow.top, + timelineManager.visibleWindow.bottom, + ); + + month.intersection = intersection; + if (isRenderable(intersection)) { timelineManager.clearDeferredLayout(month); } } -// Bit flags for intersection state -export const Intersection = { - NONE: 0, - PRE: 1, - ACTUAL: 3, // includes PRE (both bits set) -} as const; - -/** - * Returns a numeric flag: NONE (0), PRE (1, within expanded margin only), or ACTUAL (3, truly visible). - */ export function calculateViewerAssetIntersecting( timelineManager: TimelineManager, positionTop: number, positionHeight: number, ) { - const positionBottom = positionTop + positionHeight; const headerHeight = timelineManager.headerHeight; - const windowTop = timelineManager.visibleWindow.top - headerHeight; - const windowBottom = timelineManager.visibleWindow.bottom + headerHeight; - - if (isIntersecting(positionTop, positionBottom, windowTop, windowBottom)) { - return Intersection.ACTUAL; - } - - if ( - isIntersecting( - positionTop, - positionBottom, - windowTop - INTERSECTION_EXPAND_TOP, - windowBottom + INTERSECTION_EXPAND_BOTTOM, - ) - ) { - return Intersection.PRE; - } - - return Intersection.NONE; + return calculateIntersection( + positionTop, + positionTop + positionHeight, + timelineManager.visibleWindow.top - headerHeight, + timelineManager.visibleWindow.bottom + headerHeight, + ); } diff --git a/web/src/lib/managers/timeline-manager/month-group.svelte.ts b/web/src/lib/managers/timeline-manager/month-group.svelte.ts index b41deb5785..e9391dd5e4 100644 --- a/web/src/lib/managers/timeline-manager/month-group.svelte.ts +++ b/web/src/lib/managers/timeline-manager/month-group.svelte.ts @@ -17,6 +17,12 @@ import { import { t } from 'svelte-i18n'; import { get } from 'svelte/store'; +import { + IntersectionFlags, + isRenderable, + isVisible, + type IntersectionFlag, +} from '$lib/managers/timeline-manager/internal/intersection-support.svelte'; import { SvelteSet } from 'svelte/reactivity'; import { DayGroup } from './day-group.svelte'; import { GroupInsertionCache } from './group-insertion-cache.svelte'; @@ -25,8 +31,7 @@ import type { AssetDescriptor, Direction, MoveAsset, TimelineAsset } from './typ import { ViewerAsset } from './viewer-asset.svelte'; export class MonthGroup { - #intersecting: boolean = $state(false); - actuallyIntersecting: boolean = $state(false); + #intersection: IntersectionFlag = $state(IntersectionFlags.NONE); isLoaded: boolean = $state(false); dayGroups: DayGroup[] = $state([]); readonly timelineManager: TimelineManager; @@ -78,21 +83,25 @@ export class MonthGroup { } } - set intersecting(newValue: boolean) { - const old = this.#intersecting; + set intersection(newValue: IntersectionFlag) { + const old = this.#intersection; if (old === newValue) { return; } - this.#intersecting = newValue; - if (newValue) { + this.#intersection = newValue; + if (isRenderable(newValue)) { void this.timelineManager.loadMonthGroup(this.yearMonth); } else { this.cancel(); } } + get renderable() { + return isRenderable(this.#intersection); + } + get intersecting() { - return this.#intersecting; + return isVisible(this.#intersection); } get lastDayGroup() { diff --git a/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts b/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts index 38c593bd00..52217d4225 100644 --- a/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts +++ b/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts @@ -208,7 +208,7 @@ export class TimelineManager extends VirtualScrollManager { updateIntersectionMonthGroup(this, month); } - const month = this.months.find((month) => month.actuallyIntersecting); + const month = this.months.find((month) => month.intersecting); const viewportTopRatioInMonth = this.#calculateVewportTopRatioInMonth(month); const monthBottomViewportRatio = this.#calculateMonthBottomViewportRatio(month); diff --git a/web/src/lib/managers/timeline-manager/utils.svelte.ts b/web/src/lib/managers/timeline-manager/utils.svelte.ts index 2aba6470ee..4cd9476162 100644 --- a/web/src/lib/managers/timeline-manager/utils.svelte.ts +++ b/web/src/lib/managers/timeline-manager/utils.svelte.ts @@ -2,3 +2,7 @@ import type { TimelineAsset } from './types'; export const assetSnapshot = (asset: TimelineAsset): TimelineAsset => $state.snapshot(asset); export const assetsSnapshot = (assets: TimelineAsset[]) => assets.map((asset) => $state.snapshot(asset)); + +export function filterRenderable(items: T[]) { + return items.filter(({ renderable }) => renderable); +} diff --git a/web/src/lib/managers/timeline-manager/viewer-asset.svelte.ts b/web/src/lib/managers/timeline-manager/viewer-asset.svelte.ts index 10299c83eb..f0096f4d98 100644 --- a/web/src/lib/managers/timeline-manager/viewer-asset.svelte.ts +++ b/web/src/lib/managers/timeline-manager/viewer-asset.svelte.ts @@ -1,7 +1,12 @@ import type { CommonPosition } from '$lib/utils/layout-utils'; import type { DayGroup } from './day-group.svelte'; -import { Intersection, calculateViewerAssetIntersecting } from './internal/intersection-support.svelte'; +import { + IntersectionFlags, + calculateViewerAssetIntersecting, + isRenderable, + isVisible, +} from './internal/intersection-support.svelte'; import type { TimelineAsset } from './types'; export class ViewerAsset { @@ -9,7 +14,7 @@ export class ViewerAsset { #intersection = $derived.by(() => { if (!this.position) { - return Intersection.NONE; + return IntersectionFlags.NONE; } const store = this.#group.monthGroup.timelineManager; @@ -18,12 +23,12 @@ export class ViewerAsset { return calculateViewerAssetIntersecting(store, positionTop, this.position.height); }); - get intersecting() { - return this.#intersection !== Intersection.NONE; + get renderable() { + return isRenderable(this.#intersection); } - get actuallyIntersecting() { - return this.#intersection === Intersection.ACTUAL; + get intersecting() { + return isVisible(this.#intersection); } position: CommonPosition | undefined = $state.raw();