mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 14:54:16 +00:00
Merge branch 'leptos_dom_v2' of https://github.com/jquesada2016/leptos into leptos_dom_v2
This commit is contained in:
commit
7c298272d3
4 changed files with 250 additions and 61 deletions
|
@ -33,18 +33,20 @@ features = [
|
|||
"Text",
|
||||
|
||||
# Events we cast to in leptos_macro -- added here so we don't force users to import them
|
||||
"MouseEvent",
|
||||
"AnimationEvent",
|
||||
"ClipboardEvent",
|
||||
"CompositionEvent",
|
||||
"DragEvent",
|
||||
"FocusEvent",
|
||||
"KeyboardEvent",
|
||||
"ProgressEvent",
|
||||
"WheelEvent",
|
||||
"InputEvent",
|
||||
"SubmitEvent",
|
||||
"AnimationEvent",
|
||||
"KeyboardEvent",
|
||||
"MouseEvent",
|
||||
"PointerEvent",
|
||||
"ProgressEvent",
|
||||
"SubmitEvent",
|
||||
"TouchEvent",
|
||||
"TransitionEvent",
|
||||
"WheelEvent",
|
||||
]
|
||||
|
||||
[features]
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
//! Collection of typed events.
|
||||
|
||||
use std::{borrow::Cow, marker::PhantomData};
|
||||
use wasm_bindgen::convert::FromWasmAbi;
|
||||
|
||||
use crate::IntoElement;
|
||||
|
||||
/// A trait for converting types into [web_sys events](web_sys).
|
||||
pub trait EventDescriptor {
|
||||
/// The [`web_sys`] event type, such as [`web_sys::MouseEvent`].
|
||||
type EventType: FromWasmAbi;
|
||||
|
||||
/// The name of the event, such as `click` or `mouseover`.
|
||||
fn name(&self) -> Cow<'static, str>;
|
||||
|
||||
/// Indicates if this event bubbles. For example, `click` bubbles,
|
||||
/// but `focus` does not.
|
||||
///
|
||||
/// If this method returns true, then the event will be delegated globally,
|
||||
/// otherwise, event listeners will be directly attached to the element.
|
||||
fn bubbles(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Overrides the [`EventDescriptor::bubbles`] method to always return
|
||||
/// `false`, which forces the event to not be globally delegated.
|
||||
pub struct Undelegated<Ev: EventDescriptor>(Ev);
|
||||
|
||||
impl<Ev: EventDescriptor> EventDescriptor for Undelegated<Ev> {
|
||||
type EventType = Ev::EventType;
|
||||
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
self.0.name()
|
||||
}
|
||||
|
||||
fn bubbles(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// A custom event.
|
||||
pub struct Custom<E: FromWasmAbi = web_sys::Event> {
|
||||
name: Cow<'static, str>,
|
||||
_event_type: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<E: FromWasmAbi> EventDescriptor for Custom<E> {
|
||||
type EventType = E;
|
||||
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
self.name.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: FromWasmAbi> Custom<E> {
|
||||
/// Creates a custom event type that can be used within
|
||||
/// [`HtmlElement::on`](crate::HtmlElement::on), for events
|
||||
/// which are not covered in the [`ev`](crate::ev) module.
|
||||
pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
|
||||
Self {
|
||||
name: name.into(),
|
||||
_event_type: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_event_types {
|
||||
[$([$web_sys_event:ident, [$($event:ident),* $(,)?]]),* $(,)?] => {
|
||||
paste::paste! {
|
||||
$(
|
||||
$(
|
||||
#[doc = "The "]
|
||||
#[doc = stringify!([<$event:lower>])]
|
||||
#[doc = "event."]
|
||||
pub struct $event;
|
||||
|
||||
impl EventDescriptor for $event {
|
||||
type EventType = web_sys::MouseEvent;
|
||||
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
concat!("on", stringify!([<$event:lower>])).into()
|
||||
}
|
||||
}
|
||||
)*
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
generate_event_types![
|
||||
// ClipboardEvent is unstable
|
||||
[Event, [Copy, Cut, Paste]],
|
||||
[
|
||||
CompositionEvent,
|
||||
[CompositionEnd, CompositionStart, CompositionUpdate]
|
||||
],
|
||||
[KeyboardEvent, [KeyDown, Keypress, Keyup]],
|
||||
[FocusEvent, [Focus, FocusOut, FocusIn, Blur]],
|
||||
[FormEvent, [Change, Input, Invalid, Reset, Submit]],
|
||||
[
|
||||
MouseEvent,
|
||||
[
|
||||
Click,
|
||||
ContextMenu,
|
||||
DoubleClick,
|
||||
DblClick,
|
||||
Drag,
|
||||
DragEnd,
|
||||
DragEnter,
|
||||
DragExit,
|
||||
DragLeave,
|
||||
DragOver,
|
||||
DragStart,
|
||||
Drop,
|
||||
MouseDown,
|
||||
MouseEnter,
|
||||
MouseLeave,
|
||||
MouseMove,
|
||||
MouseOut,
|
||||
MouseOver,
|
||||
MouseUp,
|
||||
]
|
||||
],
|
||||
[ScrollEvent, [Scroll]],
|
||||
[
|
||||
PointerEvent,
|
||||
[
|
||||
PointerDown,
|
||||
PointerMove,
|
||||
PointerUp,
|
||||
PointerCancel,
|
||||
GotPointerCapture,
|
||||
LostPointerCapture,
|
||||
PointerEnter,
|
||||
PointerLeave,
|
||||
PointerOver,
|
||||
PointerOut,
|
||||
]
|
||||
],
|
||||
[SelectionEvent, [Select]],
|
||||
[TouchEvent, [TouchCancel, TouchEnd, TouchMove, TouchStart]],
|
||||
[WheelEvent, [Wheel]],
|
||||
[
|
||||
MediaEvent,
|
||||
[
|
||||
Abort,
|
||||
CanPlay,
|
||||
CanPlayThrough,
|
||||
DurationChange,
|
||||
Emptied,
|
||||
Encrypted,
|
||||
Ended,
|
||||
Error,
|
||||
LoadedData,
|
||||
LoadedMetadata,
|
||||
LoadStart,
|
||||
Pause,
|
||||
Play,
|
||||
Playing,
|
||||
Progress,
|
||||
RateChange,
|
||||
Seeked,
|
||||
Seeking,
|
||||
Stalled,
|
||||
Suspend,
|
||||
TimeUpdate,
|
||||
VolumeChange,
|
||||
Waiting,
|
||||
]
|
||||
],
|
||||
[
|
||||
AnimationEvent,
|
||||
[AnimationStart, AnimationEnd, AnimationIteration,]
|
||||
],
|
||||
[TransitionEvent, [TransitionEnd]],
|
||||
[ToggleEvent, [Toggle]]
|
||||
];
|
|
@ -1,6 +1,9 @@
|
|||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
use crate::events::*;
|
||||
use crate::{components::DynChild, Element, Fragment, IntoNode, Node, Text};
|
||||
use crate::{
|
||||
components::DynChild, ev::EventDescriptor, Element, Fragment, IntoNode, Node,
|
||||
Text,
|
||||
};
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
use crate::{mount_child, MountKind};
|
||||
use cfg_if::cfg_if;
|
||||
|
@ -369,31 +372,21 @@ impl<El: IntoElement> HtmlElement<El> {
|
|||
|
||||
/// Adds an event listener to this element.
|
||||
#[track_caller]
|
||||
pub fn on<E>(self, event_name: impl Into<Cow<'static, str>>, event_handler: impl FnMut(E) + 'static) -> Self
|
||||
where E: FromWasmAbi + 'static,
|
||||
{
|
||||
pub fn on<E: EventDescriptor + 'static>(
|
||||
self,
|
||||
event: E,
|
||||
event_handler: impl FnMut(E::EventType) + 'static,
|
||||
) -> Self {
|
||||
cfg_if! {
|
||||
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
|
||||
let event_name = event_name.into();
|
||||
add_event_listener_undelegated(self.element.get_element(), &event_name, event_handler);
|
||||
} else {
|
||||
_ = event_name;
|
||||
_ = event_handler;
|
||||
}
|
||||
}
|
||||
let event_name = event.name();
|
||||
|
||||
self
|
||||
}
|
||||
if event.bubbles() {
|
||||
add_event_listener(self.element.get_element(), event_name, event_handler);
|
||||
} else {
|
||||
add_event_listener_undelegated(self.element.get_element(), &event_name, event_handler);
|
||||
}
|
||||
|
||||
/// Adds an event listener to this element, using event delegation.
|
||||
#[track_caller]
|
||||
pub fn on_delegated<E>(self, event_name: impl Into<Cow<'static, str>>, event_handler: impl FnMut(E) + 'static) -> Self
|
||||
where E: FromWasmAbi + 'static,
|
||||
{
|
||||
cfg_if! {
|
||||
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
|
||||
let event_name = event_name.into();
|
||||
add_event_listener(self.element.get_element(), event_name, event_handler);
|
||||
} else {
|
||||
_ = event_name;
|
||||
_ = event_handler;
|
||||
|
@ -409,7 +402,7 @@ impl<El: IntoElement> HtmlElement<El> {
|
|||
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
|
||||
{
|
||||
let child = child.into_node(self.cx);
|
||||
|
||||
|
||||
mount_child(MountKind::Append(self.element.get_element()), &child)
|
||||
}
|
||||
}
|
||||
|
@ -576,11 +569,16 @@ use crate::macro_helpers::*;
|
|||
use leptos_reactive::create_render_effect;
|
||||
impl<El: IntoElement> HtmlElement<El> {
|
||||
#[doc(hidden)]
|
||||
#[track_caller]
|
||||
pub fn _attr(mut self, cx: Scope, name: impl Into<Cow<'static, str>>, attr: impl IntoAttribute) -> Self {
|
||||
#[track_caller]
|
||||
pub fn _attr(
|
||||
mut self,
|
||||
cx: Scope,
|
||||
name: impl Into<Cow<'static, str>>,
|
||||
attr: impl IntoAttribute,
|
||||
) -> Self {
|
||||
let name = name.into();
|
||||
cfg_if! {
|
||||
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
|
||||
cfg_if! {
|
||||
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
|
||||
let el = self.element.get_element();
|
||||
let value = attr.into_attribute(cx);
|
||||
match value {
|
||||
|
@ -597,15 +595,15 @@ impl<El: IntoElement> HtmlElement<El> {
|
|||
_ => attribute_expression(el, &name, value),
|
||||
};
|
||||
self
|
||||
}
|
||||
else {
|
||||
}
|
||||
else {
|
||||
let mut attr = attr.into_attribute(cx);
|
||||
while let Attribute::Fn(f) = attr {
|
||||
attr = f();
|
||||
}
|
||||
match attr {
|
||||
Attribute::String(value) => self.attr(name, value),
|
||||
Attribute::Bool(include) => if include {
|
||||
Attribute::Bool(include) => if include {
|
||||
self.attr_bool(name)
|
||||
} else {
|
||||
self
|
||||
|
@ -617,16 +615,21 @@ impl<El: IntoElement> HtmlElement<El> {
|
|||
}
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[track_caller]
|
||||
pub fn _class(mut self, cx: Scope, name: impl Into<Cow<'static, str>>, class: impl IntoClass) -> Self {
|
||||
#[track_caller]
|
||||
pub fn _class(
|
||||
mut self,
|
||||
cx: Scope,
|
||||
name: impl Into<Cow<'static, str>>,
|
||||
class: impl IntoClass,
|
||||
) -> Self {
|
||||
let name = name.into();
|
||||
cfg_if! {
|
||||
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
|
||||
cfg_if! {
|
||||
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
|
||||
let el = self.element.get_element();
|
||||
let class_list = el.class_list();
|
||||
let value = class.into_class(cx);
|
||||
|
@ -643,22 +646,27 @@ impl<El: IntoElement> HtmlElement<El> {
|
|||
Class::Value(value) => class_expression(&class_list, &name, value),
|
||||
};
|
||||
self
|
||||
}
|
||||
else {
|
||||
}
|
||||
else {
|
||||
let mut class = class.into_class(cx);
|
||||
match class {
|
||||
Class::Value(include) => self.class_bool(name, include),
|
||||
Class::Fn(f) => self.class_bool(name, f())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[track_caller]
|
||||
pub fn _prop(mut self, cx: Scope, name: impl Into<Cow<'static, str>>, value: impl IntoProperty) -> Self {
|
||||
#[track_caller]
|
||||
pub fn _prop(
|
||||
mut self,
|
||||
cx: Scope,
|
||||
name: impl Into<Cow<'static, str>>,
|
||||
value: impl IntoProperty,
|
||||
) -> Self {
|
||||
cfg_if! {
|
||||
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
|
||||
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
|
||||
let name = name.into();
|
||||
let value = value.into_property(cx);
|
||||
let el = self.element.get_element();
|
||||
|
@ -687,20 +695,20 @@ impl<El: IntoElement> HtmlElement<El> {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[track_caller]
|
||||
pub fn _child(mut self, cx: Scope, child: impl IntoChild) -> Self {
|
||||
let child = child.into_child(cx);
|
||||
cfg_if! {
|
||||
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
|
||||
#[doc(hidden)]
|
||||
#[track_caller]
|
||||
pub fn _child(mut self, cx: Scope, child: impl IntoChild) -> Self {
|
||||
let child = child.into_child(cx);
|
||||
cfg_if! {
|
||||
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
|
||||
mount_child(MountKind::Append(self.element.get_element()), &child.into_node(cx))
|
||||
}
|
||||
else {
|
||||
}
|
||||
else {
|
||||
self.children.push(Box::new(move |cx| child.into_node(cx)));
|
||||
}
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ mod node_ref;
|
|||
|
||||
use cfg_if::cfg_if;
|
||||
pub use components::*;
|
||||
pub use events::typed as ev;
|
||||
pub use html::*;
|
||||
pub use node_ref::*;
|
||||
pub use logging::*;
|
||||
|
|
Loading…
Reference in a new issue