Compare commits

..

1 Commits

Author SHA1 Message Date
Claude baee028792 fix(cuesheet): reduce image reload flicker when scrolling
Cuesheet rows are virtualized (react-virtuoso), so rows scrolling out
of the small overscan buffer get unmounted, destroying their <img>
elements; scrolling back remounts them from scratch. Native
loading='lazy' on the image compounded this with an extra deferred
load on every remount. Widen the overscan buffer and drop the
redundant lazy attribute so images stay mounted through normal
scroll-and-back gestures.
2026-07-25 18:57:02 +00:00
5 changed files with 33 additions and 21 deletions
@@ -260,7 +260,7 @@ export default function CuesheetTable({
context={virtuosoContext}
style={tableRoot === 'editor' ? { paddingLeft: '1rem' } : undefined}
computeItemKey={computeItemKey}
increaseViewportBy={{ top: 100, bottom: 200 }}
increaseViewportBy={{ top: 300, bottom: 600 }}
components={virtuosoComponents}
fixedHeaderContent={fixedHeaderContent}
/>
@@ -62,7 +62,7 @@ function EditableImage({ initialValue, readOnly, updateValue }: EditableImagePro
</Button>
</div>
)}
{Boolean(initialValue) && <img loading='lazy' src={initialValue} className={style.image} />}
{Boolean(initialValue) && <img src={initialValue} className={style.image} />}
</div>
);
}
@@ -152,10 +152,13 @@ export function computeScopedRundown(
const timeFromPrevious: number = getTimeFrom(currentEntry, lastEntry);
// each event only contributes the time it pushes past the latest event so far
// NOTE: timeFromPrevious is negative on overlap, so adding it removes the overlapping part
totalDuration += Math.max(currentEntry.duration + timeFromPrevious, 0);
if (timeFromPrevious === 0) {
totalDuration += currentEntry.duration;
} else if (timeFromPrevious > 0) {
totalDuration += timeFromPrevious + currentEntry.duration;
} else if (timeFromPrevious < 0) {
totalDuration += Math.max(currentEntry.duration + timeFromPrevious, 0);
}
if (isNewLatest(currentEntry, lastEntry)) {
lastEntry = currentEntry;
}
@@ -309,15 +309,18 @@ function processEntry<T extends OntimeEntry>(
entry.gap = getTimeFrom(entry, rundownMetadata.latestEvent);
/**
* The rundown duration is the union of all event intervals, so each event
* only contributes the time it pushes past the latest event so far.
* - gap >= 0: the event contributes its gap plus its full duration
* - gap < 0: the event overlaps, only the part after the latest end counts
* (clamped at 0 for events which are fully contained in a previous one)
* NOTE: gap is negative on overlap, so adding it removes the overlapping part
*/
rundownMetadata.totalDuration += Math.max(entry.duration + entry.gap, 0);
if (entry.gap === 0) {
// event starts on previous finish, we add its duration
rundownMetadata.totalDuration += entry.duration;
} else if (entry.gap > 0) {
// event has a gap, we add the gap and the duration
rundownMetadata.totalDuration += entry.gap + entry.duration;
} else {
// there is an overlap, we remove the overlap from the duration
// ensuring that the sum is not negative (ie: fully overlapped events)
// NOTE: we add the gap since it is a negative number
rundownMetadata.totalDuration += Math.max(entry.duration + entry.gap, 0);
}
// remove eventual gaps from the accumulated delay
// we only affect positive delays (time forwards)
+12 -6
View File
@@ -17,11 +17,17 @@ export function getTimeFrom(
const normalisedCurrentStart = current.timeStart + current.dayOffset * dayInMs;
const normalisedPreviousEnd = previous.timeStart + previous.duration + previous.dayOffset * dayInMs;
/**
* The distance between the current start and the previous end
* - positive: there is a gap between the events
* - zero: the current event starts on the previous end
* - negative: the events overlap
*/
// event is linked to previous
if (normalisedCurrentStart === normalisedPreviousEnd) {
return 0;
}
// event has a gap from previous
if (normalisedCurrentStart > normalisedPreviousEnd) {
// time from previous is difference between start and previous end
return normalisedCurrentStart - normalisedPreviousEnd;
}
// event overlaps with previous
return normalisedCurrentStart - normalisedPreviousEnd;
}