leptos_use/use_prefers_reduced_motion.rs
1use crate::utils::get_header;
2use default_struct_builder::DefaultBuilder;
3use leptos::prelude::*;
4use std::sync::Arc;
5
6/// Reactive [reduced motions preference](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion).
7///
8/// ## Demo
9///
10/// [Link to Demo](https://github.com/Synphonyte/leptos-use/tree/main/examples/use_prefers_reduced_motion)
11///
12/// ## Usage
13///
14/// ```
15/// # use leptos::prelude::*;
16/// # use leptos_use::use_prefers_reduced_motion;
17/// #
18/// # #[component]
19/// # fn Demo() -> impl IntoView {
20/// let is_reduced_motion_preferred = use_prefers_reduced_motion();
21///
22/// view! {
23/// <div>
24/// <p>Prefers reduced motions: {move || if is_reduced_motion_preferred.get() { "Yes" } else { "No" }}</p>
25/// <p>
26/// Update reduce motion preference
27/// <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion#user_preferences">
28/// documentation.
29/// </a>
30/// </p>
31/// </div>
32/// }
33/// # }
34/// ```
35///
36/// ## Server-Side Rendering
37///
38/// > Make sure you follow the [instructions in Server-Side Rendering](https://leptos-use.rs/server_side_rendering.html).
39///
40/// On the server this will try to read the
41/// [`Sec-CH-Prefers-Reduced-Motion` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-Prefers-Reduced-Motion)
42/// to indicate the preference for animations to be displayed with reduced motion.
43/// Please have a look at the linked documentation above to see browser support
44/// as well as potential serve requirements.
45///
46/// > If you're using `axum` you have to enable the `"axum"` feature in your Cargo.toml.
47/// > In case it's `actix-web` enable the feature `"actix"`.
48///
49/// ### Bring your own header
50///
51/// In case you're neither using Axum nor Actix or the default implementation is not to your
52/// liking, you can provide your own way of reading the reduced motion header value using the option
53/// [`crate::UsePrefersReducedMotionOptions::ssr_motion_header_getter`].
54///
55/// ## See also
56///
57/// * [`fn@crate::use_media_query`]
58/// * [`fn@crate::use_preferred_contrast`]
59/// * [`fn@crate::use_preferred_dark`]
60pub fn use_prefers_reduced_motion() -> Signal<bool> {
61 use_prefers_reduced_motion_with_options(UsePrefersReducedMotionOptions::default())
62}
63
64/// Version of [`fn@crate::use_prefers_reduced_motion`] that takes a `UsePrefersReducedMotionOptions`. See [`fn@crate::use_prefers_reduced_motion`] for how to use.
65pub fn use_prefers_reduced_motion_with_options(
66 options: UsePrefersReducedMotionOptions,
67) -> Signal<bool> {
68 #[cfg(not(feature = "ssr"))]
69 {
70 let _ = options;
71 crate::use_media_query("(prefers-reduced-motion: reduce)")
72 }
73 #[cfg(feature = "ssr")]
74 {
75 Signal::derive(move || (options.ssr_motion_header_getter)() == Some("reduce".to_string()))
76 }
77}
78
79/// Options for [`fn@crate::use_prefers_reduced_motion_with_options`].
80#[derive(DefaultBuilder)]
81pub struct UsePrefersReducedMotionOptions {
82 /// Getter function to return the string value of the
83 /// [`Sec-CH-Prefers-Reduced-Motion`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-CH-Prefers-Reduced-Motion)
84 /// header.
85 /// When you use one of the features `"axum"` or `"actix"` there's a valid default
86 /// implementation provided.
87 #[allow(dead_code)]
88 pub(crate) ssr_motion_header_getter: Arc<dyn Fn() -> Option<String> + Send + Sync>,
89}
90
91impl Default for UsePrefersReducedMotionOptions {
92 fn default() -> Self {
93 Self {
94 ssr_motion_header_getter: Arc::new(move || {
95 get_header!(
96 HeaderName::from_static("sec-ch-prefers-reduced-motion"),
97 use_prefers_reduced_motion,
98 ssr_motion_header_getter
99 )
100 }),
101 }
102 }
103}