mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 14:54:16 +00:00
Add signal helpers from main
that are needed for <Transition/>
This commit is contained in:
parent
46e77d72ea
commit
7959f5b324
3 changed files with 196 additions and 0 deletions
|
@ -77,6 +77,7 @@ mod selector;
|
|||
mod serialization;
|
||||
mod signal;
|
||||
mod signal_wrappers;
|
||||
mod signal_wrappers_write;
|
||||
mod spawn;
|
||||
mod suspense;
|
||||
|
||||
|
@ -91,6 +92,7 @@ pub use selector::*;
|
|||
pub use serialization::*;
|
||||
pub use signal::*;
|
||||
pub use signal_wrappers::*;
|
||||
pub use signal_wrappers_write::*;
|
||||
pub use spawn::*;
|
||||
pub use suspense::*;
|
||||
|
||||
|
|
|
@ -616,6 +616,28 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns a write-only handle to the signal.
|
||||
///
|
||||
/// Useful if you're trying to give write access to another component, or split an
|
||||
/// `RwSignal` into a [ReadSignal] and a [WriteSignal].
|
||||
/// ```
|
||||
/// # use leptos_reactive::*;
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let count = create_rw_signal(cx, 0);
|
||||
/// let set_count = count.write_only();
|
||||
/// assert_eq!(count(), 0);
|
||||
/// set_count(1);
|
||||
/// assert_eq!(count(), 1);
|
||||
/// # }).dispose();
|
||||
/// ```
|
||||
pub fn write_only(&self) -> WriteSignal<T> {
|
||||
WriteSignal {
|
||||
runtime: self.runtime,
|
||||
id: self.id,
|
||||
ty: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a [Stream] that emits the new value of the signal whenever it changes.
|
||||
pub fn to_stream(&self) -> impl Stream<Item = T>
|
||||
where
|
||||
|
|
172
leptos_reactive/src/signal_wrappers_write.rs
Normal file
172
leptos_reactive/src/signal_wrappers_write.rs
Normal file
|
@ -0,0 +1,172 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use crate::{RwSignal, Scope, WriteSignal};
|
||||
|
||||
/// A wrapper for any kind of settable reactive signal: a [WriteSignal](crate::WriteSignal),
|
||||
/// [RwSignal](crate::RwSignal), or closure that receives a value and sets a signal depending
|
||||
/// on it.
|
||||
///
|
||||
/// This allows you to create APIs that take any kind of `SignalSetter<T>` as an argument,
|
||||
/// rather than adding a generic `F: Fn(T)`. Values can be set with the same
|
||||
/// function call or `set()`, API as other signals.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use leptos_reactive::*;
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let (count, set_count) = create_signal(cx, 2);
|
||||
/// let set_double_input = SignalSetter::map(cx, move |n| set_count(n * 2));
|
||||
///
|
||||
/// // this function takes any kind of signal setter
|
||||
/// fn set_to_4(setter: &SignalSetter<i32>) {
|
||||
/// // ✅ calling the signal sets the value
|
||||
/// // it is a shorthand for arg.set()
|
||||
/// setter(4);
|
||||
/// }
|
||||
///
|
||||
/// set_to_4(&set_count.into());
|
||||
/// assert_eq!(count(), 4);
|
||||
/// set_to_4(&set_double_input);
|
||||
/// assert_eq!(count(), 8);
|
||||
/// # });
|
||||
/// ```
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SignalSetter<T>(SignalSetterTypes<T>)
|
||||
where
|
||||
T: 'static;
|
||||
|
||||
impl<T> SignalSetter<T>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
/// Wraps a signal-setting closure, i.e., any computation that sets one or more
|
||||
/// reactive signals.
|
||||
/// ```rust
|
||||
/// # use leptos_reactive::*;
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let (count, set_count) = create_signal(cx, 2);
|
||||
/// let set_double_count = SignalSetter::map(cx, move |n| set_count(n * 2));
|
||||
///
|
||||
/// // this function takes any kind of signal setter
|
||||
/// fn set_to_4(setter: &SignalSetter<i32>) {
|
||||
/// // ✅ calling the signal sets the value
|
||||
/// // it is a shorthand for arg.set()
|
||||
/// setter(4)
|
||||
/// }
|
||||
///
|
||||
/// set_to_4(&set_count.into());
|
||||
/// assert_eq!(count(), 4);
|
||||
/// set_to_4(&set_double_count);
|
||||
/// assert_eq!(count(), 8);
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn map(cx: Scope, mapped_setter: impl Fn(T) + 'static) -> Self {
|
||||
Self(SignalSetterTypes::Mapped(cx, Rc::new(mapped_setter)))
|
||||
}
|
||||
|
||||
/// Calls the setter function with the given value.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use leptos_reactive::*;
|
||||
/// # create_scope(create_runtime(), |cx| {
|
||||
/// let (count, set_count) = create_signal(cx, 2);
|
||||
/// let set_double_count = SignalSetter::map(cx, move |n| set_count(n * 2));
|
||||
///
|
||||
/// // this function takes any kind of signal setter
|
||||
/// fn set_to_4(setter: &SignalSetter<i32>) {
|
||||
/// // ✅ calling the signal sets the value
|
||||
/// // it is a shorthand for arg.set()
|
||||
/// setter(4);
|
||||
/// }
|
||||
///
|
||||
/// set_to_4(&set_count.into());
|
||||
/// assert_eq!(count(), 4);
|
||||
/// set_to_4(&set_double_count);
|
||||
/// assert_eq!(count(), 8);
|
||||
/// # });
|
||||
pub fn set(&self, value: T) {
|
||||
match &self.0 {
|
||||
SignalSetterTypes::Write(s) => s.set(value),
|
||||
SignalSetterTypes::Mapped(_, s) => s(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<WriteSignal<T>> for SignalSetter<T> {
|
||||
fn from(value: WriteSignal<T>) -> Self {
|
||||
Self(SignalSetterTypes::Write(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<RwSignal<T>> for SignalSetter<T> {
|
||||
fn from(value: RwSignal<T>) -> Self {
|
||||
Self(SignalSetterTypes::Write(value.write_only()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum SignalSetterTypes<T>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
Write(WriteSignal<T>),
|
||||
Mapped(Scope, Rc<dyn Fn(T)>),
|
||||
}
|
||||
|
||||
impl<T> std::fmt::Debug for SignalSetterTypes<T>
|
||||
where
|
||||
T: std::fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Write(arg0) => f.debug_tuple("WriteSignal").field(arg0).finish(),
|
||||
Self::Mapped(_, _) => f.debug_tuple("Mapped").finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PartialEq for SignalSetterTypes<T>
|
||||
where
|
||||
T: PartialEq,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Write(l0), Self::Write(r0)) => l0 == r0,
|
||||
(Self::Mapped(_, l0), Self::Mapped(_, r0)) => std::ptr::eq(l0, r0),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Eq for SignalSetterTypes<T> where T: PartialEq {}
|
||||
|
||||
#[cfg(not(feature = "stable"))]
|
||||
impl<T> FnOnce<(T,)> for SignalSetter<T>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
type Output = ();
|
||||
|
||||
extern "rust-call" fn call_once(self, args: (T,)) -> Self::Output {
|
||||
self.set(args.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "stable"))]
|
||||
impl<T> FnMut<(T,)> for SignalSetter<T>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
extern "rust-call" fn call_mut(&mut self, args: (T,)) -> Self::Output {
|
||||
self.set(args.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "stable"))]
|
||||
impl<T> Fn<(T,)> for SignalSetter<T>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
extern "rust-call" fn call(&self, args: (T,)) -> Self::Output {
|
||||
self.set(args.0)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue