From 4bfd4393dae5b1a600cfdb58ea05649ce2e30da5 Mon Sep 17 00:00:00 2001
From: Jet Li <jing.i.qin@icloud.com>
Date: Tue, 5 Mar 2024 17:58:26 +0800
Subject: [PATCH] use_visible demo

---
 README.md                                     |  7 +++--
 crates/yew-hooks/Cargo.toml                   |  4 +--
 crates/yew-hooks/src/hooks/use_visible.rs     | 14 ++++++----
 crates/yew-hooks/src/hooks/use_websocket.rs   |  4 +--
 examples/yew-app/src/app/home.rs              |  1 +
 examples/yew-app/src/app/hooks/mod.rs         |  2 ++
 examples/yew-app/src/app/hooks/use_visible.rs | 28 +++++++++++++++++++
 examples/yew-app/src/app/mod.rs               |  3 ++
 8 files changed, 50 insertions(+), 13 deletions(-)
 create mode 100644 examples/yew-app/src/app/hooks/use_visible.rs

diff --git a/README.md b/README.md
index af48b1a..da4fedf 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@ fn counter() -> Html {
         let counter = counter.clone();
         Callback::from(move |_| counter.decrease())
     };
-    
+
     html! {
         <>
             <button onclick={onincrease}>{ "Increase" }</button>
@@ -72,7 +72,7 @@ fn counter() -> Html {
 
 - `use_toggle` - tracks state of counterparts.
 - `use_bool_toggle` - tracks state of a boolean.
-- `use_counter` -  tracks state of a number.
+- `use_counter` - tracks state of a number.
 - `use_latest` - returns the latest immutable ref to state or props.
 - `use_mut_latest` - returns the latest mutable ref to state or props.
 - `use_previous` - returns the previous immutable ref to state or props.
@@ -134,6 +134,7 @@ fn counter() -> Html {
 - `use_measure` - tracks an HTML element's dimensions using the `ResizeObserver` API.
 - `use_geolocation` - tracks user's geographic location.
 - `use_swipe` - detects swipe based on TouchEvent.
+- `use_visible` - checks if an element is visible.
 
 ### UI
 
@@ -178,7 +179,7 @@ fn counter() -> Html {
         let counter = counter.clone();
         Callback::from(move |_| counter.reset())
     };
-    
+
     html! {
         <div>
             <button onclick={onincrease}>{ "Increase" }</button>
diff --git a/crates/yew-hooks/Cargo.toml b/crates/yew-hooks/Cargo.toml
index 27d40fa..cdde7fb 100644
--- a/crates/yew-hooks/Cargo.toml
+++ b/crates/yew-hooks/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "yew-hooks"
-version = "0.3.0"
+version = "0.3.1"
 edition = "2021"
 authors = ["Jet Li <jing.i.qin@icloud.com>"]
 categories = ["gui", "wasm", "web-programming"]
@@ -16,7 +16,7 @@ documentation = "https://docs.rs/yew-hooks/"
 
 [dependencies]
 log = "0.4"
-yew = { version = "0.21.0", features=["csr"] }
+yew = { version = "0.21.0", features = ["csr"] }
 gloo = "0.10"
 wasm-bindgen = "0.2"
 wasm-bindgen-futures = "0.4"
diff --git a/crates/yew-hooks/src/hooks/use_visible.rs b/crates/yew-hooks/src/hooks/use_visible.rs
index 61a0d8e..812c10c 100644
--- a/crates/yew-hooks/src/hooks/use_visible.rs
+++ b/crates/yew-hooks/src/hooks/use_visible.rs
@@ -4,7 +4,6 @@ use yew::prelude::*;
 
 use super::use_effect_once;
 
-#[hook]
 /// Check if an element is visible. Internally, it uses an [`IntersectionObserver`] to receive
 /// notifications from the browser whenever the visibility state of the node changes.
 ///
@@ -15,13 +14,15 @@ use super::use_effect_once;
 /// # Example
 ///
 /// ```rust
-/// use yew::prelude::*;
-/// use yew_hooks::use_visible;
+/// # use yew::prelude::*;
+/// #
+/// use yew_hooks::prelude::*;
 ///
 /// #[function_component]
 /// fn MyComponent() -> Html {
 ///     let node = use_node_ref();
 ///     let visible = use_visible(node.clone(), false);
+///
 ///     html! {
 ///         <div ref={node}>
 ///             if visible {
@@ -33,11 +34,13 @@ use super::use_effect_once;
 ///     }
 /// }
 /// ```
+#[hook]
 pub fn use_visible(node: NodeRef, sticky: bool) -> bool {
     // code adapted from:
     // https://stackoverflow.com/questions/1462138/event-listener-for-when-element-becomes-visible
     let visible = use_state_eq(|| false);
     let visible_clone = visible.clone();
+
     use_effect_once(move || {
         let closure = Closure::<dyn Fn(Vec<IntersectionObserverEntry>, IntersectionObserver)>::new(
             move |entries: Vec<IntersectionObserverEntry>, observer: IntersectionObserver| {
@@ -45,9 +48,7 @@ pub fn use_visible(node: NodeRef, sticky: bool) -> bool {
                 let visible = entries.iter().any(|entry| entry.intersection_ratio() > 0.0);
 
                 // if the visibility changed, update the state.
-                if (visible != *visible_clone) && (!sticky || !*visible_clone) {
-                    visible_clone.set(visible);
-                }
+                visible_clone.set(visible);
 
                 // if this is sticky and it is currently visible, disconnect the observer.
                 if visible && sticky {
@@ -62,5 +63,6 @@ pub fn use_visible(node: NodeRef, sticky: bool) -> bool {
         }
         move || observer.disconnect()
     });
+
     *visible
 }
diff --git a/crates/yew-hooks/src/hooks/use_websocket.rs b/crates/yew-hooks/src/hooks/use_websocket.rs
index fd11804..d39a63f 100644
--- a/crates/yew-hooks/src/hooks/use_websocket.rs
+++ b/crates/yew-hooks/src/hooks/use_websocket.rs
@@ -33,9 +33,9 @@ pub struct UseWebSocketOptions {
     /// `WebSocket` close callback.
     pub onclose: Option<Box<dyn FnMut(CloseEvent)>>,
 
-    /// Retry times.
+    /// Retry times. Defaults to 3, use `u32::MAX` for infinite retries.
     pub reconnect_limit: Option<u32>,
-    /// Retry interval(ms).
+    /// Retry interval(ms). Defaults to 3000.
     pub reconnect_interval: Option<u32>,
     /// Manually starts connection
     pub manual: Option<bool>,
diff --git a/examples/yew-app/src/app/home.rs b/examples/yew-app/src/app/home.rs
index d968b6c..e90474f 100644
--- a/examples/yew-app/src/app/home.rs
+++ b/examples/yew-app/src/app/home.rs
@@ -89,6 +89,7 @@ pub fn home() -> Html {
                         <li><Link<AppRoute> to={AppRoute::UseMeasure} classes="text-emerald-800 underline" >{ "use_measure" }</Link<AppRoute>> { " - tracks an HTML element's dimensions using the ResizeObserver API." }</li>
                         <li><Link<AppRoute> to={AppRoute::UseGeolocation} classes="text-emerald-800 underline" >{ "use_geolocation" }</Link<AppRoute>> { " - tracks user's geographic location." }</li>
                         <li><Link<AppRoute> to={AppRoute::UseSwipe} classes="text-emerald-800 underline" >{ "use_swipe" }</Link<AppRoute>> { " - detects swipe based on TouchEvent." }</li>
+                        <li><Link<AppRoute> to={AppRoute::UseVisible} classes="text-emerald-800 underline" >{ "use_visible" }</Link<AppRoute>> { " - checks if an element is visible." }</li>
                     </ul>
 
                     <h2 class="text-2xl font-bold">{ "UI" }</h2>
diff --git a/examples/yew-app/src/app/hooks/mod.rs b/examples/yew-app/src/app/hooks/mod.rs
index 811beed..4201893 100644
--- a/examples/yew-app/src/app/hooks/mod.rs
+++ b/examples/yew-app/src/app/hooks/mod.rs
@@ -51,6 +51,7 @@ mod use_title;
 mod use_toggle;
 mod use_unmount;
 mod use_update;
+mod use_visible;
 mod use_websocket;
 mod use_window_scroll;
 mod use_window_size;
@@ -108,6 +109,7 @@ pub use use_title::*;
 pub use use_toggle::*;
 pub use use_unmount::*;
 pub use use_update::*;
+pub use use_visible::*;
 pub use use_websocket::*;
 pub use use_window_scroll::*;
 pub use use_window_size::*;
diff --git a/examples/yew-app/src/app/hooks/use_visible.rs b/examples/yew-app/src/app/hooks/use_visible.rs
new file mode 100644
index 0000000..644b71a
--- /dev/null
+++ b/examples/yew-app/src/app/hooks/use_visible.rs
@@ -0,0 +1,28 @@
+use yew::prelude::*;
+use yew_hooks::prelude::*;
+
+/// `use_visible` demo
+#[function_component]
+pub fn UseVisible() -> Html {
+    let node = use_node_ref();
+    let visible = use_visible(node.clone(), false);
+
+    html! {
+        <div class="container">
+            <header class="mt-24 text-xl text-center">
+                <div class="space-x-4 space-y-4">
+                    <p>
+                        <b>{ " Visible: " }</b>
+                        { visible }
+                    </p>
+                    <div class="w-[600px] h-[400px] overflow-scroll bg-emerald-800 mx-auto text-slate-100">
+                        <div class="w-[1000px] h-[1000px] text-left">
+                            <div class="h-[600px]">{ "Try to scroll in this area." }</div>
+                            <div ref={node} class="w-[100px] h-[100px] bg-slate-800"></div>
+                        </div>
+                    </div>
+                </div>
+            </header>
+        </div>
+    }
+}
diff --git a/examples/yew-app/src/app/mod.rs b/examples/yew-app/src/app/mod.rs
index 8e429e5..a21f97c 100644
--- a/examples/yew-app/src/app/mod.rs
+++ b/examples/yew-app/src/app/mod.rs
@@ -127,6 +127,8 @@ pub enum AppRoute {
     UseClipboard,
     #[at("/use_infinite_scroll")]
     UseInfiniteScroll,
+    #[at("/use_visible")]
+    UseVisible,
     #[not_found]
     #[at("/page-not-found")]
     PageNotFound,
@@ -195,6 +197,7 @@ pub fn switch(routes: AppRoute) -> Html {
         AppRoute::UseFavicon => html! { <UseFavicon /> },
         AppRoute::UseClipboard => html! { <UseClipboard /> },
         AppRoute::UseInfiniteScroll => html! { <UseInfiniteScroll /> },
+        AppRoute::UseVisible => html! { <UseVisible /> },
         AppRoute::PageNotFound => html! { <Home /> },
     }
 }