1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
//! The datatable's motion layer — one small, coherent, opt-out vocabulary of
//! entrance transitions shared by the flat grid and the pivot.
//!
//! # What moves, and what deliberately does not
//!
//! The data surface itself — cells, selection, hover, sort state — is painted
//! imperatively every frame and stays **instant**. That is a design choice, not
//! a gap: a spreadsheet's value is that state reads the very frame it changes,
//! and Excel / Numbers never tween a selection marquee. Motion here is reserved
//! for the *chrome* that pops into existence — context menus, filter panels,
//! popovers, dialogs, the busy scrim, the drag ghost — where an instant appear
//! reads as a jarring flash and a short fade reads as native.
//!
//! # The vocabulary
//!
//! A single gesture: an opacity fade on enter, fast (~110 ms) and eased with
//! [`ease_out_quint`] so it decelerates into place. No scale, no bounce, no
//! slide — those betray a web toolkit; macOS menus simply fade, so we do too.
//! Exits are instant (the element is dropped from the tree), matching the
//! platform. Every surface uses [`pop_in`], so the whole crate speaks one
//! motion dialect rather than a dozen hand-tuned ones.
//!
//! # Opting out
//!
//! All motion routes through the `animations` flag ([`crate::GridConfig`],
//! mirrored onto [`crate::pivot::PivotState`]). GPUI 0.2 exposes no OS
//! reduce-motion signal, so this flag *is* the accessibility control: a host
//! that honors a system "reduce motion" preference sets it to `false` and every
//! surface falls back to an instant appear, with zero other changes.
use Duration;
use ;
/// Enter duration for transient surfaces (menus, popovers, dialogs). Fast
/// enough to feel instant to a user in a task (product-register motion budget
/// is 150–250 ms; a reveal wants the low end), slow enough to register as a
/// fade rather than a pop.
pub const SURFACE_ENTER_MS: u64 = 110;
/// Enter duration for the busy scrim. A touch slower than a menu: the overlay
/// covers the whole grid, and a softer fade signals "work is starting" instead
/// of snapping a wall in front of the data.
pub const SCRIM_ENTER_MS: u64 = 150;
/// Enter duration for the pivot drag ghost. Quicker than a menu — the ghost is
/// a direct extension of the pointer, so it should feel lifted, not revealed.
pub const GHOST_ENTER_MS: u64 = 90;
/// Enter duration for a sidebar accordion body on expand. Sits with the other
/// state transitions; the header chevron flips instantly, the body fades in.
pub const SECTION_ENTER_MS: u64 = 140;
/// Fade `element` in over `duration_ms`, easing out. When `animations` is
/// `false` the element is returned untouched (instant appear) so the same call
/// site serves both the animated and the reduce-motion path.
///
/// Apply this to the *visible, styled* body of a surface — the card with the
/// background and border — not to a wrapping `anchored`/`deferred`/`occlude`
/// layer (those are not [`Styled`], and fading an invisible click-catcher would
/// do nothing). Opacity does not affect layout, so an `anchored()` parent keeps
/// its edge-flip positioning stable across the fade.
pub
/// [`fade_in`] at the standard transient-surface duration ([`SURFACE_ENTER_MS`]).
/// The default entrance for every menu, popover, and dialog in the crate.
pub