mirror of
https://github.com/adoyle0/leptos-use.git
synced 2025-01-23 09:09:21 -05:00
added watch and use_supported
This commit is contained in:
parent
af1eee6f28
commit
715f858ea2
12 changed files with 244 additions and 11 deletions
|
@ -1,5 +1,12 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.1.4
|
||||||
|
|
||||||
|
#### New Functions
|
||||||
|
- `use_supported`
|
||||||
|
- `use_resize_observer`
|
||||||
|
- `watch`
|
||||||
|
|
||||||
## 0.1.3
|
## 0.1.3
|
||||||
|
|
||||||
#### New Functions
|
#### New Functions
|
||||||
|
|
15
Cargo.toml
15
Cargo.toml
|
@ -14,10 +14,23 @@ repository = "https://github.com/Synphonyte/leptos-use"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
leptos = "0.3.0"
|
leptos = "0.3.0"
|
||||||
web-sys = { version = "0.3.63", features = ["ScrollToOptions", "ScrollBehavior", "CssStyleDeclaration"] }
|
|
||||||
wasm-bindgen = "0.2.86"
|
wasm-bindgen = "0.2.86"
|
||||||
js-sys = "0.3.63"
|
js-sys = "0.3.63"
|
||||||
default-struct-builder = "0.1.0"
|
default-struct-builder = "0.1.0"
|
||||||
|
|
||||||
|
[dependencies.web-sys]
|
||||||
|
version = "0.3.63"
|
||||||
|
features = [
|
||||||
|
"ScrollToOptions",
|
||||||
|
"ScrollBehavior",
|
||||||
|
"CssStyleDeclaration",
|
||||||
|
"ResizeObserver",
|
||||||
|
"ResizeObserverOptions",
|
||||||
|
"ResizeObserverBoxOptions",
|
||||||
|
"ResizeObserverSize",
|
||||||
|
"ResizeObserverEntry",
|
||||||
|
"Navigator",
|
||||||
|
]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
docs = []
|
docs = []
|
|
@ -16,7 +16,12 @@
|
||||||
|
|
||||||
- [use_scroll](sensors/use_scroll.md)
|
- [use_scroll](sensors/use_scroll.md)
|
||||||
|
|
||||||
|
# Watch
|
||||||
|
|
||||||
|
- [watch](watch/watch.md)
|
||||||
|
|
||||||
# Utilities
|
# Utilities
|
||||||
|
|
||||||
- [use_debounce_fn](utilities/use_debounce_fn.md)
|
- [use_debounce_fn](utilities/use_debounce_fn.md)
|
||||||
|
- [use_supported](utilities/use_supported.md)
|
||||||
- [use_throttle_fn](utilities/use_throttle_fn.md)
|
- [use_throttle_fn](utilities/use_throttle_fn.md)
|
|
@ -21,3 +21,16 @@ pre > code {
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.meta-data {
|
||||||
|
font-size: 87.5%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 70px auto;
|
||||||
|
gap: 2rem;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin: 2rem 0 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-data > div:first-child {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
category = os.path.split(os.getcwd())[-1]
|
||||||
|
|
||||||
|
print(f"""
|
||||||
|
<div class="meta-data">
|
||||||
|
<div>Category</div>
|
||||||
|
<div>{category.title()}</div>
|
||||||
|
</div>
|
||||||
|
""")
|
||||||
|
|
||||||
name = sys.argv[1]
|
name = sys.argv[1]
|
||||||
file_name = f"../../../../src/{name}.rs"
|
file_name = f"../../../../src/{name}.rs"
|
||||||
|
|
||||||
|
@ -49,8 +59,11 @@ def add_source_paragraph(name):
|
||||||
demo_url = f"https://github.com/Synphonyte/leptos-use/tree/main/examples/{name}"
|
demo_url = f"https://github.com/Synphonyte/leptos-use/tree/main/examples/{name}"
|
||||||
docs_url = f"https://docs.rs/leptos-use/latest/leptos_use/fn.{name}.html"
|
docs_url = f"https://docs.rs/leptos-use/latest/leptos_use/fn.{name}.html"
|
||||||
|
|
||||||
|
demo_link = " • <a href=\"{demo_url}\" target=\"_blank\">Demo</a>" if os.path.isdir(
|
||||||
|
os.path.join("..", "..", "..", "..", "examples", name)) else ""
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f"<a href=\"{source_url}\" target=\"_blank\">Source</a> • <a href=\"{demo_url}\" target=\"_blank\">Demo</a> • <a href=\"{docs_url}\" target=\"_blank\">Docs</a>")
|
f"<a href=\"{source_url}\" target=\"_blank\">Source</a>{demo_link} • <a href=\"{docs_url}\" target=\"_blank\">Docs</a>")
|
||||||
|
|
||||||
|
|
||||||
interal_doc_link_pattern = re.compile(r"\[`([^]]+)\`](?!\()")
|
interal_doc_link_pattern = re.compile(r"\[`([^]]+)\`](?!\()")
|
||||||
|
|
3
docs/book/src/utilities/use_supported.md
Normal file
3
docs/book/src/utilities/use_supported.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# use_supported
|
||||||
|
|
||||||
|
<!-- cmdrun python3 ../extract_doc_comment.py use_supported -->
|
3
docs/book/src/watch/watch.md
Normal file
3
docs/book/src/watch/watch.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# watch
|
||||||
|
|
||||||
|
<!-- cmdrun python3 ../extract_doc_comment.py watch -->
|
19
src/lib.rs
19
src/lib.rs
|
@ -1,18 +1,25 @@
|
||||||
//! Collection of essential Leptos utilities inspired by SolidJS USE / VueUse
|
//! Collection of essential Leptos utilities inspired by SolidJS USE / VueUse
|
||||||
|
|
||||||
pub mod core;
|
pub mod core;
|
||||||
mod use_debounce_fn;
|
|
||||||
mod use_event_listener;
|
|
||||||
mod use_scroll;
|
|
||||||
mod use_throttle_fn;
|
|
||||||
pub mod utils;
|
|
||||||
|
|
||||||
#[cfg(feature = "docs")]
|
#[cfg(feature = "docs")]
|
||||||
pub mod docs;
|
pub mod docs;
|
||||||
|
mod use_debounce_fn;
|
||||||
|
mod use_event_listener;
|
||||||
|
#[cfg(web_sys_unstable_apis)]
|
||||||
|
mod use_resize_observer;
|
||||||
|
mod use_scroll;
|
||||||
|
mod use_supported;
|
||||||
|
mod use_throttle_fn;
|
||||||
|
pub mod utils;
|
||||||
|
mod watch;
|
||||||
|
|
||||||
pub use use_debounce_fn::*;
|
pub use use_debounce_fn::*;
|
||||||
pub use use_event_listener::*;
|
pub use use_event_listener::*;
|
||||||
|
#[cfg(web_sys_unstable_apis)]
|
||||||
|
pub use use_resize_observer::*;
|
||||||
pub use use_scroll::*;
|
pub use use_scroll::*;
|
||||||
|
pub use use_supported::*;
|
||||||
pub use use_throttle_fn::*;
|
pub use use_throttle_fn::*;
|
||||||
|
pub use watch::*;
|
||||||
|
|
||||||
extern crate self as leptos_use;
|
extern crate self as leptos_use;
|
||||||
|
|
|
@ -64,7 +64,7 @@ use leptos::MaybeSignal;
|
||||||
/// ## Recommended Reading
|
/// ## Recommended Reading
|
||||||
///
|
///
|
||||||
/// - [**Debounce vs Throttle**: Definitive Visual Guide](https://redd.one/blog/debounce-vs-throttle)
|
/// - [**Debounce vs Throttle**: Definitive Visual Guide](https://redd.one/blog/debounce-vs-throttle)
|
||||||
pub fn use_debounce_fn<F>(func: F, ms: impl Into<MaybeSignal<f64>>) -> impl Fn()
|
pub fn use_debounce_fn<F>(func: F, ms: impl Into<MaybeSignal<f64>>) -> impl Fn() + Clone
|
||||||
where
|
where
|
||||||
F: FnOnce() + Clone + 'static,
|
F: FnOnce() + Clone + 'static,
|
||||||
{
|
{
|
||||||
|
@ -76,7 +76,7 @@ pub fn use_debounce_fn_with_options<F>(
|
||||||
func: F,
|
func: F,
|
||||||
ms: impl Into<MaybeSignal<f64>>,
|
ms: impl Into<MaybeSignal<f64>>,
|
||||||
options: DebounceOptions,
|
options: DebounceOptions,
|
||||||
) -> impl Fn()
|
) -> impl Fn() + Clone
|
||||||
where
|
where
|
||||||
F: FnOnce() + Clone + 'static,
|
F: FnOnce() + Clone + 'static,
|
||||||
{
|
{
|
||||||
|
|
59
src/use_resize_observer.rs
Normal file
59
src/use_resize_observer.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use crate::core::ElementMaybeSignal;
|
||||||
|
use crate::use_supported;
|
||||||
|
use default_struct_builder::DefaultBuilder;
|
||||||
|
use leptos::*;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use wasm_bindgen::{JsCast, JsValue};
|
||||||
|
|
||||||
|
pub fn use_resize_observer_with_options<El, T, F>(
|
||||||
|
cx: Scope,
|
||||||
|
target: El, // TODO : multiple elements?
|
||||||
|
callback: F,
|
||||||
|
options: web_sys::ResizeObserverOptions,
|
||||||
|
) where
|
||||||
|
(Scope, El): Into<ElementMaybeSignal<T, web_sys::Element>>,
|
||||||
|
T: Into<web_sys::Element> + Clone + 'static,
|
||||||
|
F: FnMut(Vec<web_sys::ResizeObserverEntry>, web_sys::ResizeObserver) + 'static,
|
||||||
|
{
|
||||||
|
let observer: Rc<RefCell<Option<web_sys::ResizeObserver>>> = Rc::new(RefCell::new(None));
|
||||||
|
|
||||||
|
let is_supported = use_supported(cx, || JsValue::from("ResizeObserver").js_in(&window()));
|
||||||
|
|
||||||
|
let obs = Rc::clone(&observer);
|
||||||
|
let cleanup = move || {
|
||||||
|
let observer = obs.borrow_mut();
|
||||||
|
if let Some(o) = *observer {
|
||||||
|
o.disconnect();
|
||||||
|
*observer = None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let target = target.into();
|
||||||
|
|
||||||
|
let clean = cleanup.clone();
|
||||||
|
create_effect(cx, move |_| {
|
||||||
|
clean();
|
||||||
|
|
||||||
|
if is_supported() {
|
||||||
|
let obs = web_sys::ResizeObserver::new(move |entries: &js_sys::Array, observer| {
|
||||||
|
callback(
|
||||||
|
entries
|
||||||
|
.to_vec()
|
||||||
|
.into_iter()
|
||||||
|
.map(|v| v.unchecked_into::<web_sys::ResizeObserver>(&options)),
|
||||||
|
observer,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.expect("failed to create ResizeObserver");
|
||||||
|
|
||||||
|
observer.observe(&target.get());
|
||||||
|
|
||||||
|
observer.replace(obs);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let stop = move || {
|
||||||
|
cleanup();
|
||||||
|
};
|
||||||
|
}
|
26
src/use_supported.rs
Normal file
26
src/use_supported.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
use leptos::*;
|
||||||
|
|
||||||
|
/// SSR compatibe `is_supported`
|
||||||
|
///
|
||||||
|
/// ## Usage
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use leptos::*;
|
||||||
|
/// # use leptos_use::use_supported;
|
||||||
|
/// # use wasm_bindgen::JsValue;
|
||||||
|
/// #
|
||||||
|
/// # pub fn Demo(cx: Scope) -> impl IntoView {
|
||||||
|
/// let is_supported = use_supported(
|
||||||
|
/// cx,
|
||||||
|
/// || JsValue::from("getBattery").js_in(&window().navigator())
|
||||||
|
/// );
|
||||||
|
///
|
||||||
|
/// if is_supported() {
|
||||||
|
/// // do something
|
||||||
|
/// }
|
||||||
|
/// # view! { cx, }
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub fn use_supported(cx: Scope, callback: impl Fn() -> bool + 'static) -> Signal<bool> {
|
||||||
|
Signal::derive(cx, callback)
|
||||||
|
}
|
84
src/watch.rs
Normal file
84
src/watch.rs
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
use leptos::*;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
/// A version of `create_effect` that listens to any dependency that is accessed inside `deps`.
|
||||||
|
/// Also a stop handler is returned.
|
||||||
|
/// If `immediate` is false, the `callback` will not run immediately but only after
|
||||||
|
/// the first change is detected of any signal that is accessed in `deps`.
|
||||||
|
/// The return value of `deps` is passed into `callback` as an argument together with the previous value
|
||||||
|
/// and the previous value that the `callback` itself returned last time.
|
||||||
|
///
|
||||||
|
/// # Usage
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use std::time::Duration;
|
||||||
|
/// # use leptos::*;
|
||||||
|
/// # use leptos_use::watch;
|
||||||
|
/// #
|
||||||
|
/// # pub fn Demo(cx: Scope) -> impl IntoView {
|
||||||
|
/// let (num, set_num) = create_signal(cx, 0);
|
||||||
|
///
|
||||||
|
/// let stop = watch(
|
||||||
|
/// cx,
|
||||||
|
/// num,
|
||||||
|
/// move |num, _, _| {
|
||||||
|
/// log!("number {}", num);
|
||||||
|
/// },
|
||||||
|
/// true,
|
||||||
|
/// );
|
||||||
|
///
|
||||||
|
/// set_num(1); // > "number 1"
|
||||||
|
///
|
||||||
|
/// set_timeout_with_handle(move || {
|
||||||
|
/// stop(); // stop watching
|
||||||
|
///
|
||||||
|
/// set_num(2); // nothing happens
|
||||||
|
/// }, Duration::from_millis(1000));
|
||||||
|
/// # view! { cx, }
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub fn watch<W, T, DFn, CFn>(
|
||||||
|
cx: Scope,
|
||||||
|
deps: DFn,
|
||||||
|
callback: CFn,
|
||||||
|
immediate: bool,
|
||||||
|
) -> impl Fn() + Clone
|
||||||
|
where
|
||||||
|
DFn: Fn() -> W + 'static,
|
||||||
|
CFn: Fn(&W, Option<&W>, Option<T>) -> T + 'static,
|
||||||
|
W: 'static,
|
||||||
|
T: 'static,
|
||||||
|
{
|
||||||
|
let (is_active, set_active) = create_signal(cx, true);
|
||||||
|
|
||||||
|
let prev_deps_value: RefCell<Option<W>> = RefCell::new(None);
|
||||||
|
let prev_callback_value: RefCell<Option<T>> = RefCell::new(None);
|
||||||
|
|
||||||
|
create_effect(cx, move |did_run_before| {
|
||||||
|
if !is_active() {
|
||||||
|
return ();
|
||||||
|
}
|
||||||
|
|
||||||
|
let deps_value = deps();
|
||||||
|
|
||||||
|
if !immediate && did_run_before.is_none() {
|
||||||
|
prev_deps_value.replace(Some(deps_value));
|
||||||
|
return ();
|
||||||
|
}
|
||||||
|
|
||||||
|
let callback_value = callback(
|
||||||
|
&deps_value,
|
||||||
|
prev_deps_value.borrow().as_ref(),
|
||||||
|
prev_callback_value.take(),
|
||||||
|
);
|
||||||
|
prev_callback_value.replace(Some(callback_value));
|
||||||
|
|
||||||
|
prev_deps_value.replace(Some(deps_value));
|
||||||
|
|
||||||
|
()
|
||||||
|
});
|
||||||
|
|
||||||
|
move || {
|
||||||
|
set_active(false);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue