Skip to content

Commit

Permalink
fixed some SSR issues with not using use_window() in some functions
Browse files Browse the repository at this point in the history
  • Loading branch information
maccesch committed Oct 21, 2023
1 parent dd2e88f commit f3af2ad
Show file tree
Hide file tree
Showing 15 changed files with 88 additions and 64 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.7.2] - 2023-10-21

### Fixes 🍕

- Some functions still used `window()` which could lead to panics in SSR. This is now fixed.
Specifically for `use_draggable`.

## [0.7.1] - 2023-10-02

### New Function 🚀
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "leptos-use"
version = "0.7.1"
version = "0.7.2"
edition = "2021"
authors = ["Marc-Stefan Cassola"]
categories = ["gui", "web-programming"]
Expand Down
2 changes: 1 addition & 1 deletion examples/ssr/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "start-axum"
name = "leptos-use-ssr"
version = "0.1.0"
edition = "2021"

Expand Down
6 changes: 3 additions & 3 deletions examples/ssr/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ async fn main() {
use leptos::logging::log;
use leptos::*;
use leptos_axum::{generate_route_list, LeptosRoutes};
use start_axum::app::*;
use start_axum::fileserv::file_and_error_handler;
use leptos_use_ssr::app::*;
use leptos_use_ssr::fileserv::file_and_error_handler;

simple_logger::init_with_level(log::Level::Debug).expect("couldn't initialize logging");

Expand All @@ -18,7 +18,7 @@ async fn main() {
let conf = get_configuration(None).await.unwrap();
let leptos_options = conf.leptos_options;
let addr = leptos_options.site_addr;
let routes = generate_route_list(|| view! { <App/> }).await;
let routes = generate_route_list(|| view! { <App/> });

// build our application with a route
let app = Router::new()
Expand Down
7 changes: 5 additions & 2 deletions examples/use_draggable/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ use leptos::html::Div;
use leptos::*;
use leptos_use::core::Position;
use leptos_use::docs::demo_or_body;
use leptos_use::{use_draggable_with_options, UseDraggableOptions, UseDraggableReturn};
use leptos_use::{use_draggable_with_options, use_window, UseDraggableOptions, UseDraggableReturn};

#[component]
fn Demo() -> impl IntoView {
let el = create_node_ref::<Div>();

let inner_width = window().inner_width().unwrap().as_f64().unwrap();
let inner_width = use_window()
.as_ref()
.map(|w| w.inner_width().unwrap().as_f64().unwrap())
.unwrap_or(0.0);

let UseDraggableReturn { x, y, style, .. } = use_draggable_with_options(
el,
Expand Down
4 changes: 2 additions & 2 deletions examples/use_event_listener/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ use leptos::ev::{click, keydown};
use leptos::html::A;
use leptos::logging::log;
use leptos::*;
use leptos_use::use_event_listener;
use leptos_use::{use_event_listener, use_window};

#[component]
fn Demo() -> impl IntoView {
let _ = use_event_listener(window(), keydown, |evt| {
let _ = use_event_listener(use_window(), keydown, |evt| {
log!("window keydown: '{}'", evt.key());
});

Expand Down
2 changes: 2 additions & 0 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod maybe_rw_signal;
mod pointer_type;
mod position;
mod size;
mod ssr_safe_method;
mod storage;

pub use connection_ready_state::*;
Expand All @@ -14,4 +15,5 @@ pub use maybe_rw_signal::*;
pub use pointer_type::*;
pub use position::*;
pub use size::*;
pub(crate) use ssr_safe_method::*;
pub use storage::*;
19 changes: 19 additions & 0 deletions src/core/ssr_safe_method.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
macro_rules! impl_ssr_safe_method {
(
$(#[$attr:meta])*
$method:ident(&self$(, $p_name:ident: $p_ty:ty)*) -> $return_ty:ty
$(; $($post_fix:tt)+)?
) => {
$(#[$attr])*
#[inline(always)]
pub fn $method(&self, $($p_name: $p_ty),*) -> $return_ty {
self.0.as_ref()
.map(
|w| w.$method($($p_name),*)
)
$($($post_fix)+)?
}
};
}

pub(crate) use impl_ssr_safe_method;
6 changes: 3 additions & 3 deletions src/use_active_element.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![cfg_attr(feature = "ssr", allow(unused_variables, unused_imports))]

use crate::{use_document, use_event_listener_with_options, UseEventListenerOptions};
use crate::{use_document, use_event_listener_with_options, use_window, UseEventListenerOptions};
use leptos::ev::{blur, focus};
use leptos::html::{AnyElement, ToHtmlElement};
use leptos::*;
Expand Down Expand Up @@ -45,7 +45,7 @@ pub fn use_active_element() -> Signal<Option<HtmlElement<AnyElement>>> {
let listener_options = UseEventListenerOptions::default().capture(true);

let _ = use_event_listener_with_options(
window(),
use_window(),
blur,
move |event| {
if event.related_target().is_some() {
Expand All @@ -58,7 +58,7 @@ pub fn use_active_element() -> Signal<Option<HtmlElement<AnyElement>>> {
);

let _ = use_event_listener_with_options(
window(),
use_window(),
focus,
move |_| {
set_active_element.update(|el| *el = get_active_element());
Expand Down
4 changes: 2 additions & 2 deletions src/use_breakpoints.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::use_media_query;
use crate::{use_media_query, use_window};
use leptos::logging::error;
use leptos::*;
use paste::paste;
Expand Down Expand Up @@ -185,7 +185,7 @@ macro_rules! impl_cmp_reactively {

impl<K: Eq + Hash + Debug + Clone> UseBreakpointsReturn<K> {
fn match_(query: &str) -> bool {
if let Ok(Some(query_list)) = window().match_media(query) {
if let Ok(Some(query_list)) = use_window().match_media(query) {
return query_list.matches();
}

Expand Down
17 changes: 11 additions & 6 deletions src/use_document.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use cfg_if::cfg_if;
use std::ops::Deref;

use crate::core::impl_ssr_safe_method;
#[cfg(not(feature = "ssr"))]
use leptos::*;

Expand Down Expand Up @@ -46,11 +47,15 @@ impl Deref for UseDocument {
}

impl UseDocument {
pub fn body(&self) -> Option<web_sys::HtmlElement> {
self.0.as_ref().and_then(|d| d.body())
}
impl_ssr_safe_method!(
/// Returns `Some(Document)` in the Browser. `None` otherwise.
body(&self) -> Option<web_sys::HtmlElement>;
.unwrap_or_default()
);

pub fn active_element(&self) -> Option<web_sys::Element> {
self.0.as_ref().and_then(|d| d.active_element())
}
impl_ssr_safe_method!(
/// Returns the active (focused) `Some(web_sys::Element)` in the Browser. `None` otherwise.
active_element(&self) -> Option<web_sys::Element>;
.unwrap_or_default()
);
}
15 changes: 5 additions & 10 deletions src/use_draggable.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::core::{ElementMaybeSignal, MaybeRwSignal, PointerType, Position};
use crate::{use_event_listener_with_options, UseEventListenerOptions};
use crate::{use_event_listener_with_options, use_window, UseEventListenerOptions, UseWindow};
use default_struct_builder::DefaultBuilder;
use leptos::ev::{pointerdown, pointermove, pointerup};
use leptos::*;
Expand Down Expand Up @@ -52,8 +52,8 @@ where
use_draggable_with_options::<
El,
T,
web_sys::EventTarget,
web_sys::EventTarget,
UseWindow,
web_sys::Window,
web_sys::EventTarget,
web_sys::EventTarget,
>(target, UseDraggableOptions::default())
Expand Down Expand Up @@ -267,19 +267,14 @@ where
}

impl Default
for UseDraggableOptions<
web_sys::EventTarget,
web_sys::EventTarget,
web_sys::EventTarget,
web_sys::EventTarget,
>
for UseDraggableOptions<UseWindow, web_sys::Window, web_sys::EventTarget, web_sys::EventTarget>
{
fn default() -> Self {
Self {
exact: MaybeSignal::default(),
prevent_default: MaybeSignal::default(),
stop_propagation: MaybeSignal::default(),
dragging_element: window().into(),
dragging_element: use_window(),
handle: None,
pointer_types: vec![PointerType::Mouse, PointerType::Touch, PointerType::Pen],
initial_value: MaybeRwSignal::default(),
Expand Down
40 changes: 12 additions & 28 deletions src/use_mouse.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![cfg_attr(feature = "ssr", allow(unused_variables, unused_imports))]

use crate::core::{ElementMaybeSignal, Position};
use crate::{use_event_listener_with_options, UseEventListenerOptions};
use crate::{use_event_listener_with_options, use_window, UseEventListenerOptions, UseWindow};
use cfg_if::cfg_if;
use default_struct_builder::DefaultBuilder;
use leptos::ev::{dragover, mousemove, touchend, touchmove, touchstart};
Expand Down Expand Up @@ -208,8 +208,7 @@ where
/// Options for [`use_mouse_with_options`].
pub struct UseMouseOptions<El, T, Ex>
where
El: Clone,
El: Into<ElementMaybeSignal<T, web_sys::EventTarget>>,
El: Clone + Into<ElementMaybeSignal<T, web_sys::EventTarget>>,
T: Into<web_sys::EventTarget> + Clone + 'static,
Ex: UseMouseEventExtractor + Clone,
{
Expand All @@ -232,33 +231,18 @@ where
_marker: PhantomData<T>,
}

cfg_if! { if #[cfg(feature = "ssr")] {
impl Default for UseMouseOptions<Option<web_sys::Window>, web_sys::Window, UseMouseEventExtractorDefault> {
fn default() -> Self {
Self {
coord_type: UseMouseCoordType::<UseMouseEventExtractorDefault>::default(),
target: None,
touch: true,
reset_on_touch_ends: false,
initial_value: Position { x: 0.0, y: 0.0 },
_marker: Default::default(),
}
}
}
} else {
impl Default for UseMouseOptions<web_sys::Window, web_sys::Window, UseMouseEventExtractorDefault> {
fn default() -> Self {
Self {
coord_type: UseMouseCoordType::<UseMouseEventExtractorDefault>::default(),
target: window(),
touch: true,
reset_on_touch_ends: false,
initial_value: Position { x: 0.0, y: 0.0 },
_marker: Default::default(),
}
impl Default for UseMouseOptions<UseWindow, web_sys::Window, UseMouseEventExtractorDefault> {
fn default() -> Self {
Self {
coord_type: UseMouseCoordType::<UseMouseEventExtractorDefault>::default(),
target: use_window(),
touch: true,
reset_on_touch_ends: false,
initial_value: Position { x: 0.0, y: 0.0 },
_marker: PhantomData,
}
}
}}
}

/// Defines how to get the coordinates from the event.
#[derive(Clone)]
Expand Down
15 changes: 11 additions & 4 deletions src/use_window.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::core::impl_ssr_safe_method;
use crate::{use_document, UseDocument};
use cfg_if::cfg_if;
use std::ops::Deref;
Expand Down Expand Up @@ -48,14 +49,20 @@ impl Deref for UseWindow {
}

impl UseWindow {
/// Returns the `Some(Navigator)` in the Browser. `None` otherwise.
pub fn navigator(&self) -> Option<web_sys::Navigator> {
self.0.as_ref().map(|w| w.navigator())
}
impl_ssr_safe_method!(
/// Returns `Some(Navigator)` in the Browser. `None` otherwise.
navigator(&self) -> Option<web_sys::Navigator>
);

/// Returns the same as [`use_document`].
#[inline(always)]
pub fn document(&self) -> UseDocument {
use_document()
}

impl_ssr_safe_method!(
/// Returns the same as `window().match_media()` in the Browser. `Ok(None)` otherwise.
match_media(&self, query: &str) -> Result<Option<web_sys::MediaQueryList>, wasm_bindgen::JsValue>;
.unwrap_or(Ok(None))
);
}
6 changes: 4 additions & 2 deletions src/utils/is.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::use_window;
use lazy_static::lazy_static;
use leptos::*;

lazy_static! {
pub static ref IS_IOS: bool = if let Ok(user_agent) = window().navigator().user_agent() {
pub static ref IS_IOS: bool = if let Some(Ok(user_agent)) =
use_window().navigator().map(|n| n.user_agent())
{
user_agent.contains("iPhone") || user_agent.contains("iPad") || user_agent.contains("iPod")
} else {
false
Expand Down

0 comments on commit f3af2ad

Please sign in to comment.