Merge branch 'main' into main

This commit is contained in:
feral-dot-io 2023-11-11 10:34:32 +00:00 committed by GitHub
commit 776479cafe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 146 additions and 110 deletions

View file

@ -1,3 +0,0 @@
[unstable]
rustflags = ["--cfg=web_sys_unstable_apis"]
rustdocflags = ["--cfg=web_sys_unstable_apis"]

View file

@ -3,6 +3,15 @@
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.2] - 2023-11-09
### Fixes 🍕
- Fixed SSR for
- use_timestamp
- use_raf_fn
- use_idle
## [0.8.1] - 2023-10-28 ## [0.8.1] - 2023-10-28
### Fixes 🍕 ### Fixes 🍕

View file

@ -1,6 +1,6 @@
[package] [package]
name = "leptos-use" name = "leptos-use"
version = "0.8.1" version = "0.8.2"
edition = "2021" edition = "2021"
authors = ["Marc-Stefan Cassola"] authors = ["Marc-Stefan Cassola"]
categories = ["gui", "web-programming"] categories = ["gui", "web-programming"]
@ -27,7 +27,7 @@ prost = { version = "0.12", optional = true }
serde = { version = "1", optional = true } serde = { version = "1", optional = true }
serde_json = { version = "1", optional = true } serde_json = { version = "1", optional = true }
thiserror = "1.0" thiserror = "1.0"
wasm-bindgen = "0.2" wasm-bindgen = "0.2.87"
wasm-bindgen-futures = "0.4" wasm-bindgen-futures = "0.4"
[dependencies.web-sys] [dependencies.web-sys]
@ -102,5 +102,3 @@ ssr = []
[package.metadata.docs.rs] [package.metadata.docs.rs]
all-features = true all-features = true
rustdoc-args = ["--cfg=web_sys_unstable_apis"]
rustc-args = ["--cfg=web_sys_unstable_apis"]

View file

@ -1,2 +0,0 @@
[build]
rustflags = ["--cfg=web_sys_unstable_apis", "--cfg=has_std"]

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_color_mode, 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_timestamp,
ColorMode, UseColorModeReturn, UseIntlNumberFormatOptions, use_window, ColorMode, UseColorModeReturn, UseIntlNumberFormatOptions,
}; };
#[component] #[component]
@ -65,6 +65,8 @@ fn HomePage() -> impl IntoView {
let UseColorModeReturn { mode, set_mode, .. } = use_color_mode(); let UseColorModeReturn { mode, set_mode, .. } = use_color_mode();
let timestamp = use_timestamp();
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>
@ -75,5 +77,6 @@ fn HomePage() -> impl IntoView {
<button on:click=move |_| set_mode.set(ColorMode::Light)>Change to Light</button> <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::Dark)>Change to Dark</button>
<button on:click=move |_| set_mode.set(ColorMode::Auto)>Change to Auto</button> <button on:click=move |_| set_mode.set(ColorMode::Auto)>Change to Auto</button>
<p>{timestamp}</p>
} }
} }

View file

@ -1,2 +0,0 @@
[build]
rustflags = ["--cfg=web_sys_unstable_apis"]

16
src/core/datetime.rs Normal file
View file

@ -0,0 +1,16 @@
use cfg_if::cfg_if;
/// SSR safe `Date.now()`.
#[inline(always)]
pub(crate) fn now() -> f64 {
cfg_if! { if #[cfg(feature = "ssr")] {
use std::time::{SystemTime, UNIX_EPOCH};
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_millis() as f64
} else {
js_sys::Date::now()
}}
}

View file

