textmachine/frontend/src/showcase/useScreenshotFlag.ts

49 lines
2.3 KiB
TypeScript

import { useEffect, useRef } from 'react';
/** How long the quiet has to hold before the screen calls itself ready. */
const quietMs = 150;
/**
* The readiness signal for the screenshot loop. `networkidle` will not do and cannot do: a live
* run keeps the SSE open by construction. The screen says by itself when it has decided what to
* draw — and "I am waiting" is a decision too, for a route that is shot for the sake of the
* waiting.
*
* ⚠ The flag is ONE-WAY: once it has settled it never goes out again. It answers the screenshot
* loop's question "has the screen come together already?", not "is the network quiet right now":
* a background refetch on focus return and an update from a live run happen constantly and by
* construction, and without the latch the frame would be shot in a race with them. A route shot for
* the sake of the waiting does not touch the latch — it never gets as far as "ready".
*
* Two conditions of the latch, and each one was bought with a frame:
*
* 1. While NOT A SINGLE request has flown, there is no attribute at all. On the first effect
* nothing is in flight, and the previous edition announced `ready` at that moment — the gate
* shot the frame before the first read had started (found by acceptance S3.6). The absence of
* the attribute the loop waits out silently, and the library is read by every screen.
* 2. The quiet has to HOLD. The reads of the second wave — the book, the chapters, the bank — turn
* on only after the library has answered, and between the waves the counter honestly drops to
* zero: a latch without the hold closed in that pit, and `/scale` was shot with the line
* "loading chapters…" (measured with a frame, not with reasoning).
*/
export function useScreenshotFlag(waiting: boolean): void {
const started = useRef(false);
const settled = useRef(false);
useEffect(() => {
if (waiting) started.current = true;
if (!started.current) return;
if (waiting || settled.current) {
document.documentElement.dataset.screen = settled.current ? 'ready' : 'loading';
return;
}
const timer = setTimeout(() => {
settled.current = true;
document.documentElement.dataset.screen = 'ready';
}, quietMs);
return () => {
clearTimeout(timer);
};
}, [waiting]);
}