1use std::rc::Rc;
2
3use gpui::{
4 AnyElement, App, Div, ElementId, FocusHandle, InteractiveElement, Interactivity, IntoElement,
5 ParentElement, RenderOnce, Role, StatefulInteractiveElement, StyleRefinement, Styled, Window,
6 div,
7};
8
9use crate::{
10 StyledExt as _,
11 actions::{Cancel, Confirm},
12};
13
14type OpenChange = Rc<dyn Fn(bool, &mut Window, &mut App)>;
15
16#[derive(IntoElement)]
19pub struct DatePicker {
20 base: gpui::Stateful<Div>,
21 open: bool,
22 disabled: bool,
23 focus_handle: FocusHandle,
24 style: StyleRefinement,
25 children: Vec<AnyElement>,
26 on_open_change: Option<OpenChange>,
27}
28
29impl DatePicker {
30 pub fn new(id: impl Into<ElementId>, focus_handle: &FocusHandle) -> Self {
31 Self {
32 base: div().id(id),
33 open: false,
34 disabled: false,
35 focus_handle: focus_handle.clone(),
36 style: StyleRefinement::default(),
37 children: vec![],
38 on_open_change: None,
39 }
40 }
41 pub fn open(mut self, open: bool) -> Self {
42 self.open = open;
43 self
44 }
45 pub fn disabled(mut self, disabled: bool) -> Self {
46 self.disabled = disabled;
47 self
48 }
49 pub fn on_open_change(
50 mut self,
51 handler: impl Fn(bool, &mut Window, &mut App) + 'static,
52 ) -> Self {
53 self.on_open_change = Some(Rc::new(handler));
54 self
55 }
56}
57impl Styled for DatePicker {
58 fn style(&mut self) -> &mut StyleRefinement {
59 &mut self.style
60 }
61}
62impl ParentElement for DatePicker {
63 fn extend(&mut self, children: impl IntoIterator<Item = AnyElement>) {
64 self.children.extend(children);
65 }
66}
67impl InteractiveElement for DatePicker {
68 fn interactivity(&mut self) -> &mut Interactivity {
69 self.base.interactivity()
70 }
71}
72impl StatefulInteractiveElement for DatePicker {}
73impl RenderOnce for DatePicker {
74 fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
75 let open = self.open;
76 let disabled = self.disabled;
77 let handler = self.on_open_change;
78 self.base
79 .role(Role::ComboBox)
80 .aria_expanded(open)
81 .track_focus(&self.focus_handle.tab_stop(!disabled))
82 .on_action({
83 let handler = handler.clone();
84 move |_: &Confirm, window, cx| {
85 if disabled {
86 cx.propagate();
87 } else if !open {
88 if let Some(handler) = &handler {
89 handler(true, window, cx);
90 }
91 }
92 }
93 })
94 .on_action(move |_: &Cancel, window, cx| {
95 if open {
96 if let Some(handler) = &handler {
97 handler(false, window, cx);
98 }
99 } else {
100 cx.propagate();
101 }
102 })
103 .refine_style(&self.style)
104 .children(self.children)
105 }
106}