Skip to content

Commit

Permalink
Update hooks to Leptos 0.7 (#410)
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielleHuisman authored Jan 5, 2025
1 parent a87b546 commit 4054662
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 48 deletions.
43 changes: 43 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ members = [
"packages/primitives/leptos/direction",
"packages/primitives/leptos/id",
"packages/primitives/leptos/label",
"packages/primitives/leptos/use-controllable-state",
"packages/primitives/leptos/use-escape-keydown",
"packages/primitives/leptos/use-previous",
"packages/primitives/leptos/use-size",
"packages/primitives/leptos/visually-hidden",
"packages/primitives/yew/*",
"packages/themes/yew",
Expand All @@ -42,8 +46,10 @@ dioxus = "0.6.1"
leptos = "0.7.2"
leptos_dom = "0.7.2"
leptos_router = "0.7.2"
leptos-node-ref = "0.0.3"
leptos-style = "0.0.3"
log = "0.4.22"
send_wrapper = "0.6.0"
serde = "1.0.198"
serde_json = "1.0.116"
tailwind_fuse = { version = "0.3.0", features = ["variant"] }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
use leptos::{
create_signal, Callable, Callback, Effect, MaybeProp, ReadSignal, RwSignal, Signal, SignalGet,
SignalGetUntracked, SignalSet, WriteSignal,
};
use leptos::prelude::*;

pub struct UseControllableStateParams<T: 'static> {
pub struct UseControllableStateParams<T: Send + Sync + 'static> {
pub prop: MaybeProp<T>,
pub default_prop: MaybeProp<T>,
pub on_change: Option<Callback<Option<T>>>,
}

pub fn use_controllable_state<T: Clone + PartialEq>(
pub fn use_controllable_state<T: Clone + PartialEq + Send + Sync>(
UseControllableStateParams {
prop,
default_prop,
Expand All @@ -32,7 +29,7 @@ pub fn use_controllable_state<T: Clone + PartialEq>(
if is_controlled.get() {
if next_value != prop.get() {
if let Some(on_change) = on_change {
on_change.call(next_value);
on_change.run(next_value);
}
}
} else {
Expand All @@ -43,26 +40,26 @@ pub fn use_controllable_state<T: Clone + PartialEq>(
(value, set_value)
}

pub struct UseUncontrollableStateParams<T: 'static> {
pub struct UseUncontrollableStateParams<T: Send + Sync + 'static> {
pub default_prop: MaybeProp<T>,
pub on_change: Option<Callback<Option<T>>>,
}

fn use_uncontrolled_state<T: Clone + PartialEq>(
fn use_uncontrolled_state<T: Clone + PartialEq + Send + Sync>(
UseUncontrollableStateParams {
default_prop,
on_change,
}: UseUncontrollableStateParams<T>,
) -> (ReadSignal<Option<T>>, WriteSignal<Option<T>>) {
let uncontrolled_state = create_signal::<Option<T>>(default_prop.get());
let uncontrolled_state = signal::<Option<T>>(default_prop.get());
let (value, _) = uncontrolled_state;
let prev_value = RwSignal::new(value.get_untracked());

Effect::new(move |_| {
let value = value.get();
if prev_value.get() != value {
if let Some(on_change) = on_change {
on_change.call(value.clone());
on_change.run(value.clone());
prev_value.set(value);
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/primitives/leptos/use-escape-keydown/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ version.workspace = true

[dependencies]
leptos.workspace = true
send_wrapper.workspace = true
web-sys = { workspace = true, features = ["EventListenerOptions"] }
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::rc::Rc;
use std::sync::Arc;

use leptos::{document, ev::KeyboardEvent, on_cleanup, Callable, Callback, Effect, StoredValue};
use leptos::{ev::KeyboardEvent, prelude::*};
use send_wrapper::SendWrapper;
use web_sys::{
wasm_bindgen::{closure::Closure, JsCast},
AddEventListenerOptions, Document, EventListenerOptions,
Expand All @@ -11,30 +12,35 @@ pub fn use_escape_keydown(
on_escape_key_down: Option<Callback<KeyboardEvent>>,
owner_document: Option<Document>,
) {
let owner_document = StoredValue::new(owner_document.unwrap_or(document()));
let owner_document = StoredValue::new(SendWrapper::new(owner_document.unwrap_or(document())));

let handle_key_down: Rc<Closure<dyn Fn(KeyboardEvent)>> =
Rc::new(Closure::new(move |event: KeyboardEvent| {
type HandleKeyDown = dyn Fn(KeyboardEvent);
let handle_key_down: Arc<SendWrapper<Closure<HandleKeyDown>>> = Arc::new(SendWrapper::new(
Closure::new(move |event: KeyboardEvent| {
if event.key() == "Escape" {
if let Some(on_escape_key_down) = on_escape_key_down {
on_escape_key_down.call(event);
on_escape_key_down.run(event);
}
}
}));
let cleanup_handle_key_down = handle_key_down.clone();
}),
));

Effect::new(move |_| {
let options = AddEventListenerOptions::new();
options.set_capture(true);
Effect::new({
let handle_key_down = handle_key_down.clone();

owner_document
.get_value()
.add_event_listener_with_callback_and_add_event_listener_options(
"keydown",
(*handle_key_down).as_ref().unchecked_ref(),
&options,
)
.expect("Key down event listener should be added.");
move |_| {
let options = AddEventListenerOptions::new();
options.set_capture(true);

owner_document
.get_value()
.add_event_listener_with_callback_and_add_event_listener_options(
"keydown",
(*handle_key_down).as_ref().unchecked_ref(),
&options,
)
.expect("Key down event listener should be added.");
}
});

on_cleanup(move || {
Expand All @@ -45,7 +51,7 @@ pub fn use_escape_keydown(
.get_value()
.remove_event_listener_with_callback_and_event_listener_options(
"keydown",
(*cleanup_handle_key_down).as_ref().unchecked_ref(),
(*handle_key_down).as_ref().unchecked_ref(),
&options,
)
.expect("Key down event listener should be removed.");
Expand Down
17 changes: 9 additions & 8 deletions packages/primitives/leptos/use-previous/src/use_previous.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
use leptos::{Memo, RwSignal, Signal, SignalGet, SignalGetUntracked, SignalSetUntracked};
use leptos::prelude::*;

pub fn use_previous<T: Clone + PartialEq>(value: Signal<T>) -> Memo<T> {
let current = RwSignal::new(value.get_untracked());
let previous = RwSignal::new(value.get_untracked());
pub fn use_previous<T: Clone + PartialEq + Send + Sync + 'static>(value: Signal<T>) -> Memo<T> {
let stored_value = StoredValue::new((value.get_untracked(), value.get_untracked()));

Memo::new(move |_| {
let value = value.get();
let current_value = current.get();
let (current_value, previous_value) = stored_value.get_value();

if current_value != value {
previous.set_untracked(current_value);
current.set_untracked(value.clone());
stored_value.set_value((value.clone(), current_value.clone()));
current_value
} else {
previous_value
}
previous.get()
})
}
2 changes: 2 additions & 0 deletions packages/primitives/leptos/use-size/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ version.workspace = true

[dependencies]
leptos.workspace = true
leptos-node-ref.workspace = true
send_wrapper.workspace = true
web-sys = { workspace = true, features = [
"ResizeObserver",
"ResizeObserverBoxOptions",
Expand Down
29 changes: 20 additions & 9 deletions packages/primitives/leptos/use-size/src/use_size.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::{cell::RefCell, rc::Rc};
use std::sync::{Arc, Mutex};

use leptos::{create_signal, html::AnyElement, on_cleanup, Effect, NodeRef, ReadSignal, SignalSet};
use leptos::prelude::*;
use leptos_node_ref::AnyNodeRef;
use send_wrapper::SendWrapper;
use web_sys::{
wasm_bindgen::{closure::Closure, JsCast},
ResizeObserver, ResizeObserverBoxOptions, ResizeObserverEntry, ResizeObserverOptions,
Expand All @@ -13,14 +15,18 @@ pub struct Size {
pub height: f64,
}

pub fn use_size(element_ref: NodeRef<AnyElement>) -> ReadSignal<Option<Size>> {
let (size, set_size) = create_signal::<Option<Size>>(None);
pub fn use_size(element_ref: AnyNodeRef) -> ReadSignal<Option<Size>> {
let (size, set_size) = signal::<Option<Size>>(None);

let resize_observer: Rc<RefCell<Option<ResizeObserver>>> = Rc::new(RefCell::new(None));
let resize_observer: Arc<Mutex<Option<SendWrapper<ResizeObserver>>>> =
Arc::new(Mutex::new(None));
let cleanup_resize_observer = resize_observer.clone();

Effect::new(move |_| {
if let Some(element) = element_ref.get() {
if let Some(element) = element_ref
.get()
.and_then(|element| element.dyn_into::<web_sys::HtmlElement>().ok())
{
// Provide size as early as possible.
set_size.set(Some(Size {
width: element.offset_width() as f64,
Expand All @@ -43,7 +49,7 @@ pub fn use_size(element_ref: NodeRef<AnyElement>) -> ReadSignal<Option<Size>> {
}
});

resize_observer.replace(Some(
*resize_observer.lock().expect("Lock should be acquired.") = Some(SendWrapper::new(
ResizeObserver::new(resize_closure.into_js_value().unchecked_ref())
.expect("Resize observer should be created."),
));
Expand All @@ -52,7 +58,8 @@ pub fn use_size(element_ref: NodeRef<AnyElement>) -> ReadSignal<Option<Size>> {
options.set_box(ResizeObserverBoxOptions::BorderBox);

resize_observer
.borrow()
.lock()
.expect("Lock should be acquired.")
.as_ref()
.expect("Resize observer should exist.")
.observe_with_options(element.as_ref(), &options);
Expand All @@ -63,7 +70,11 @@ pub fn use_size(element_ref: NodeRef<AnyElement>) -> ReadSignal<Option<Size>> {
});

on_cleanup(move || {
if let Some(resize_observer) = cleanup_resize_observer.take() {
if let Some(resize_observer) = cleanup_resize_observer
.lock()
.expect("Lock should be acquired.")
.as_ref()
{
resize_observer.disconnect();
}
});
Expand Down

0 comments on commit 4054662

Please sign in to comment.