123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- use crate::{innerlude::AttributeValue, AnyEvent, ElementId, VNode};
- use bumpalo::boxed::Box as BumpBox;
- use std::{
- cell::{Cell, RefCell},
- fmt::{Debug, Formatter},
- };
- /// An element like a "div" with children, listeners, and attributes.
- pub struct VElement<'a> {
- /// The [`ElementId`] of the VText.
- pub id: Cell<Option<ElementId>>,
- /// The key of the element to be used during keyed diffing.
- pub key: Option<&'a str>,
- /// The tag name of the element.
- ///
- /// IE "div"
- pub tag: &'static str,
- /// The namespace of the VElement
- ///
- /// IE "svg"
- pub namespace: Option<&'static str>,
- /// The parent of the Element (if any).
- ///
- /// Used when bubbling events
- pub parent: Cell<Option<ElementId>>,
- /// The Listeners of the VElement.
- pub listeners: &'a [Listener<'a>],
- /// The attributes of the VElement.
- pub attributes: &'a [Attribute<'a>],
- /// The children of the VElement.
- pub children: &'a [VNode<'a>],
- }
- impl Debug for VElement<'_> {
- fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
- f.debug_struct("VElement")
- .field("tag_name", &self.tag)
- .field("namespace", &self.namespace)
- .field("key", &self.key)
- .field("id", &self.id)
- .field("parent", &self.parent)
- .field("listeners", &self.listeners.len())
- .field("attributes", &self.attributes)
- .field("children", &self.children)
- .finish()
- }
- }
- /// An attribute on a DOM node, such as `id="my-thing"` or
- /// `href="https://example.com"`.
- #[derive(Clone, Debug)]
- pub struct Attribute<'a> {
- /// The name of the attribute.
- pub name: &'static str,
- /// The namespace of the attribute.
- ///
- /// Doesn't exist in the html spec.
- /// Used in Dioxus to denote "style" tags and other attribute groups.
- pub namespace: Option<&'static str>,
- /// An indication of we should always try and set the attribute.
- /// Used in controlled components to ensure changes are propagated.
- pub volatile: bool,
- /// The value of the attribute.
- pub value: AttributeValue<'a>,
- }
- /// An event listener.
- /// IE onclick, onkeydown, etc
- pub struct Listener<'bump> {
- /// The ID of the node that this listener is mounted to
- /// Used to generate the event listener's ID on the DOM
- pub mounted_node: Cell<ElementId>,
- /// The type of event to listen for.
- ///
- /// IE "click" - whatever the renderer needs to attach the listener by name.
- pub event: &'static str,
- /// The actual callback that the user specified
- pub(crate) callback: InternalHandler<'bump>,
- }
- pub type InternalHandler<'bump> = &'bump RefCell<Option<InternalListenerCallback<'bump>>>;
- type InternalListenerCallback<'bump> = BumpBox<'bump, dyn FnMut(AnyEvent) + 'bump>;
- type ExternalListenerCallback<'bump, T> = BumpBox<'bump, dyn FnMut(T) + 'bump>;
- /// The callback type generated by the `rsx!` macro when an `on` field is specified for components.
- ///
- /// This makes it possible to pass `move |evt| {}` style closures into components as property fields.
- ///
- ///
- /// # Example
- ///
- /// ```rust, ignore
- ///
- /// rsx!{
- /// MyComponent { onclick: move |evt| log::info!("clicked"), }
- /// }
- ///
- /// #[derive(Props)]
- /// struct MyProps<'a> {
- /// onclick: EventHandler<'a, MouseEvent>,
- /// }
- ///
- /// fn MyComponent(cx: Scope<'a, MyProps<'a>>) -> Element {
- /// cx.render(rsx!{
- /// button {
- /// onclick: move |evt| cx.props.onclick.call(evt),
- /// }
- /// })
- /// }
- ///
- /// ```
- pub struct EventHandler<'bump, T = ()> {
- /// The (optional) callback that the user specified
- /// Uses a `RefCell` to allow for interior mutability, and FnMut closures.
- pub callback: RefCell<Option<ExternalListenerCallback<'bump, T>>>,
- }
- impl<'a, T> Default for EventHandler<'a, T> {
- fn default() -> Self {
- Self {
- callback: RefCell::new(None),
- }
- }
- }
- impl<T> EventHandler<'_, T> {
- /// Call this event handler with the appropriate event type
- pub fn call(&self, event: T) {
- if let Some(callback) = self.callback.borrow_mut().as_mut() {
- callback(event);
- }
- }
- /// Forcibly drop the internal handler callback, releasing memory
- pub fn release(&self) {
- self.callback.replace(None);
- }
- }
|