1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
use web_sys::Element;
use yew::prelude::*;
use super::{use_event, use_mut_latest};
/// Options for drag.
#[derive(Default)]
pub struct UseDragOptions {
/// Callback for `dragstart`.
pub ondragstart: Option<Box<dyn FnMut(DragEvent)>>,
/// Callback for `dragend`.
pub ondragend: Option<Box<dyn FnMut(DragEvent)>>,
}
/// State handle for the [`use_drag`] hook.
pub struct UseDragHandle {
/// State for whether is dragging.
pub dragging: UseStateHandle<bool>,
}
/// This hook tracks file, link and copy-paste drags.
///
/// # Example
///
/// ```rust
/// # use yew::prelude::*;
/// #
/// use yew_hooks::prelude::*;
///
/// #[function_component(UseDrag)]
/// fn drag() -> Html {
/// let node = use_node_ref();
/// let state = use_drag(node.clone());
///
/// html! {
/// <div ref={node}>
/// <p>
/// <b>{ " Dragging: " }</b>
/// { *state.dragging }
/// </p>
/// <p>
/// { "Try to drag this area" }
/// </p>
/// </div>
/// }
/// }
/// ```
#[hook]
pub fn use_drag(node: NodeRef) -> UseDragHandle {
use_drag_with_options(node, UseDragOptions::default())
}
/// This hook tracks file, link and copy-paste drags.
/// [`use_drag`] hook with options.
///
/// # Example
///
/// ```rust
/// # use yew::prelude::*;
/// #
/// use yew_hooks::prelude::*;
///
/// #[function_component(UseDrag)]
/// fn drag() -> Html {
/// let node = use_node_ref();
/// let state = use_drag_with_options(node.clone(), UseDragOptions {
/// ondragstart: Some(Box::new(move |e| {
/// if let Some(data_transfer) = e.data_transfer() {
/// let _ = data_transfer.set_data("text", "hello");
/// }
/// })),
/// ondragend: Some(Box::new(move |e| {
/// })),
/// });
///
/// html! {
/// <div ref={node}>
/// <p>
/// <b>{ " Dragging: " }</b>
/// { *state.dragging }
/// </p>
/// <p>
/// { "Try to drag this area" }
/// </p>
/// </div>
/// }
/// }
/// ```
#[hook]
pub fn use_drag_with_options(node: NodeRef, options: UseDragOptions) -> UseDragHandle {
let dragging = use_state(|| false);
let ondragstart_ref = use_mut_latest(options.ondragstart);
let ondragend_ref = use_mut_latest(options.ondragend);
{
let dragging = dragging.clone();
use_event(node.clone(), "dragstart", move |e: DragEvent| {
dragging.set(true);
let ondragstart_ref = ondragstart_ref.current();
let ondragstart = &mut *ondragstart_ref.borrow_mut();
if let Some(ondragstart) = ondragstart {
ondragstart(e);
}
});
}
{
let dragging = dragging.clone();
use_event(node.clone(), "dragend", move |e: DragEvent| {
dragging.set(false);
let ondragend_ref = ondragend_ref.current();
let ondragend = &mut *ondragend_ref.borrow_mut();
if let Some(ondragend) = ondragend {
ondragend(e);
}
});
}
use_effect_with(node, move |node| {
if let Some(element) = &node.cast::<Element>() {
let _ = element.set_attribute("draggable", "true");
}
|| ()
});
UseDragHandle { dragging }
}