made ElementMaybeSignal's from string conversion SSR safe.

Fixes #41
This commit is contained in:
Maccesch 2023-10-28 16:18:29 -05:00
parent 8c2beb814d
commit 7084b91c0a
14 changed files with 88 additions and 41 deletions

View file

@ -3,6 +3,13 @@
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.8.1] - 2023-10-28
### Fixes 🍕
- Using strings for `ElementMaybeSignal` and `ElementsMaybeSignal` is now SSR safe.
- This fixes specifically `use_color_mode` to work on the server.
## [0.8.0] - 2023-10-24 ## [0.8.0] - 2023-10-24
### New Functions 🚀 ### New Functions 🚀

View file

@ -1,6 +1,6 @@
[package] [package]
name = "leptos-use" name = "leptos-use"
version = "0.8.0" version = "0.8.1"
edition = "2021" edition = "2021"
authors = ["Marc-Stefan Cassola"] authors = ["Marc-Stefan Cassola"]
categories = ["gui", "web-programming"] categories = ["gui", "web-programming"]

View file

@ -5,8 +5,8 @@ use leptos_meta::*;
use leptos_router::*; use leptos_router::*;
use leptos_use::storage::use_local_storage; use leptos_use::storage::use_local_storage;
use leptos_use::{ use leptos_use::{
use_debounce_fn, use_event_listener, use_intl_number_format, use_window, use_color_mode, use_debounce_fn, use_event_listener, use_intl_number_format, use_window,
UseIntlNumberFormatOptions, ColorMode, UseColorModeReturn, UseIntlNumberFormatOptions,
}; };
#[component] #[component]
@ -63,11 +63,17 @@ fn HomePage() -> impl IntoView {
); );
debounced_fn(); debounced_fn();
let UseColorModeReturn { mode, set_mode, .. } = use_color_mode();
view! { view! {
<h1>Leptos-Use SSR Example</h1> <h1>Leptos-Use SSR Example</h1>
<button on:click=on_click>Click Me: {count}</button> <button on:click=on_click>Click Me: {count}</button>
<p>Locale zh-Hans-CN-u-nu-hanidec: {zh_count}</p> <p>Locale zh-Hans-CN-u-nu-hanidec: {zh_count}</p>
<p>Press any key: {key}</p> <p>Press any key: {key}</p>
<p>Debounced called: {debounce_value}</p> <p>Debounced called: {debounce_value}</p>
<p>Color mode: {move || format!("{:?}", mode.get())}</p>
<button on:click=move |_| set_mode.set(ColorMode::Light)>Change to Light</button>
<button on:click=move |_| set_mode.set(ColorMode::Dark)>Change to Dark</button>
<button on:click=move |_| set_mode.set(ColorMode::Auto)>Change to Auto</button>
} }
} }

View file

@ -1,4 +1,9 @@
body { body {
font-family: sans-serif; font-family: sans-serif;
text-align: center; text-align: center;
}
.dark {
background-color: black;
color: white;
} }

View file

@ -1,4 +1,5 @@
use crate::{UseDocument, UseWindow}; use crate::{UseDocument, UseWindow};
use cfg_if::cfg_if;
use leptos::html::ElementDescriptor; use leptos::html::ElementDescriptor;
use leptos::*; use leptos::*;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -177,7 +178,11 @@ where
E: From<web_sys::Element> + 'static, E: From<web_sys::Element> + 'static,
{ {
fn from(target: &'a str) -> Self { fn from(target: &'a str) -> Self {
Self::Static(document().query_selector(target).unwrap_or_default()) cfg_if! { if #[cfg(feature = "ssr")] {
Self::Static(None)
} else {
Self::Static(document().query_selector(target).unwrap_or_default())
}}
} }
} }
@ -186,7 +191,7 @@ where
E: From<web_sys::Element> + 'static, E: From<web_sys::Element> + 'static,
{ {
fn from(target: String) -> Self { fn from(target: String) -> Self {
Self::Static(document().query_selector(&target).unwrap_or_default()) Self::from(target.as_str())
} }
} }
@ -195,10 +200,14 @@ where
E: From<web_sys::Element> + 'static, E: From<web_sys::Element> + 'static,
{ {
fn from(signal: Signal<String>) -> Self { fn from(signal: Signal<String>) -> Self {
Self::Dynamic( cfg_if! { if #[cfg(feature = "ssr")] {
create_memo(move |_| document().query_selector(&signal.get()).unwrap_or_default()) Self::Dynamic(Signal::derive(|| None))
.into(), } else {
) Self::Dynamic(
create_memo(move |_| document().query_selector(&signal.get()).unwrap_or_default())
.into(),
)
}}
} }
} }

View file

