Skip to main content

gpui_ce_motion/
lib.rs

1//! Declarative transitions with retained, explicitly owned motion state.
2//!
3//! Keep one [`MotionState`] per logical object in its owning view. Recreate the
4//! [`Motion`] description each render; changing a target interrupts from the
5//! current presentation. Springs also preserve velocity. No tasks, allocations,
6//! global registries, or timers are needed to sample motion. Prepared clips and
7//! timelines allocate during construction; their sampling reuses retained state.
8//!
9//! ```
10//! use gpui_ce_motion::{Motion, MotionState, Target, Transition};
11//! use std::time::Duration;
12//!
13//! let mut state = MotionState::default();
14//! let motion = Motion::new(Target::default().x(120.0).width(240.0).border_radius(12.0))
15//!     .initial(Target::default().width(0.0).border_radius(0.0).opacity(0.0))
16//!     .exit(Target::default().y(16.0).opacity(0.0))
17//!     .transition(Transition::default());
18//! assert!(state.sample(motion, Duration::ZERO, false).is_animating());
19//! let frame = state.sample(motion, Duration::from_secs(5), false);
20//! assert_eq!(frame.target().x_px(), 120.0);
21//! assert_eq!(frame.target().width_px(), Some(240.0));
22//! assert!(!frame.is_animating());
23//! ```
24//!
25//! The optional `gpui` feature adds `MotionState::frame` and GPUI rendering
26//! helpers. See the crate README for integration and publication constraints.
27
28//!
29//! Prepared playback uses the same explicit clocks and ownership:
30//!
31//! ```
32//! use gpui_ce_motion::{Animation, AnimationState, Easing, Repeat, RepeatMode, Target};
33//! use std::time::Duration;
34//! # fn main() -> Result<(), gpui_ce_motion::AnimationError> {
35//! let clip = Animation::to(Target::default().x(120.0), Duration::from_millis(600), Easing::Linear)
36//!     .repeat(Repeat::Forever, RepeatMode::Mirror, Duration::ZERO)?;
37//! let mut state = AnimationState::default();
38//! state.sample(&clip, Duration::ZERO, false);
39//! state.pause(Duration::from_millis(300));
40//! let held = state.sample(&clip, Duration::from_millis(900), false);
41//! assert_eq!(held.target().x_px(), 60.0);
42//! assert!(!held.is_animating());
43//! # Ok(())
44//! # }
45//! ```
46
47mod animation;
48mod color;
49mod interaction;
50mod layout;
51#[cfg(feature = "gpui")]
52mod layout_native;
53mod motion;
54mod presence;
55mod svg;
56mod transition;
57mod value;
58
59#[cfg(feature = "gpui")]
60mod native;
61
62pub use motion::{Frame, Motion, MotionState, Presence, Property, Target};
63
64pub use transition::{
65    Bezier, CustomEasing, Easing, InvalidEasing, InvalidSpring, Spring, Transition,
66};
67
68pub use value::{Inertia, MotionValue, ValueFrame};
69
70pub use animation::{
71    Animation, AnimationError, AnimationState, Keyframe, Playback, Repeat, RepeatMode, StaggerFrom,
72    Timeline, stagger,
73};
74
75pub use color::{Color, ColorState};
76
77pub use interaction::{
78    Drag, GestureTargets, InView, Interaction, Variants, move_item, reorder_index, scroll_progress,
79    transform,
80};
81
82pub use presence::{PresenceChild, PresenceGroup, PresenceMode};
83
84pub use svg::{SvgFrame, SvgMotion, SvgMotionState, SvgTarget};
85
86pub use layout::{LayoutPositionFrame, LayoutPositionState};
87#[cfg(feature = "gpui")]
88pub use layout_native::{LayoutGroup, LayoutPositionElement};
89
90mod style_motion;
91
92pub use style_motion::{
93    ColorProperty, StyleFrame, StyleMotion, StyleMotionState, StyleProperty, StyleTarget,
94};
95
96#[cfg(feature = "gpui")]
97mod measured_size;
98
99#[cfg(feature = "gpui")]
100pub use measured_size::{AutoSize, SizeAxis};
101
102#[cfg(feature = "gpui")]
103mod pop_layout;
104
105#[cfg(feature = "gpui")]
106pub use pop_layout::{PopElement, PopLayout, PopRequest};
107
108#[cfg(feature = "gpui")]
109mod gesture_native;
110
111#[cfg(feature = "gpui")]
112pub use gesture_native::{GestureElement, GestureState};
113
114#[cfg(feature = "gpui")]
115mod scroll_native;
116
117#[cfg(feature = "gpui")]
118pub use scroll_native::{Axis, ScrollMotion, native_scroll_progress};
119
120#[cfg(feature = "gpui")]
121mod shared_layout;
122
123#[cfg(feature = "gpui")]
124pub use shared_layout::{SharedElement, SharedLayout};
125
126#[cfg(feature = "gpui")]
127mod reorder_native;
128
129#[cfg(feature = "gpui")]
130pub use reorder_native::{ReorderElement, ReorderGroup};
131
132mod vector;
133
134pub use vector::{PathCommand, PathError, PathFrame, PathMorphState, PathShape, StrokeReveal};
135
136#[cfg(feature = "gpui")]
137mod vector_native;
138
139#[cfg(feature = "gpui")]
140pub use vector_native::{VectorElement, VectorState};
141
142#[cfg(feature = "text")]
143mod text;
144
145#[cfg(feature = "text")]
146pub use text::{
147    NumberEffect, Scramble, TextClip, TextError, TextLayoutUnit, TextMatch, TextOptions,
148    TextPlaybackState, TextPresentation, TextPreset, TextRevealAxis, TextTarget, TextUnit,
149    TextUnitInfo, text_ranges,
150};
151
152#[cfg(feature = "gpui")]
153mod text_native {
154    use gpui::ColorExt as _;
155
156    fn text_color_to_native(color: crate::Color) -> gpui::Hsla {
157        gpui::rgb_to_hsla(color.to_rgba())
158    }
159
160    fn text_color_from_native(color: gpui::Hsla) -> crate::Color {
161        let color = gpui::hsla_to_rgba(color);
162
163        crate::Color::rgba(
164            color.red.into(),
165            color.green.into(),
166            color.blue.into(),
167            color.alpha.into(),
168        )
169    }
170
171    crate::__motion_text_adapter!(gpui, text_color_to_native, text_color_from_native);
172}
173
174#[cfg(feature = "gpui")]
175pub use text_native::{NumberElement, NumberMotionState, TextElement, TextMotionState};
176
177mod graph;
178
179pub use graph::{
180    GraphError, GraphSubscription, MotionEvent, MotionEventKind, MotionGraph, ValueId,
181};
182
183mod geometry;
184
185pub use geometry::{
186    AutoScroll, DragBounds, GeometryError, LayoutRect, ReorderAxis, ScrollEdge, ScrollOffsets,
187};
188
189mod completion;
190
191pub use completion::{Completion, CompletionStatus};
192
193mod typed_animation;
194
195pub use typed_animation::{
196    MotionData, TrackId, TypedAnimation, TypedFrame, TypedKeyframe, TypedState, TypedTimeline,
197};
198
199mod orchestration;
200
201pub use orchestration::{ChildrenOrder, MotionConfig, MotionNode, MotionTree, TreeError};
202
203#[cfg(feature = "svg-path")]
204pub use vector::SvgPathError;
205pub use vector::{PathMeasure, PathPoint};
206
207#[cfg(feature = "text")]
208pub use text::{FixedNumber, FormattedNumber, NumberFormat, NumberFormatError, RichText, TextSpan};
209
210mod spatial_native;
211
212#[cfg(feature = "gpui")]
213mod spatial {
214    crate::__motion_spatial_adapter!(gpui, crate);
215}
216
217pub use geometry::ScrollFrame;
218
219#[cfg(feature = "gpui")]
220pub use spatial::{
221    AnchorElement, GraphState, MotionAnchor, MotionTreeState, ScrollTracker, SharedOverlay,
222    SharedOverlayElement,
223};
224
225pub use geometry::{DragEvent, GesturePhase, PinchGesture};