leptos_motion/
lib.rs

1//! # Leptos Motion
2//!
3//! A comprehensive animation library for Leptos with Framer Motion-inspired API.
4//!
5//! ## Features
6//!
7//! - **Declarative animations** with Motion-style API
8//! - **Hardware acceleration** via Web Animations API with RAF fallback
9//! - **Gesture support** for drag, hover, tap, and more
10//! - **Layout animations** using FLIP technique
11//! - **Scroll animations** with intersection observers
12//! - **Type safety** with full Rust compile-time validation
13//! - **High performance** targeting 60fps for 100+ concurrent animations
14//! - **Animation presets** for common patterns
15//! - **Keyframe animations** for complex multi-step animations
16//! - **Variants** for named animation states
17//!
18//! ## Quick Start
19//!
20//! ```rust,no_run
21//! use leptos::*;
22//! use leptos_motion::*;
23//! use std::collections::HashMap;
24//!
25//! #[component]
26//! fn App() -> impl IntoView {
27//!     let mut initial = HashMap::new();
28//!     initial.insert("opacity".to_string(), AnimationValue::Number(0.0));
29//!     initial.insert("scale".to_string(), AnimationValue::Number(0.5));
30//!
31//!     let mut animate = HashMap::new();
32//!     animate.insert("opacity".to_string(), AnimationValue::Number(1.0));
33//!     animate.insert("scale".to_string(), AnimationValue::Number(1.0));
34//!
35//!     view! {
36//!         <MotionDiv
37//!             class="my-element".to_string()
38//!             initial=initial
39//!             animate=animate
40//!             transition=Transition {
41//!                 duration: Some(0.5),
42//!                 ease: Easing::EaseOut,
43//!                 delay: None,
44//!                 repeat: RepeatConfig::Never,
45//!                 stagger: None,
46//!             }
47//!         >
48//!             "Hello Leptos Motion!"
49//!         </MotionDiv>
50//!     }
51//! }
52//! ```
53//!
54//! ## Core Concepts
55//!
56//! ### Animation Values
57//!
58//! Animation values represent different types of animatable properties:
59//!
60//! ```rust,no_run
61//! use leptos_motion::*;
62//!
63//! let opacity = AnimationValue::Number(1.0);
64//! let position = AnimationValue::Pixels(100.0);
65//! let rotation = AnimationValue::Degrees(45.0);
66//! let color = AnimationValue::Color("#ff0000".to_string());
67//! ```
68//!
69//! ### Transitions
70//!
71//! Configure how animations behave:
72//!
73//! ```rust,no_run
74//! # use leptos_motion::*;
75//! // Spring animation
76//! let spring = Transition {
77//!     ease: Easing::Spring(SpringConfig {
78//!         stiffness: 100.0,
79//!         damping: 10.0,
80//!         mass: 1.0,
81//!         ..Default::default()
82//!     }),
83//!     ..Default::default()
84//! };
85//!
86//! // Tween animation
87//! let tween = Transition {
88//!     duration: Some(0.3),
89//!     ease: Easing::EaseInOut,
90//!     delay: Some(0.1),
91//!     ..Default::default()
92//! };
93//! ```
94//!
95//! ### Gestures
96//!
97//! Add interactivity to your animations:
98//!
99//! ```rust,no_run
100//! # use leptos::*;
101//! # use leptos_motion::*;
102//! # use std::collections::HashMap;
103//! # fn main() {
104//! let mut hover_target = HashMap::new();
105//! hover_target.insert("scale".to_string(), AnimationValue::Number(1.1));
106//!
107//! let mut tap_target = HashMap::new();
108//! tap_target.insert("scale".to_string(), AnimationValue::Number(0.9));
109//!
110//! let _view = view! {
111//!     <MotionDiv
112//!         while_hover=hover_target
113//!         while_tap=tap_target
114//!         drag=DragConfig::default()
115//!     >
116//!         "Interactive element"
117//!     </MotionDiv>
118//! };
119//! # }
120//! ```
121
122#![warn(missing_docs)]
123#![forbid(unsafe_code)]
124
125// Re-export core functionality
126pub use leptos_motion_core::{
127    AnimationConfig, AnimationEngine, AnimationHandle, AnimationValue, Easing, RepeatConfig,
128    Result, SpringConfig, Transition, animation, easing, spring,
129};
130
131// Re-export performance module if available
132#[cfg(feature = "performance-metrics")]
133pub use leptos_motion_core::performance;
134
135// Re-export DOM functionality
136pub use leptos_motion_dom::{
137    AnimatePresence, DragAxis, DragConfig, DragConstraints, MotionDiv, MotionProps, MotionSpan,
138    PresenceMode,
139};
140
141// Re-export macros
142pub use leptos_motion_macros::motion_target;
143
144#[cfg(feature = "gestures")]
145pub use leptos_motion_gestures::*;
146
147#[cfg(feature = "layout")]
148pub use leptos_motion_layout::*;
149
150#[cfg(feature = "scroll")]
151pub use leptos_motion_scroll::*;
152
153pub use leptos_motion_macros::*;
154
155/// Animation presets and common patterns
156pub mod presets {
157    // Core animation presets
158    pub use leptos_motion_core::animation::presets::*;
159    pub use leptos_motion_core::easing::presets::*;
160    pub use leptos_motion_core::spring::presets::*;
161}
162
163/// Re-export commonly used external types
164pub mod external {
165    pub use leptos::*;
166    pub use wasm_bindgen::prelude::*;
167    pub use web_sys::{Element, Event, HtmlElement, MouseEvent, TouchEvent};
168}
169
170/// Version information
171pub const VERSION: &str = env!("CARGO_PKG_VERSION");
172
173/// Library information
174pub const DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION");
175
176#[cfg(test)]
177mod tests {
178    use super::*;
179
180    #[test]
181    fn test_version() {
182        // VERSION and DESCRIPTION are compile-time constants
183        // This test just verifies the constants are defined and have content
184        assert!(VERSION.contains("0.8") || DESCRIPTION.contains("motion"));
185    }
186
187    #[test]
188    fn test_animation_value_creation() {
189        let opacity = AnimationValue::Number(1.0);
190        let position = AnimationValue::Pixels(100.0);
191        let rotation = AnimationValue::Degrees(45.0);
192
193        assert_eq!(opacity, AnimationValue::Number(1.0));
194        assert_eq!(position, AnimationValue::Pixels(100.0));
195        assert_eq!(rotation, AnimationValue::Degrees(45.0));
196    }
197
198    #[test]
199    fn test_transition_creation() {
200        let transition = Transition {
201            duration: Some(1.0),
202            ease: Easing::Spring(SpringConfig::default()),
203            ..Default::default()
204        };
205
206        assert_eq!(transition.duration, Some(1.0));
207        assert!(matches!(transition.ease, Easing::Spring(_)));
208    }
209}