fix(studio): the strip stands on the frame in hand when the rail changes width

A narrower rail is not the wide one with less of the roll in it: its frames
are a different number of pixels wide, so the scrollLeft the reader was
standing on is a different frame. Opening the studio on a desk and switching
to the phone layout left the strip standing further down the roll than the
frame on the stage — with three hundred frames in the folder, frame 170
where frame 150 was open — and the frames of the open photo were off the
rail. The rail is now put back on the frame in hand whenever its own width
changes, the window is read from where it then stands, and the tiles the
reader is being shown are the ones asked for.
This commit is contained in:
2026-10-15 18:25:18 +07:00
parent e7e739ded1
commit 6d16783d17
+19 -4
View File
@@ -92,12 +92,18 @@ export const Filmstrip = memo(function Filmstrip({
// and not `scroll-behavior: smooth` on the rail, which glides across the whole
// roll: a scroll event a frame, and a fresh window asked for at each one, of
// frames the reader never stops on. The rail is put where it is wanted.
useEffect(() => {
const centre = useCallback(() => {
const box = rail.current;
const el = box?.children[at] as HTMLElement | undefined;
if (!box || !el) return;
box.scrollLeft = el.offsetLeft - box.clientWidth / 2 + el.clientWidth / 2;
}, [at, frames]);
}, [at]);
useEffect(() => {
centre();
// The frames are in the dependency too: the frame in hand is a child of the
// rail, and until the folder arrives there is nothing to stand on.
}, [centre, frames]);
// Scrolling and resizing both move what the rail can reach: the phone's rail
// is a different window on the same roll, and the tiles it now needs are not
@@ -115,14 +121,23 @@ export const Filmstrip = memo(function Filmstrip({
report();
});
};
// A narrower rail is not the wide one with less of the roll in it: it is a
// different number of frames to the pixel the reader was standing on, so the
// same scrollLeft is a different frame — the strip left the frame on the
// stage behind and drew the roll from somewhere else down it. It is put back
// on that frame first, and the window is read from where it then stands.
const resized = () => {
centre();
again();
};
box.addEventListener('scroll', again, { passive: true });
const ro = new ResizeObserver(again);
const ro = new ResizeObserver(resized);
ro.observe(box);
return () => {
box.removeEventListener('scroll', again);
ro.disconnect();
};
}, [report]);
}, [report, centre]);
return (
// A wheel has no sideways axis, so a plain tick over the roll walks it along.