tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

output-reveal.ts (1837B)


      1 // Reveal only the start of a foreground result, never its whole (possibly huge)
      2 // box. Bounds are visual-viewport coordinates, accounting for the sticky toolbar.
      3 export function revealDelta(top: number, height: number, toolbarHeight: number, viewportTop: number, viewportHeight: number): number {
      4   const safeTop = viewportTop + toolbarHeight + 12;
      5   const bottom = viewportTop + viewportHeight - 12;
      6   if (bottom <= safeTop) return 0;
      7   const visibleStart = Math.min(64, height, bottom - safeTop);
      8   return top >= safeTop && top + visibleStart <= bottom ? 0 : top - safeTop;
      9 }
     10 
     11 export function outputReveal(toolbar: HTMLElement) {
     12   let armed = false, revision = 0;
     13   const cancel = (): void => { armed = false; revision++; };
     14   // A user who scrolls elsewhere during a slow run has chosen what to read.
     15   window.addEventListener('pagehide', cancel);
     16   window.addEventListener('wheel', cancel, { passive: true });
     17   window.addEventListener('touchmove', cancel, { passive: true });
     18   window.addEventListener('keydown', event => {
     19     if (['PageUp', 'PageDown', 'Home', 'End', 'ArrowUp', 'ArrowDown', ' '].includes(event.key)) cancel();
     20   });
     21   function reveal(target: HTMLElement): void {
     22     if (!armed) return;
     23     armed = false; const current = revision;
     24     requestAnimationFrame(() => {
     25       if (current !== revision || !matchMedia('(max-width:740px)').matches || target.closest('[inert]') || !target.getClientRects().length) return;
     26       const rect = target.getBoundingClientRect(), viewport = window.visualViewport;
     27       const delta = revealDelta(rect.top, rect.height, toolbar.getBoundingClientRect().height, viewport?.offsetTop ?? 0, viewport?.height ?? innerHeight);
     28       if (delta) window.scrollBy({ top: delta, behavior: 'instant' });
     29     });
     30   }
     31   return { arm(): void { cancel(); armed = true; }, cancel, reveal };
     32 }