@ -179,6 +179,7 @@ where
{ {
fn from(target: &'a str) -> Self { fn from(target: &'a str) -> Self {
cfg_if! { if #[cfg(feature = "ssr")] { cfg_if! { if #[cfg(feature = "ssr")] {
let _ = target;
Self::Static(None) Self::Static(None)
} else { } else {
Self::Static(document().query_selector(target).unwrap_or_default()) Self::Static(document().query_selector(target).unwrap_or_default())
@ -201,6 +202,7 @@ where
{ {
fn from(signal: Signal<String>) -> Self { fn from(signal: Signal<String>) -> Self {
cfg_if! { if #[cfg(feature = "ssr")] { cfg_if! { if #[cfg(feature = "ssr")] {
let _ = signal;
Self::Dynamic(Signal::derive(|| None)) Self::Dynamic(Signal::derive(|| None))
} else { } else {
Self::Dynamic( Self::Dynamic(

View file

@ -1,4 +1,5 @@
mod connection_ready_state; mod connection_ready_state;
mod datetime;
mod direction; mod direction;
mod element_maybe_signal; mod element_maybe_signal;
mod elements_maybe_signal; mod elements_maybe_signal;
@ -10,6 +11,7 @@ mod ssr_safe_method;
mod storage; mod storage;
pub use connection_ready_state::*; pub use connection_ready_state::*;
pub(crate) use datetime::*;
pub use direction::*; pub use direction::*;
pub use element_maybe_signal::*; pub use element_maybe_signal::*;
pub use elements_maybe_signal::*; pub use elements_maybe_signal::*;

View file

@ -1,8 +1,6 @@
// #![feature(doc_cfg)] // #![feature(doc_cfg)]
//! Collection of essential Leptos utilities inspired by SolidJS USE / VueUse //! Collection of essential Leptos utilities inspired by SolidJS USE / VueUse
use cfg_if::cfg_if;
pub mod core; pub mod core;
#[cfg(feature = "docs")] #[cfg(feature = "docs")]
pub mod docs; pub mod docs;
@ -11,14 +9,6 @@ pub mod math;
pub mod storage; pub mod storage;
pub mod utils; pub mod utils;
cfg_if! { if #[cfg(web_sys_unstable_apis)] {
mod use_element_size;
mod use_resize_observer;
pub use use_element_size::*;
pub use use_resize_observer::*;
}}
mod is_err; mod is_err;
mod is_none; mod is_none;
mod is_ok; mod is_ok;
@ -37,6 +27,7 @@ mod use_document_visibility;
mod use_draggable; mod use_draggable;
mod use_drop_zone; mod use_drop_zone;
mod use_element_hover; mod use_element_hover;
mod use_element_size;
mod use_element_visibility; mod use_element_visibility;
mod use_event_listener; mod use_event_listener;
mod use_favicon; mod use_favicon;
@ -53,6 +44,7 @@ mod use_mutation_observer;
mod use_preferred_contrast; mod use_preferred_contrast;
mod use_preferred_dark; mod use_preferred_dark;
mod use_raf_fn; mod use_raf_fn;
mod use_resize_observer;
mod use_scroll; mod use_scroll;
mod use_service_worker; mod use_service_worker;
mod use_sorted; mod use_sorted;
@ -89,6 +81,7 @@ pub use use_document_visibility::*;
pub use use_draggable::*; pub use use_draggable::*;
pub use use_drop_zone::*; pub use use_drop_zone::*;
pub use use_element_hover::*; pub use use_element_hover::*;
pub use use_element_size::*;
pub use use_element_visibility::*; pub use use_element_visibility::*;
pub use use_event_listener::*; pub use use_event_listener::*;
pub use use_favicon::*; pub use use_favicon::*;
@ -105,6 +98,7 @@ pub use use_mutation_observer::*;
pub use use_preferred_contrast::*; pub use use_preferred_contrast::*;
pub use use_preferred_dark::*; pub use use_preferred_dark::*;
pub use use_raf_fn::*; pub use use_raf_fn::*;
pub use use_resize_observer::*;
pub use use_scroll::*; pub use use_scroll::*;
pub use use_service_worker::*; pub use use_service_worker::*;
pub use use_sorted::*; pub use use_sorted::*;

View file

@ -12,9 +12,6 @@ cfg_if! { if #[cfg(not(feature = "ssr"))] {
/// Reactive size of an HTML element. /// Reactive size of an HTML element.
/// ///
/// > This function requires `--cfg=web_sys_unstable_apis` to be activated as
/// [described in the wasm-bindgen guide](https://rustwasm.github.io/docs/wasm-bindgen/web-sys/unstable-apis.html).
///
/// Please refer to [ResizeObserver on MDN](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) /// Please refer to [ResizeObserver on MDN](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver)
/// for more details. /// for more details.
/// ///
@ -25,12 +22,12 @@ cfg_if! { if #[cfg(not(feature = "ssr"))] {
/// ## Usage /// ## Usage
/// ///
/// ``` /// ```
/// # use leptos::*; /// # use leptos::{html::Div, *};
/// # use leptos_use::{use_element_size, UseElementSizeReturn}; /// # use leptos_use::{use_element_size, UseElementSizeReturn};
/// # /// #
/// # #[component] /// # #[component]
/// # fn Demo() -> impl IntoView { /// # fn Demo() -> impl IntoView {
/// let el = create_node_ref(); /// let el = create_node_ref::<Div>();
/// ///
/// let UseElementSizeReturn { width, height } = use_element_size(el); /// let UseElementSizeReturn { width, height } = use_element_size(el);
/// ///
@ -175,7 +172,7 @@ where
} }
} }
#[derive(DefaultBuilder)] #[derive(DefaultBuilder, Default)]
/// Options for [`use_element_size_with_options`]. /// Options for [`use_element_size_with_options`].
pub struct UseElementSizeOptions { pub struct UseElementSizeOptions {
/// Initial size returned before any measurements on the `target` are done. Also the value reported /// Initial size returned before any measurements on the `target` are done. Also the value reported
@ -187,15 +184,6 @@ pub struct UseElementSizeOptions {
pub box_: Option<web_sys::ResizeObserverBoxOptions>, pub box_: Option<web_sys::ResizeObserverBoxOptions>,
} }
impl Default for UseElementSizeOptions {
fn default() -> Self {
Self {
initial_size: Size::default(),
box_: None,
}
}
}
/// The return value of [`use_element_size`]. /// The return value of [`use_element_size`].
pub struct UseElementSizeReturn { pub struct UseElementSizeReturn {
/// The width of the element. /// The width of the element.

View file

@ -1,8 +1,10 @@
use crate::core::now;
use crate::utils::{create_filter_wrapper, DebounceOptions, FilterOptions, ThrottleOptions}; use crate::utils::{create_filter_wrapper, DebounceOptions, FilterOptions, ThrottleOptions};
use crate::{ use crate::{
filter_builder_methods, use_document, use_event_listener, use_event_listener_with_options, filter_builder_methods, use_document, use_event_listener, use_event_listener_with_options,
UseEventListenerOptions, UseEventListenerOptions,
}; };
use cfg_if::cfg_if;
use default_struct_builder::DefaultBuilder; use default_struct_builder::DefaultBuilder;
use leptos::ev::{visibilitychange, Custom}; use leptos::ev::{visibilitychange, Custom};
use leptos::leptos_dom::helpers::TimeoutHandle; use leptos::leptos_dom::helpers::TimeoutHandle;
@ -54,6 +56,18 @@ use std::time::Duration;
/// # view! { } /// # view! { }
/// # } /// # }
/// ``` /// ```
///
/// ## Server-Side Rendering
///
/// On the server this will always return static signals
///
/// ```ignore
/// UseIdleReturn{
/// idle: Signal(initial_state),
/// last_active: Signal(now),
/// reset: || {}
/// }
/// ```
pub fn use_idle(timeout: u64) -> UseIdleReturn<impl Fn() + Clone> { pub fn use_idle(timeout: u64) -> UseIdleReturn<impl Fn() + Clone> {
use_idle_with_options(timeout, UseIdleOptions::default()) use_idle_with_options(timeout, UseIdleOptions::default())
} }
@ -71,8 +85,15 @@ pub fn use_idle_with_options(
} = options; } = options;
let (idle, set_idle) = create_signal(initial_state); let (idle, set_idle) = create_signal(initial_state);
let (last_active, set_last_active) = create_signal(js_sys::Date::now()); let (last_active, set_last_active) = create_signal(now());
cfg_if! { if #[cfg(feature = "ssr")] {
let reset = || ();
let _ = timeout;
let _ = events;
let _ = listen_for_visibility_change;
let _ = filter;
} else {
let reset = { let reset = {
let timer = Cell::new(None::<TimeoutHandle>); let timer = Cell::new(None::<TimeoutHandle>);
@ -122,6 +143,7 @@ pub fn use_idle_with_options(
} }
reset.clone()(); reset.clone()();
}}
UseIdleReturn { UseIdleReturn {
idle: idle.into(), idle: idle.into(),

View file

@ -1,10 +1,9 @@
use crate::utils::Pausable; use crate::utils::Pausable;
use cfg_if::cfg_if;
use default_struct_builder::DefaultBuilder; use default_struct_builder::DefaultBuilder;
use leptos::*; use leptos::*;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::rc::Rc; use std::rc::Rc;
use wasm_bindgen::closure::Closure;
use wasm_bindgen::JsCast;
/// Call function on every requestAnimationFrame. /// Call function on every requestAnimationFrame.
/// With controls of pausing and resuming. /// With controls of pausing and resuming.
@ -34,6 +33,10 @@ use wasm_bindgen::JsCast;
/// ///
/// You can use `use_raf_fn_with_options` and set `immediate` to `false`. In that case /// You can use `use_raf_fn_with_options` and set `immediate` to `false`. In that case
/// you have to call `resume()` before the `callback` is executed. /// you have to call `resume()` before the `callback` is executed.
///
/// ## Server-Side Rendering
///
/// On the server this does basically nothing. The provided closure will never be called.
pub fn use_raf_fn( pub fn use_raf_fn(
callback: impl Fn(UseRafFnCallbackArgs) + 'static, callback: impl Fn(UseRafFnCallbackArgs) + 'static,
) -> Pausable<impl Fn() + Clone, impl Fn() + Clone> { ) -> Pausable<impl Fn() + Clone, impl Fn() + Clone> {
@ -54,6 +57,12 @@ pub fn use_raf_fn_with_options(
let loop_ref = Rc::new(RefCell::new(Box::new(|_: f64| {}) as Box<dyn Fn(f64)>)); let loop_ref = Rc::new(RefCell::new(Box::new(|_: f64| {}) as Box<dyn Fn(f64)>));
let request_next_frame = { let request_next_frame = {
cfg_if! { if #[cfg(feature = "ssr")] {
move || ()
} else {
use wasm_bindgen::JsCast;
use wasm_bindgen::closure::Closure;
let loop_ref = Rc::clone(&loop_ref); let loop_ref = Rc::clone(&loop_ref);
let raf_handle = Rc::clone(&raf_handle); let raf_handle = Rc::clone(&raf_handle);
@ -72,6 +81,7 @@ pub fn use_raf_fn_with_options(
.ok(), .ok(),
); );
} }
}}
}; };
let loop_fn = { let loop_fn = {

View file

@ -12,9 +12,6 @@ cfg_if! { if #[cfg(not(feature = "ssr"))] {
/// Reports changes to the dimensions of an Element's content or the border-box. /// Reports changes to the dimensions of an Element's content or the border-box.
/// ///
/// > This function requires `--cfg=web_sys_unstable_apis` to be activated as
/// [described in the wasm-bindgen guide](https://rustwasm.github.io/docs/wasm-bindgen/web-sys/unstable-apis.html).
///
/// Please refer to [ResizeObserver on MDN](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) /// Please refer to [ResizeObserver on MDN](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver)
/// for more details. /// for more details.
/// ///
@ -25,12 +22,12 @@ cfg_if! { if #[cfg(not(feature = "ssr"))] {
/// ## Usage /// ## Usage
/// ///
/// ``` /// ```
/// # use leptos::*; /// # use leptos::{html::Div, *};
/// # use leptos_use::use_resize_observer; /// # use leptos_use::use_resize_observer;
/// # /// #
/// # #[component] /// # #[component]
/// # fn Demo() -> impl IntoView { /// # fn Demo() -> impl IntoView {
/// let el = create_node_ref(); /// let el = create_node_ref::<Div>();
/// let (text, set_text) = create_signal("".to_string()); /// let (text, set_text) = create_signal("".to_string());
/// ///
/// use_resize_observer( /// use_resize_observer(

View file

@ -1,3 +1,4 @@
use crate::core::now;
use crate::utils::Pausable; use crate::utils::Pausable;
use crate::{ use crate::{
use_interval_fn_with_options, use_raf_fn_with_options, UseIntervalFnOptions, UseRafFnOptions, use_interval_fn_with_options, use_raf_fn_with_options, UseIntervalFnOptions, UseRafFnOptions,
@ -47,7 +48,8 @@ use std::rc::Rc;
/// ///
/// ## Server-Side Rendering /// ## Server-Side Rendering
/// ///
/// On the server this function will simply be ignored. /// On the server this function will return a signal with the milliseconds since the Unix epoch.
/// But the signal will never update (as there's no `request_animation_frame` on the server).
pub fn use_timestamp() -> Signal<f64> { pub fn use_timestamp() -> Signal<f64> {
use_timestamp_with_controls().timestamp use_timestamp_with_controls().timestamp
} }
@ -71,10 +73,10 @@ pub fn use_timestamp_with_controls_and_options(options: UseTimestampOptions) ->
callback, callback,
} = options; } = options;
let (ts, set_ts) = create_signal(js_sys::Date::now() + offset); let (ts, set_ts) = create_signal(now() + offset);
let update = move || { let update = move || {
set_ts.set(js_sys::Date::now() + offset); set_ts.set(now() + offset);
}; };
let cb = { let cb = {

View file

@ -1,8 +1,8 @@
#![cfg_attr(feature = "ssr", allow(unused_variables, unused_imports))] #![cfg_attr(feature = "ssr", allow(unused_variables, unused_imports))]
use crate::core::now;
use cfg_if::cfg_if; use cfg_if::cfg_if;
use default_struct_builder::DefaultBuilder; use default_struct_builder::DefaultBuilder;
use js_sys::Date;
use leptos::leptos_dom::helpers::TimeoutHandle; use leptos::leptos_dom::helpers::TimeoutHandle;
use leptos::{set_timeout_with_handle, MaybeSignal, SignalGetUntracked}; use leptos::{set_timeout_with_handle, MaybeSignal, SignalGetUntracked};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
@ -51,7 +51,7 @@ where
move |mut _invoke: Rc<dyn Fn() -> R>| { move |mut _invoke: Rc<dyn Fn() -> R>| {
let duration = ms.get_untracked(); let duration = ms.get_untracked();
let elapsed = Date::now() - last_exec.get(); let elapsed = now() - last_exec.get();
let last_return_val = Rc::clone(&last_return_value); let last_return_val = Rc::clone(&last_return_value);
let invoke = move || { let invoke = move || {
@ -65,13 +65,13 @@ where
clear(); clear();
if duration <= 0.0 { if duration <= 0.0 {
last_exec.set(Date::now()); last_exec.set(now());
invoke(); invoke();
return Rc::clone(&last_return_value); return Rc::clone(&last_return_value);
} }
if elapsed > duration && (options.leading || !is_leading.get()) { if elapsed > duration && (options.leading || !is_leading.get()) {
last_exec.set(Date::now()); last_exec.set(now());
invoke(); invoke();
} else if options.trailing { } else if options.trailing {
cfg_if! { if #[cfg(not(feature = "ssr"))] { cfg_if! { if #[cfg(not(feature = "ssr"))] {
@ -80,7 +80,7 @@ where
timer.set( timer.set(
set_timeout_with_handle( set_timeout_with_handle(
move || { move || {
last_exec.set(Date::now()); last_exec.set(now());
is_leading.set(true); is_leading.set(true);
invoke(); invoke();
clear(); clear();