pane_resizer/
group.rs

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}