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