@ -1,5 +1,6 @@
use crate::core::ElementMaybeSignal; use crate::core::ElementMaybeSignal;
use crate::{UseDocument, UseWindow}; use crate::{UseDocument, UseWindow};
use cfg_if::cfg_if;
use leptos::html::ElementDescriptor; use leptos::html::ElementDescriptor;
use leptos::*; use leptos::*;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -178,17 +179,31 @@ where
E: From<web_sys::Node> + 'static, E: From<web_sys::Node> + 'static,
{ {
fn from(target: &'a str) -> Self { fn from(target: &'a str) -> Self {
if let Ok(node_list) = document().query_selector_all(target) { cfg_if! { if #[cfg(feature = "ssr")] {
let mut list = Vec::with_capacity(node_list.length() as usize); if let Ok(node_list) = document().query_selector_all(target) {
for i in 0..node_list.length() { let mut list = Vec::with_capacity(node_list.length() as usize);
let node = node_list.get(i).expect("checked the range"); for i in 0..node_list.length() {
list.push(Some(node)); let node = node_list.get(i).expect("checked the range");
} list.push(Some(node));
}
Self::Static(list) Self::Static(list)
} else {
Self::Static(vec![])
}
} else { } else {
let _ = target;
Self::Static(vec![]) Self::Static(vec![])
} }}
}
}
impl<E> From<String> for ElementsMaybeSignal<web_sys::Node, E>
where
E: From<web_sys::Node> + 'static,
{
fn from(target: String) -> Self {
Self::from(target.as_str())
} }
} }
@ -197,21 +212,26 @@ where
E: From<web_sys::Node> + 'static, E: From<web_sys::Node> + 'static,
{ {
fn from(signal: Signal<String>) -> Self { fn from(signal: Signal<String>) -> Self {
Self::Dynamic( cfg_if! { if #[cfg(feature = "ssr")] {
create_memo(move |_| { Self::Dynamic(
if let Ok(node_list) = document().query_selector_all(&signal.get()) { create_memo(move |_| {
let mut list = Vec::with_capacity(node_list.length() as usize); if let Ok(node_list) = document().query_selector_all(&signal.get()) {
for i in 0..node_list.length() { let mut list = Vec::with_capacity(node_list.length() as usize);
let node = node_list.get(i).expect("checked the range"); for i in 0..node_list.length() {
list.push(Some(node)); let node = node_list.get(i).expect("checked the range");
list.push(Some(node));
}
list
} else {
vec![]
} }
list })
} else { .into(),
vec![] )
} } else {
}) let _ = signal;
.into(), Self::Dynamic(Signal::derive(Vec::new))
) }}
} }
} }

View file

@ -125,7 +125,7 @@ where
}) })
}; };
let target = (target).into(); let target = target.into();
let listener = { let listener = {
let should_listen = Rc::clone(&should_listen); let should_listen = Rc::clone(&should_listen);

View file

@ -160,7 +160,7 @@ where
} }
}); });
let target = (target).into(); let target = target.into();
let update_html_attrs = { let update_html_attrs = {
move |target: ElementMaybeSignal<T, web_sys::Element>, move |target: ElementMaybeSignal<T, web_sys::Element>,

View file

@ -105,7 +105,7 @@ where
let (variable, set_variable) = create_signal(initial_value.clone()); let (variable, set_variable) = create_signal(initial_value.clone());
cfg_if! { if #[cfg(not(feature = "ssr"))] { cfg_if! { if #[cfg(not(feature = "ssr"))] {
let el_signal = (target).into(); let el_signal = target.into();
let prop = prop.into(); let prop = prop.into();
let update_css_var = { let update_css_var = {

View file

@ -87,7 +87,7 @@ where
.. ..
} = options; } = options;
let target = (target).into(); let target = target.into();
let dragging_handle = if let Some(handle) = handle { let dragging_handle = if let Some(handle) = handle {
let handle = (handle).into(); let handle = (handle).into();

View file

@ -132,7 +132,7 @@ where
let event_name = event.name(); let event_name = event.name();
let signal = (target).into(); let signal = target.into();
let prev_element = Rc::new(RefCell::new(None::<web_sys::EventTarget>)); let prev_element = Rc::new(RefCell::new(None::<web_sys::EventTarget>));

View file

@ -124,7 +124,7 @@ where
} }
}; };
let targets = (target).into(); let targets = target.into();
let root = root.map(|root| (root).into()); let root = root.map(|root| (root).into());
let stop_watch = { let stop_watch = {

View file

@ -109,7 +109,7 @@ where
} }
}; };
let targets = (target).into(); let targets = target.into();
let stop_watch = { let stop_watch = {
let cleanup = cleanup.clone(); let cleanup = cleanup.clone();

View file

@ -114,7 +114,7 @@ where
} }
}; };
let targets = (target).into(); let targets = target.into();
let stop_watch = { let stop_watch = {
let cleanup = cleanup.clone(); let cleanup = cleanup.clone();