From 683fcd8a36b2eede6294a0abbe551021f02b386d Mon Sep 17 00:00:00 2001
From: luoxiao <luoxiaozero@163.com>
Date: Mon, 8 Apr 2024 22:10:03 +0800
Subject: [PATCH] feat: Modal scrollbar

---
 thaw/src/modal/mod.rs     | 46 +++++++++++++++++++--------------------
 thaw/src/modal/modal.css  |  7 ------
 thaw/src/scrollbar/mod.rs | 20 ++++++++++++++++-
 3 files changed, 42 insertions(+), 31 deletions(-)

diff --git a/thaw/src/modal/mod.rs b/thaw/src/modal/mod.rs
index 6140cfa..6add373 100644
--- a/thaw/src/modal/mod.rs
+++ b/thaw/src/modal/mod.rs
@@ -1,7 +1,7 @@
-use crate::{Card, CardFooter, CardHeader, CardHeaderExtra, Icon};
+use crate::{Card, CardFooter, CardHeader, CardHeaderExtra, Icon, Scrollbar, ScrollbarRef};
 use leptos::*;
 use thaw_components::{CSSTransition, FocusTrap, OptionComp, Teleport};
-use thaw_utils::{mount_style, use_click_position, Model};
+use thaw_utils::{mount_style, use_click_position, ComponentRef, Model};
 
 #[slot]
 pub struct ModalFooter {
@@ -39,7 +39,7 @@ pub fn Modal(
     };
 
     let mask_ref = NodeRef::<html::Div>::new();
-    let scroll_ref = NodeRef::<html::Div>::new();
+    let scrollbar_ref = ComponentRef::<ScrollbarRef>::new();
     let modal_ref = NodeRef::<html::Div>::new();
 
     let click_position = use_click_position();
@@ -48,10 +48,10 @@ pub fn Modal(
             return;
         };
 
-        let Some(scroll_el) = scroll_ref.get_untracked() else {
+        let Some(scroll_el) = scrollbar_ref.get_untracked() else {
             return;
         };
-        let scroll_top = scroll_el.scroll_top();
+        let scroll_top = scroll_el.container_scroll_top();
 
         let Some(modal_el) = modal_ref.get_untracked() else {
             return;
@@ -71,24 +71,24 @@ pub fn Modal(
                     style:z-index=move || z_index.get()
                     style=("--thaw-width", move || width.get())
                 >
-                    <CSSTransition
-                        node_ref=mask_ref
-                        show=show.signal()
-                        name="fade-in-transition"
-                        let:display
-                    >
-                        <div
-                            class="thaw-modal-mask"
-                            style=move || display.get()
-                            on:click=on_mask_click
-                            ref=mask_ref
-                        ></div>
-                    </CSSTransition>
-                    <div
-                        class="thaw-modal-scroll"
-                        style=move || (!displayed.get()).then_some("display: none")
-                        ref=scroll_ref
+                    <Scrollbar
+                        content_style="min-height: 100%; display: flex;"
+                        style=Signal::derive(move || if displayed.get() { String::new() } else { String::from("display: none") })
+                        comp_ref=scrollbar_ref
                     >
+                        <CSSTransition
+                            node_ref=mask_ref
+                            show=show.signal()
+                            name="fade-in-transition"
+                            let:display
+                        >
+                            <div
+                                class="thaw-modal-mask"
+                                style=move || display.get()
+                                on:click=on_mask_click
+                                ref=mask_ref
+                            ></div>
+                        </CSSTransition>
                         <CSSTransition
                             node_ref=modal_ref
                             show=show.signal()
@@ -125,7 +125,7 @@ pub fn Modal(
                                 </Card>
                             </div>
                         </CSSTransition>
-                    </div>
+                    </Scrollbar>
                 </div>
             </FocusTrap>
         </Teleport>
diff --git a/thaw/src/modal/modal.css b/thaw/src/modal/modal.css
index 97efb78..867fc3e 100644
--- a/thaw/src/modal/modal.css
+++ b/thaw/src/modal/modal.css
@@ -13,13 +13,6 @@
     pointer-events: auto;
 }
 
-.thaw-modal-scroll {
-    display: flex;
-    min-height: 100%;
-    min-width: 100%;
-    overflow: scroll;
-}
-
 .thaw-modal-mask {
     position: fixed;
     top: 0;
diff --git a/thaw/src/scrollbar/mod.rs b/thaw/src/scrollbar/mod.rs
index 6329c9e..f56bcd8 100644
--- a/thaw/src/scrollbar/mod.rs
+++ b/thaw/src/scrollbar/mod.rs
@@ -4,7 +4,7 @@ pub use theme::ScrollbarTheme;
 
 use crate::{use_theme, Theme};
 use leptos::{leptos_dom::helpers::WindowListenerHandle, *};
-use thaw_utils::{class_list, mount_style, OptionalProp};
+use thaw_utils::{class_list, mount_style, ComponentRef, OptionalProp};
 
 #[component]
 pub fn Scrollbar(
@@ -13,6 +13,7 @@ pub fn Scrollbar(
     #[prop(optional, into)] content_class: OptionalProp<MaybeSignal<String>>,
     #[prop(optional, into)] content_style: OptionalProp<MaybeSignal<String>>,
     #[prop(default = 8)] size: u8,
+    #[prop(optional)] comp_ref: Option<ComponentRef<ScrollbarRef>>,
     children: Children,
 ) -> impl IntoView {
     mount_style("scrollbar", include_str!("./scrollbar.css"));
@@ -49,6 +50,12 @@ pub fn Scrollbar(
     let content_height = RwSignal::new(0);
     let thumb_status = StoredValue::new(None::<ThumbStatus>);
 
+    if let Some(comp_ref) = comp_ref {
+        comp_ref.load(ScrollbarRef {
+            container_scroll_top,
+        });
+    }
+
     let x_thumb_width = Memo::new(move |_| {
         let content_width = f64::from(content_width.get());
         let x_track_width = f64::from(x_track_width.get());
@@ -322,3 +329,14 @@ enum ThumbStatus {
     Enter,
     DelayLeave,
 }
+
+#[derive(Clone)]
+pub struct ScrollbarRef {
+    container_scroll_top: RwSignal<i32>,
+}
+
+impl ScrollbarRef {
+    pub fn container_scroll_top(&self) -> i32 {
+        self.container_scroll_top.get()
+    }
+}