biji_ui/components/dialog/
root.rs1use std::time::Duration;
2
3use leptos::{
4 context::Provider,
5 leptos_dom::{self, helpers::TimeoutHandle},
6 prelude::*,
7};
8
9use crate::components::dialog::context::{DialogContext, RootContext};
10
11#[component]
12pub fn Root(
13 children: Children,
14 #[prop(into, optional)] class: String,
15 #[prop(default = true)]
17 prevent_scroll: bool,
18 #[prop(default = Duration::from_millis(200))]
20 hide_delay: Duration,
21) -> impl IntoView {
22 let root_ctx = RootContext {
23 ..RootContext::default()
24 };
25 let ctx = DialogContext {
26 root: RwSignal::new(root_ctx),
27 prevent_scroll,
28 hide_delay,
29 ..Default::default()
30 };
31
32 view! {
33 <Provider value={ctx}>
34 <RootEvents>
35 <div class={class}>
36 <Provider value={root_ctx}>{children()}</Provider>
37 </div>
38 </RootEvents>
39 </Provider>
40 }
41}
42
43#[component]
44pub fn RootEvents(children: Children) -> impl IntoView {
45 let hide_handle: StoredValue<Option<TimeoutHandle>> = StoredValue::new(None);
46 let dialog_ctx = expect_context::<DialogContext>();
47
48 let eff = RenderEffect::new(move |_| {
49 if dialog_ctx.prevent_scroll {
50 if dialog_ctx.open.get() {
51 if let Some(h) = hide_handle.get_value() {
52 h.clear();
53 }
54 if let Some(doc) = document().body() {
55 let client_width = f64::from(doc.client_width());
56 let inner_width = window()
57 .inner_width()
58 .unwrap()
59 .as_f64()
60 .unwrap_or(client_width);
61 let scrollbar_width = inner_width - client_width;
62
63 let _ = doc.style().set_property("overflow", "hidden");
64 let _ = doc
65 .style()
66 .set_property("--scrollbar-width", &format!("{}px", scrollbar_width));
67 let _ = doc
68 .style()
69 .set_property("padding-right", &format!("calc({}px)", scrollbar_width));
70 }
71 } else {
72 let h = leptos_dom::helpers::set_timeout_with_handle(
73 move || {
74 if let Some(doc) = document().body() {
75 let _ = doc.style().remove_property("overflow");
76 let _ = doc.style().remove_property("--scrollbar-width");
77 let _ = doc.style().remove_property("padding-right");
78 }
79 },
80 dialog_ctx.hide_delay,
81 )
82 .expect("set timeout in AnimatedShow");
83 hide_handle.set_value(Some(h));
84 }
85 }
86 });
87
88 on_cleanup(move || {
89 drop(eff);
90 });
91
92 children()
93}