fixed some SSR issues with not using use_window() in some functions

This commit is contained in:
Maccesch 2023-10-21 15:21:11 -05:00
parent dd2e88f8dd
commit f3af2ad9ea
15 changed files with 88 additions and 64 deletions

View file

@ -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 🚀

View file

@ -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"]

View file

@ -1,5 +1,5 @@
[package]
name = "start-axum"
name = "leptos-use-ssr"
version = "0.1.0"
edition = "2021"

View file

@ -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");
@ -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()

View file

@ -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,

View file

@ -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());
});

View file

@ -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::*;
@ -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::*;

View file

@ -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;

View file

@ -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::*;
@ -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() {
@ -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());

View file

@ -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;
@ -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();
}

View file

@ -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::*;
@ -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()
);
}

View file

@ -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::*;
@ -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())
@ -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(),

View file

@ -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};
@ -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,
{
@ -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(),
}
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,
}
}
} 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(),
}
}
}
}}
}
/// Defines how to get the coordinates from the event.
#[derive(Clone)]

View file

@ -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;
@ -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))
);
}

View file

@ -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