Commit 0d4a4ccdc6de
tarball1 file changed+25-6
@@ -29,12 +29,17 @@ function rowKey(node: Element): string {
2929
return item ?? row ?? '';3030
}3131
32
+/** Sub-pixel sizes from many rows easing out together made the pinned bottom flip between roundings. */33
+function wholePixels(css: string): string {34
+ return css.replace(/(-?\d*\.?\d+)px/g, (_, n: string) => `${Math.round(Number(n))}px`);35
+}36
+3237
function reveal(node: Element, ms: number, axis: 'x' | 'y' = 'y'): TransitionConfig {3338
const duration = motionDuration(ms);3439
if (duration === 0) return { duration: 0 };3540
noteBusy(duration);3641
const base = slide(node, { duration, easing: cubicOut, axis });37
- return { duration, easing: cubicOut, css: (t, u) => `${base.css?.(t, u) ?? ''};opacity: ${t};` };42
+ return { duration, easing: cubicOut, css: (t, u) => `${wholePixels(base.css?.(t, u) ?? '')};opacity: ${t};` };3843
}3944
4045
export function rowIn(node: Element): TransitionConfig {@@ -55,13 +60,27 @@ export function dissolve(node: Element): TransitionConfig {
5560
return fade(node, { duration });5661
}5762
63
+const settling = new WeakSet<HTMLElement>();64
+5865
export function settleHeight(node: HTMLElement, from: number): void {5966
const duration = motionDuration(180);6067
const to = node.offsetHeight;61
- if (duration === 0 || Math.abs(to - from) < 2 || node.getAnimations({ subtree: true }).length > 0) return;68
+ if (duration === 0 || Math.abs(to - from) < 2 || settling.has(node) || node.getAnimations({ subtree: true }).length > 0) return;6269
noteBusy(duration);63
- node.animate(64
- [{ height: `${from}px`, overflow: 'hidden' }, { height: `${to}px`, overflow: 'hidden' }],65
- { duration, easing: 'cubic-bezier(0.2, 0.8, 0.2, 1)' }66
- );70
+ settling.add(node);71
+ const start = performance.now();72
+ node.style.overflow = 'hidden';73
+ const step = (now: number) => {74
+ const t = Math.min(1, (now - start) / duration);75
+ if (t < 1) {76
+ node.style.height = `${Math.round(from + (to - from) * cubicOut(t))}px`;77
+ requestAnimationFrame(step);78
+ } else {79
+ node.style.height = '';80
+ node.style.overflow = '';81
+ settling.delete(node);82
+ }83
+ };84
+ node.style.height = `${Math.round(from)}px`;85
+ requestAnimationFrame(step);6786
}