Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lib/.storybook/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ if (window?.navigator?.userAgent?.includes('Chromatic')) {
// A blinking cursor is captured on-or-off depending on the frame; freeze it to a
// stable solid block so the terminal contributes no non-determinism.
cfg.terminal.cursorBlink = false;
// Snap pane splits/restores to their final geometry instead of tweening. A
// mid-tween split resizes panes through many transient widths, and xterm's DOM
// renderer can latch a frame where a pane is still narrow — freezing its last
// line clipped (`user@dormouse:~$` → `user@do`) even after the layout settles.
// Instant geometry removes that race at the source.
cfg.layout.animate = false;
}

// Collect all CSS variable names across all themes for cleanup
Expand Down
9 changes: 9 additions & 0 deletions lib/src/cfg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,13 @@ export const cfg = {
* stable solid block rather than being captured mid-blink (non-deterministic). */
cursorBlink: true,
},
layout: {
/** When false, Lath pane geometry changes (split / restore / kill / drag) apply
* instantly with no tween. Disabled under Chromatic: a mid-tween split resizes
* panes through many transient widths (briefly near-zero), and xterm's DOM
* renderer can latch onto one of those frames and leave a pane painted blank or
* clipped (`user@dormouse:~$` → `user@do`) even after the geometry settles.
* Snapping straight to the final geometry removes that whole race. */
animate: true,
},
};
9 changes: 6 additions & 3 deletions lib/src/components/wall/lath-wall-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
createAnimator,
} from '../../lib/lath/animator';
import { prefersReducedMotion } from '../../lib/ui-geometry';
import { cfg } from '../../cfg';
import { UNNAMED_PANEL_TITLE } from '../../lib/terminal-registry';
import type { ResolvedSplitDirection as DorResolvedSplitDirection } from 'dor/commands/types';
import {
Expand Down Expand Up @@ -163,9 +164,11 @@ export function createLathWallEngine(
): LathWallEngine {
const snapshot = (): LathWallSnapshot => store.getSnapshot();

// 0 under reduced motion, so entry/exit/tween all collapse to instant through the
// very same code path. Tests inject a fixed duration (or 0) via `opts`.
const durationMs = opts?.durationMs ?? (prefersReducedMotion() ? 0 : LATH_MOTION_MS);
// 0 under reduced motion (or when layout animation is disabled, e.g. Chromatic),
// so entry/exit/tween all collapse to instant through the very same code path.
// Tests inject a fixed duration (or 0) via `opts`.
const durationMs =
opts?.durationMs ?? (!cfg.layout.animate || prefersReducedMotion() ? 0 : LATH_MOTION_MS);
const animator = createAnimator({ durationMs, easing: LATH_EASING });

// Presentation-only side state (never in the store snapshot): the frame/wake
Expand Down
Loading