|
|
@@ -0,0 +1,75 @@
|
|
|
+"use client";
|
|
|
+
|
|
|
+import React from "react";
|
|
|
+
|
|
|
+/**
|
|
|
+ * useDebouncedVisibility
|
|
|
+ *
|
|
|
+ * Delays the "show" transition and optionally enforces a minimum visible time.
|
|
|
+ *
|
|
|
+ * Typical use cases:
|
|
|
+ * - Avoid flicker for fast loading indicators (e.g. show only after 300ms).
|
|
|
+ * - Keep the indicator visible for at least X ms once shown (avoid blink).
|
|
|
+ *
|
|
|
+ * @param {boolean} isActive
|
|
|
+ * @param {{ delayMs?: number, minVisibleMs?: number }} options
|
|
|
+ * @returns {boolean}
|
|
|
+ */
|
|
|
+export function useDebouncedVisibility(
|
|
|
+ isActive,
|
|
|
+ { delayMs = 200, minVisibleMs = 0 } = {},
|
|
|
+) {
|
|
|
+ const [visible, setVisible] = React.useState(false);
|
|
|
+
|
|
|
+ const showTimerRef = React.useRef(null);
|
|
|
+ const hideTimerRef = React.useRef(null);
|
|
|
+ const visibleSinceRef = React.useRef(0);
|
|
|
+
|
|
|
+ React.useEffect(() => {
|
|
|
+ if (showTimerRef.current) {
|
|
|
+ clearTimeout(showTimerRef.current);
|
|
|
+ showTimerRef.current = null;
|
|
|
+ }
|
|
|
+ if (hideTimerRef.current) {
|
|
|
+ clearTimeout(hideTimerRef.current);
|
|
|
+ hideTimerRef.current = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isActive) {
|
|
|
+ if (!visible) {
|
|
|
+ showTimerRef.current = setTimeout(
|
|
|
+ () => {
|
|
|
+ visibleSinceRef.current = Date.now();
|
|
|
+ setVisible(true);
|
|
|
+ },
|
|
|
+ Math.max(0, Number(delayMs) || 0),
|
|
|
+ );
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!visible) return;
|
|
|
+
|
|
|
+ const now = Date.now();
|
|
|
+ const elapsed = now - (visibleSinceRef.current || now);
|
|
|
+ const minMs = Math.max(0, Number(minVisibleMs) || 0);
|
|
|
+
|
|
|
+ if (elapsed >= minMs) {
|
|
|
+ setVisible(false);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ hideTimerRef.current = setTimeout(() => {
|
|
|
+ setVisible(false);
|
|
|
+ }, minMs - elapsed);
|
|
|
+ }, [isActive, delayMs, minVisibleMs, visible]);
|
|
|
+
|
|
|
+ React.useEffect(() => {
|
|
|
+ return () => {
|
|
|
+ if (showTimerRef.current) clearTimeout(showTimerRef.current);
|
|
|
+ if (hideTimerRef.current) clearTimeout(hideTimerRef.current);
|
|
|
+ };
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ return visible;
|
|
|
+}
|