tricu

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

output-reveal.js (1892B)


      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, height, toolbarHeight, viewportTop, viewportHeight) {
      4     const safeTop = viewportTop + toolbarHeight + 12;
      5     const bottom = viewportTop + viewportHeight - 12;
      6     if (bottom <= safeTop)
      7         return 0;
      8     const visibleStart = Math.min(64, height, bottom - safeTop);
      9     return top >= safeTop && top + visibleStart <= bottom ? 0 : top - safeTop;
     10 }
     11 export function outputReveal(toolbar) {
     12     let armed = false, revision = 0;
     13     const cancel = () => { 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))
     20             cancel();
     21     });
     22     function reveal(target) {
     23         if (!armed)
     24             return;
     25         armed = false;
     26         const current = revision;
     27         requestAnimationFrame(() => {
     28             if (current !== revision || !matchMedia('(max-width:740px)').matches || target.closest('[inert]') || !target.getClientRects().length)
     29                 return;
     30             const rect = target.getBoundingClientRect(), viewport = window.visualViewport;
     31             const delta = revealDelta(rect.top, rect.height, toolbar.getBoundingClientRect().height, viewport?.offsetTop ?? 0, viewport?.height ?? innerHeight);
     32             if (delta)
     33                 window.scrollBy({ top: delta, behavior: 'instant' });
     34         });
     35     }
     36     return { arm() { cancel(); armed = true; }, cancel, reveal };
     37 }