Update NodeRef to be generic over typed HTML elements

This commit is contained in:
Greg Johnston 2022-12-21 21:15:48 -05:00
parent 351389c2bf
commit ce84632c39
3 changed files with 24 additions and 24 deletions

View file

@ -262,7 +262,7 @@ pub fn Todo(cx: Scope, todo: Todo) -> impl IntoView {
let set_todos = use_context::<WriteSignal<Todos>>(cx).unwrap();
// this will be filled by _ref=input below
let input = NodeRef::new(cx);
let todo_input = NodeRef::new(cx);
let save = move |value: &str| {
let value = value.trim();
@ -282,7 +282,7 @@ pub fn Todo(cx: Scope, todo: Todo) -> impl IntoView {
>
<div class="view">
<input
_ref=input
_ref=todo_input
class="toggle"
type="checkbox"
prop:checked={move || (todo.completed)()}
@ -293,12 +293,9 @@ pub fn Todo(cx: Scope, todo: Todo) -> impl IntoView {
/>
<label on:dblclick=move |_| {
set_editing(true);
if let Some(input) = input.get()
.as_ref()
.and_then(|n| n.dyn_ref::<HtmlInputElement>())
{
input.focus();
if let Some(input) = todo_input.get() {
_ = input.focus();
}
}>
{move || todo.title.get()}

View file

@ -14,12 +14,12 @@ cfg_if! {
/// Trait alias for the trait bounts on [`IntoElement`].
pub trait IntoElementBounds:
fmt::Debug + AsRef<web_sys::HtmlElement>
fmt::Debug + AsRef<web_sys::HtmlElement> + Clone
{
}
impl<El> IntoElementBounds for El where
El: fmt::Debug + AsRef<web_sys::HtmlElement>
El: fmt::Debug + AsRef<web_sys::HtmlElement> + Clone
{
}
} else {
@ -202,6 +202,7 @@ impl IntoElement for Custom {
cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
/// Represents an HTML element.
#[derive(Clone)]
pub struct HtmlElement<El: IntoElement> {
pub(crate) cx: Scope,
pub(crate) element: El,
@ -209,7 +210,7 @@ cfg_if! {
// Server needs to build a virtualized DOM tree
} else {
/// Represents an HTML element.
#[derive(educe::Educe)]
#[derive(educe::Educe, Clone)]
#[educe(Debug)]
pub struct HtmlElement<El: IntoElement> {
pub(crate) cx: Scope,
@ -225,12 +226,12 @@ cfg_if! {
}
}
impl<El: IntoElement> std::ops::Deref for HtmlElement<El> {
type Target = web_sys::HtmlElement;
impl<El> std::ops::Deref for HtmlElement<El> where El: IntoElement + std::ops::Deref {
type Target = <El as std::ops::Deref>::Target;
fn deref(&self) -> &Self::Target {
#[cfg(all(target_arch = "wasm32", feature = "web"))]
return self.element.as_ref();
return self.element.deref();
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
unimplemented!("{HTML_ELEMENT_DEREF_UNIMPLEMENTED_MSG}");
@ -341,7 +342,7 @@ impl<El: IntoElement> HtmlElement<El> {
}
/// Binds the element reference to [`NodeRef`].
pub fn node_ref(self, node_ref: &NodeRef) -> Self {
pub fn node_ref(self, node_ref: &NodeRef<Self>) -> Self where Self: Clone {
#[cfg(all(target_arch = "wasm32", feature = "web"))]
node_ref.load(&self);

View file

@ -28,10 +28,10 @@ use leptos_reactive::{create_rw_signal, RwSignal, Scope};
/// }
/// }
/// ```
#[derive(Copy, Clone, PartialEq)]
pub struct NodeRef(RwSignal<Option<web_sys::Element>>);
#[derive(Clone, PartialEq)]
pub struct NodeRef<T: Clone + 'static>(RwSignal<Option<T>>);
impl NodeRef {
impl<T: Clone + 'static> NodeRef<T> {
/// Creates an empty reference.
pub fn new(cx: Scope) -> Self {
Self(create_rw_signal(cx, None))
@ -43,7 +43,7 @@ impl NodeRef {
/// Initially, the value will be `None`, but once it is loaded the effect
/// will rerun and its value will be `Some(Element)`.
#[track_caller]
pub fn get(&self) -> Option<web_sys::Element> {
pub fn get(&self) -> Option<T> {
self.0.get()
}
@ -52,7 +52,7 @@ impl NodeRef {
/// so that effects that use the node reference will rerun once it is loaded,
/// i.e., effects can be forward-declared.
#[track_caller]
pub fn load(&self, node: &web_sys::Element) {
pub fn load(&self, node: &T) {
self.0.update(|current| {
if current.is_some() {
crate::debug_warn!(
@ -66,23 +66,25 @@ impl NodeRef {
}
}
impl<T: Clone + 'static> Copy for NodeRef<T> { }
cfg_if::cfg_if! {
if #[cfg(not(feature = "stable"))] {
impl FnOnce<()> for NodeRef {
type Output = Option<web_sys::Element>;
impl<T: Clone + 'static> FnOnce<()> for NodeRef<T> {
type Output = Option<T>;
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
self.get()
}
}
impl FnMut<()> for NodeRef {
impl<T: Clone + 'static> FnMut<()> for NodeRef<T> {
extern "rust-call" fn call_mut(&mut self, _args: ()) -> Self::Output {
self.get()
}
}
impl Fn<()> for NodeRef {
impl<T: Clone + 'static> Fn<()> for NodeRef<T> {
extern "rust-call" fn call(&self, _args: ()) -> Self::Output {
self.get()
}