1#![doc = include_str!("../docs/api/debugging.md")]
2
3use dioxus::prelude::*;
4
5use crate::core::{use_dnd, use_joined_window, use_zone_registry};
6
7#[component]
17pub fn DndDebugOverlay<T: Clone + PartialEq + 'static>(
18 #[props(default)]
20 phantom: std::marker::PhantomData<T>,
21) -> Element {
22 let _ = phantom;
23 let dnd = use_dnd::<T>();
24 let joined = use_joined_window::<T>();
25 let registry = use_zone_registry::<T>();
26
27 use_effect(move || {
32 registry.track_mounts();
33 registry.refresh_rects();
34 });
35
36 let payload = dnd.payload();
37 let over = dnd.over();
38 let records = registry.records();
39 let unmeasured = records.iter().filter(|z| z.rect.is_none()).count();
40 let status = match (dnd.dragging(), over) {
41 (false, _) => format!("{} zones ({unmeasured} unmeasured) - idle", records.len()),
42 (true, Some(z)) => format!("dragging - over zone {}", z.0),
43 (true, None) => "dragging - over nothing".to_string(),
44 };
45
46 rsx! {
47 div {
48 "data-dnd-debug": "true",
49 style: "position: fixed; inset: 0; pointer-events: none; z-index: 9998; \
50 font-family: ui-monospace, SFMono-Regular, Menlo, monospace;",
51 for record in records {
52 {
53 let id = record.id;
54 let rect = record.cached_rect();
55 let hue = (id.0.wrapping_mul(47)) % 360;
58 let accepts = payload.as_ref().map(|p| record.accepts_payload(p));
59 let is_over = match joined {
60 Some(joined) => joined.is_over(id),
61 None => over == Some(id),
62 };
63 let name = record.label.clone().unwrap_or_else(|| "zone".to_string());
64 rsx! {
65 if let Some(r) = rect {
66 div {
67 key: "{id.0}",
68 "data-debug-zone": "{id.0}",
69 "data-over": if is_over { "true" },
70 "data-accepts": accepts.map(|a| if a { "true" } else { "false" }),
71 style: format!(
72 "position: fixed; left: {}px; top: {}px; width: {}px; height: {}px; \
73 box-sizing: border-box; border: 2px {} hsl({hue} 70% 42%); \
74 background: hsl({hue} 70% 42% / {}); opacity: {};",
75 r.x, r.y, r.width, r.height,
76 if accepts == Some(false) { "dashed" } else { "solid" },
77 if is_over { "0.18" } else { "0.04" },
78 if accepts == Some(false) { "0.45" } else { "1" },
79 ),
80 span {
81 style: "position: absolute; top: 0; left: 0; transform: translateY(-100%); \
82 background: hsl({hue} 70% 42%); color: #fff; font-size: 10px; \
83 line-height: 1.6; padding: 0 4px; white-space: nowrap;",
84 "{name} #{id.0}"
85 if accepts == Some(false) { " - rejects" }
86 if is_over { " - over" }
87 }
88 }
89 }
90 }
91 }
92 }
93 div {
94 "data-debug-status": "true",
95 style: "position: fixed; right: 8px; bottom: 8px; background: #1a1a1a; color: #fff; \
96 font-size: 11px; line-height: 1; padding: 6px 8px; border-radius: 6px; \
97 opacity: 0.85;",
98 "{status}"
99 }
100 }
101 }
102}