1use std::rc::Rc;
4
5use gpui::prelude::*;
6use gpui::{div, AnyElement, App, ElementId, IntoElement, Window};
7
8use super::chip::DragChip;
9use crate::devtools::Probed;
10use crate::theme::theme;
11
12type DropHandler<T> = Rc<dyn Fn(&T, &mut Window, &mut App) + 'static>;
13
14#[derive(IntoElement)]
24pub struct DropTarget<T: Clone + 'static> {
25 id: ElementId,
26 child: Option<AnyElement>,
27 highlight: bool,
28 on_drop: Option<DropHandler<T>>,
29}
30
31impl<T: Clone + 'static> DropTarget<T> {
32 pub fn new(id: impl Into<ElementId>) -> Self {
33 DropTarget {
34 id: id.into(),
35 child: None,
36 highlight: true,
37 on_drop: None,
38 }
39 }
40
41 pub fn plain(mut self) -> Self {
43 self.highlight = false;
44 self
45 }
46
47 pub fn child(mut self, child: impl IntoElement) -> Self {
48 self.child = Some(child.into_any_element());
49 self
50 }
51
52 pub fn on_drop(mut self, handler: impl Fn(&T, &mut Window, &mut App) + 'static) -> Self {
54 self.on_drop = Some(Rc::new(handler));
55 self
56 }
57}
58
59impl<T: Clone + 'static> RenderOnce for DropTarget<T> {
60 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
61 let t = theme(cx);
62 let accent = t.primary();
63 let accent_border = accent.hsla();
64 let accent_tint = accent.alpha(0.08);
65
66 let mut root = div().id(self.id);
67 if self.highlight {
68 root = root.drag_over::<DragChip<T>>(move |style, _drag, _window, _cx| {
69 style.border_color(accent_border).bg(accent_tint)
70 });
71 }
72 if let Some(handler) = self.on_drop {
73 root = root.on_drop(move |dragged: &DragChip<T>, window, cx| {
74 handler(&dragged.value, window, cx);
75 });
76 }
77 if let Some(child) = self.child {
78 root = root.child(child);
79 }
80 root.probe("DropTarget")
81 }
82}