added subtle fade, fixed command palette

This commit is contained in:
eli-w-king
2026-02-10 15:54:18 -08:00
parent fe391a6549
commit f3349e3a7e
4 changed files with 77 additions and 14 deletions

View File

@@ -11,23 +11,23 @@ import './motion.css';
* Duration in milliseconds for panel open (entrance) animations.
* Per Fluent 2 Enter/Exit pattern - entrance should feel smooth but not sluggish.
*/
export const PANEL_OPEN_DURATION = 200;
export const PANEL_OPEN_DURATION = 150;
/**
* Duration in milliseconds for panel close (exit) animations.
* Exits are faster than entrances - feels snappy and responsive.
*/
export const PANEL_CLOSE_DURATION = 75;
export const PANEL_CLOSE_DURATION = 50;
/**
* Duration in milliseconds for quick input open (entrance) animations.
*/
export const QUICK_INPUT_OPEN_DURATION = 200;
export const QUICK_INPUT_OPEN_DURATION = 150;
/**
* Duration in milliseconds for quick input close (exit) animations.
*/
export const QUICK_INPUT_CLOSE_DURATION = 75;
export const QUICK_INPUT_CLOSE_DURATION = 50;
//#endregion
@@ -111,6 +111,40 @@ function bezierComponentDerivative(u: number, p1: number, p2: number): number {
//#endregion
//#region Duration Scaling
/**
* Reference pixel distance at which the base duration constants apply.
* Duration scales linearly: a 600px animation takes twice as long as a 300px
* one, keeping perceived velocity constant.
*/
const REFERENCE_DISTANCE = 300;
/** Minimum animation duration in milliseconds (avoids sub-frame flickers). */
const MIN_DURATION = 50;
/** Maximum animation duration in milliseconds (avoids sluggish feel). */
const MAX_DURATION = 300;
/**
* Scales a base animation duration proportionally to the pixel distance
* being animated, so that perceived velocity stays constant regardless of
* panel width.
*
* @param baseDuration The duration (ms) that applies at {@link REFERENCE_DISTANCE} pixels.
* @param pixelDistance The actual number of pixels the view will resize.
* @returns The scaled duration, clamped to [{@link MIN_DURATION}, {@link MAX_DURATION}].
*/
export function scaleDuration(baseDuration: number, pixelDistance: number): number {
if (pixelDistance <= 0) {
return baseDuration;
}
const scaled = baseDuration * (pixelDistance / REFERENCE_DISTANCE);
return Math.round(Math.max(MIN_DURATION, Math.min(MAX_DURATION, scaled)));
}
//#endregion
//#region Utility Functions
/**

View File

@@ -14,7 +14,7 @@ import { combinedDisposable, Disposable, dispose, IDisposable, toDisposable } fr
import { clamp } from '../../../common/numbers.js';
import { Scrollable, ScrollbarVisibility, ScrollEvent } from '../../../common/scrollable.js';
import * as types from '../../../common/types.js';
import { isMotionReduced, parseCubicBezier, solveCubicBezier } from '../motion/motion.js';
import { isMotionReduced, parseCubicBezier, scaleDuration, solveCubicBezier } from '../motion/motion.js';
import './splitview.css';
export { Orientation } from '../sash/sash.js';
@@ -896,10 +896,17 @@ export class SplitView<TLayoutContext = undefined, TView extends IView<TLayoutCo
container.style.overflow = 'hidden';
}
// 7. Render the start state
// 6b. Set initial opacity for fade effect
container.style.opacity = visible ? '0' : '1';
// 7. Scale duration based on pixel distance for consistent perceived velocity
const pixelDistance = Math.abs(finalSizes[index] - startSizes[index]);
duration = scaleDuration(duration, pixelDistance);
// 8. Render the start state
this.layoutViews();
// 8. Parse easing for JS evaluation
// 9. Parse easing for JS evaluation
const [x1, y1, x2, y2] = parseCubicBezier(easing);
// Helper: snap all sizes to final state and clean up
@@ -907,6 +914,7 @@ export class SplitView<TLayoutContext = undefined, TView extends IView<TLayoutCo
for (let i = 0; i < this.viewItems.length; i++) {
this.viewItems[i].size = finalSizes[i];
}
container.style.opacity = '';
if (!visible) {
container.classList.remove('visible');
container.style.overflow = '';
@@ -932,7 +940,7 @@ export class SplitView<TLayoutContext = undefined, TView extends IView<TLayoutCo
};
this._cleanupMotion = () => cleanup(false);
// 9. Animate via requestAnimationFrame
// 10. Animate via requestAnimationFrame
const startTime = performance.now();
const totalSize = this.size;
@@ -945,6 +953,9 @@ export class SplitView<TLayoutContext = undefined, TView extends IView<TLayoutCo
const t = Math.min(elapsed / duration, 1);
const easedT = solveCubicBezier(x1, y1, x2, y2, t);
// Interpolate opacity for fade effect
container.style.opacity = String(visible ? easedT : 1 - easedT);
// Interpolate all view sizes
let runningTotal = 0;
for (let i = 0; i < this.viewItems.length; i++) {