IKHSAN
ENID Baca dalam Bahasa Indonesia

opendesk

Public
Branch
main
Latest commit
08d9f3328 October 2026

glideToRow.ts

Open raw
/** Eases the row to mid-view and resolves on arrival; the browser's smooth
 * scroll has no reliable "done", and the pinned bar waits on it. */
export function glideToRow(
  scroller: HTMLElement,
  rowId: string,
  durationMs: number
): Promise<void> {
  const row = scroller.querySelector(`[id="${CSS.escape(rowId)}"]`);
  if (!row) return Promise.resolve();
  const from = scroller.scrollTop;
  const to = from + centerOffset(scroller, row);
  if (to === from || matchMedia("(prefers-reduced-motion: reduce)").matches) {
    scroller.scrollTop = to;
    return Promise.resolve();
  }
  return new Promise((resolve) => {
    const start = performance.now();
    const step = (now: number) => {
      const progress = Math.min((now - start) / durationMs, 1);
      scroller.scrollTop = from + (to - from) * easeOutCubic(progress);
      if (progress < 1) requestAnimationFrame(step);
      else resolve();
    };
    requestAnimationFrame(step);
  });
}

// centre below the scroll padding like scrollIntoView, or the flash's own
// scroll after the glide nudges the row by half the padding
function centerOffset(scroller: HTMLElement, row: Element): number {
  const view = scroller.getBoundingClientRect();
  const box = row.getBoundingClientRect();
  const padding = parseFloat(getComputedStyle(scroller).scrollPaddingTop) || 0;
  const viewCenter = view.top + padding + (view.height - padding) / 2;
  return box.top + box.height / 2 - viewCenter;
}

function easeOutCubic(progress: number): number {
  return 1 - (1 - progress) ** 3;
}
bytes
1,542
lines
41
Type
ts
Latest commit
28 October 2026