1use leptos::{
2 context::Provider,
3 ev::{contextmenu, mouseup, touchend},
4 prelude::*,
5};
6use leptos_use::{use_document, use_event_listener, use_mouse_in_element, UseMouseInElementReturn};
7
8use crate::{context::PaneResizerContext, Style};
9
10#[derive(Debug, Clone, Copy)]
11pub enum Direction {
12 Horizontal,
13 Vertical,
14}
15
16impl Style for Direction {
17 fn style(&self) -> String {
18 match self {
19 Direction::Horizontal => "flex-direction: row".to_string(),
20 Direction::Vertical => "flex-direction: column".to_string(),
21 }
22 }
23}
24
25impl Direction {
26 pub fn cursor(&self) -> String {
27 match self {
28 Direction::Horizontal => "ew-resize".to_string(),
29 Direction::Vertical => "ns-resize".to_string(),
30 }
31 }
32}
33
34#[component]
35pub fn PaneGroup(
36 #[prop(into, optional)] class: String,
37 children: Children,
38 #[prop(default = Direction::Horizontal)] direction: Direction,
39) -> impl IntoView {
40 let ctx = PaneResizerContext {
41 direction,
42 ..Default::default()
43 };
44
45 let UseMouseInElementReturn {
46 element_width,
47 element_height,
48 element_x,
49 element_y,
50 ..
51 } = use_mouse_in_element(ctx.group_ref);
52
53 let handle_on_mouseup = move |_| {
54 ctx.resizing.set(false);
55 };
56
57 let _ = use_event_listener(use_document(), mouseup, move |_| {
58 ctx.resizing.set(false);
59 });
60
61 let _ = use_event_listener(use_document(), touchend, move |_| {
62 ctx.resizing.set(false);
63 });
64
65 let _ = use_event_listener(use_document(), contextmenu, move |_| {
66 ctx.resizing.set(false);
67 });
68
69 Effect::new(move |_| {
70 if ctx.resizing.get() {
71 let new_size = match direction {
72 Direction::Horizontal => (element_x.get() / element_width.get()) * 100.0,
73 Direction::Vertical => (element_y.get() / element_height.get()) * 100.0,
74 };
75
76 let panes = ctx.panes.get();
77
78 if panes.keys().len() == 2 {
79 let mut panes = panes.iter();
80 let (_, first_pane_ctx) = panes.next().unwrap();
81 let (_, second_pane_ctx) = panes.next().unwrap();
82
83 let first_pane_size = new_size;
84 let second_pane_size = 100.0 - new_size;
85
86 first_pane_ctx.size.set(first_pane_size);
87 second_pane_ctx.size.set(second_pane_size);
88 }
89 }
90 });
91
92 view! {
93 <Provider value=ctx>
94 <div
95 node_ref=ctx.group_ref
96 class=class
97 style:display="flex"
98 style:height="100%"
99 style:width="100%"
100 style:overflow="hidden"
101 style=direction.style()
102 on:mouseup=handle_on_mouseup
103 >
104 {children()}
105 </div>
106 </Provider>
107 }
108}