Skip to main content

orbital_motion/preview/
motion_tokens.rs

1use leptos::prelude::*;
2use orbital_macros::component_doc;
3use orbital_style::inject_style;
4
5use crate::tokens::{MotionCurve, MotionDuration};
6
7fn token_demo_styles() -> &'static str {
8    r#"
9.orbital-motion-tokens-table {
10    display: flex;
11    flex-direction: column;
12    gap: var(--orb-space-block-sm);
13    width: 100%;
14}
15
16.orbital-motion-tokens-row {
17    display: grid;
18    grid-template-columns: 140px 1fr 1fr 120px;
19    gap: var(--orb-space-inline-md);
20    align-items: center;
21    font-size: var(--orb-type-size-xs);
22}
23
24.orbital-motion-tokens-bar {
25    height: 8px;
26    border-radius: var(--orb-radius-sm);
27    background: var(--orb-color-brand-bg);
28    width: 0%;
29}
30"#
31}
32
33/// Typed duration and easing tokens for enter/exit transitions across Orbital surfaces.
34///
35/// Pick a [`MotionDuration`](crate::MotionDuration) step (50–500ms) and a [`MotionCurve`](crate::MotionCurve) for acceleration. Prefer these enums over hard-coded milliseconds in [`PresenceMotion::with_duration`](crate::PresenceMotion::with_duration) and [`PresenceMotion::with_curve`](crate::PresenceMotion::with_curve) so theme overrides propagate consistently through dialogs, drawers, toasts, and menus.
36///
37/// # Examples
38///
39/// ## Motion tokens
40/// <!-- preview -->
41/// ```rust
42/// use crate::preview::MotionTokensReference;
43/// view! {
44///     <div data-testid="motion-tokens-preview">
45///         <MotionTokensReference />
46///     </div>
47/// }
48/// ```
49#[component_doc(
50    category = "Motion",
51    preview_slug = "motion-tokens",
52    preview_label = "Motion Tokens",
53    preview_icon = icondata::AiFieldTimeOutlined,
54)]
55#[component]
56pub fn MotionTokensReference() -> impl IntoView {
57    inject_style("orbital-motion-tokens", token_demo_styles());
58
59    view! {
60        <div>
61            <h3>"Durations"</h3>
62            <div class="orbital-motion-tokens-table" data-testid="motion-tokens-durations">
63                {MotionDuration::ALL.iter().map(|&duration| {
64                    let label = format!("{duration:?}");
65                    let css_var = duration.css_var_name();
66                    let ms = duration.ms();
67                    view! {
68                        <div class="orbital-motion-tokens-row">
69                            <span>{label}</span>
70                            <code>{css_var}</code>
71                            <code>{ms}</code>
72                            <div
73                                class="orbital-motion-tokens-bar"
74                                style=format!("transition: width {ms} ease; width: 100%;")
75                            ></div>
76                        </div>
77                    }
78                }).collect_view()}
79            </div>
80            <h3>"Curves"</h3>
81            <div class="orbital-motion-tokens-table" data-testid="motion-tokens-curves">
82                {[
83                    MotionCurve::Linear,
84                    MotionCurve::AccelerateMax,
85                    MotionCurve::AccelerateMid,
86                    MotionCurve::AccelerateMin,
87                    MotionCurve::DecelerateMax,
88                    MotionCurve::DecelerateMid,
89                    MotionCurve::DecelerateMin,
90                    MotionCurve::EasyEase,
91                    MotionCurve::EasyEaseMax,
92                ].into_iter().map(|curve| {
93                    let label = curve.display_label();
94                    view! {
95                        <div class="orbital-motion-tokens-row">
96                            <span>{label}</span>
97                            <code>{curve.css_var_name()}</code>
98                            <code>{curve.cubic_bezier()}</code>
99                            <span></span>
100                        </div>
101                    }
102                }).collect_view()}
103            </div>
104        </div>
105    }
106}