Skip to main content

dioxus_dnd/core/components/
handle.rs

1//! Explicit drag activators and interactive-child escape hatches.
2
3use dioxus::prelude::*;
4
5#[derive(Clone, Copy)]
6pub(crate) struct ActivatorContext {
7    pub pointer: Signal<Option<i32>>,
8    pub keyboard: Signal<bool>,
9}
10
11/// An accessible button that activates the nearest handle-only
12/// [`super::Draggable`].
13#[component]
14pub fn DragHandle(
15    #[props(default = "Drag".to_string())] label: String,
16    #[props(default)] disabled: bool,
17    #[props(extends = button, extends = GlobalAttributes)] mut attributes: Vec<Attribute>,
18    children: Element,
19) -> Element {
20    let activator = try_use_context::<ActivatorContext>();
21    super::protect_attributes(
22        &mut attributes,
23        &[
24            "type",
25            "disabled",
26            "aria-label",
27            "data-dnd-handle",
28            "onpointerdown",
29            "onkeydown",
30        ],
31    );
32    let style = super::merge_style_invariant_last(
33        &mut attributes,
34        "touch-action: none; user-select: none;",
35        &["touch-action", "user-select"],
36    );
37    rsx! {
38        button {
39            r#type: "button",
40            disabled,
41            aria_label: label,
42            "data-dnd-handle": "true",
43            style,
44            onpointerdown: move |event: PointerEvent| {
45                if !super::primary_press(&event) {
46                    return;
47                }
48                if let Some(context) = activator.filter(|_| !disabled) {
49                    let mut pointer = context.pointer;
50                    pointer.set(Some(event.pointer_id()));
51                }
52            },
53            onkeydown: move |_| {
54                if let Some(context) = activator.filter(|_| !disabled) {
55                    let mut keyboard = context.keyboard;
56                    keyboard.set(true);
57                }
58            },
59            ..attributes,
60            {children}
61        }
62    }
63}
64
65/// Stop pointer and keyboard events in an interactive subtree from
66/// activating a surface-driven draggable.
67#[component]
68pub fn NoDrag(
69    #[props(extends = span, extends = GlobalAttributes)] attributes: Vec<Attribute>,
70    children: Element,
71) -> Element {
72    let mut attributes = attributes;
73    super::protect_attributes(
74        &mut attributes,
75        &["data-no-drag", "onpointerdown", "onkeydown"],
76    );
77    rsx! {
78        span {
79            "data-no-drag": "true",
80            onpointerdown: move |event: PointerEvent| event.stop_propagation(),
81            onkeydown: move |event: KeyboardEvent| event.stop_propagation(),
82            ..attributes,
83            {children}
84        }
85    }
86}