77import type { ReactNode , MutableRefObject } from "react" ;
88import React , { useState , useRef , useEffect } from "react" ;
99import { cn } from "@plane/utils" ;
10+ import { runIdleTask } from "@/lib/idle-task" ;
1011
1112type Props = {
1213 defaultHeight ?: string ;
@@ -19,18 +20,10 @@ type Props = {
1920 placeholderChildren ?: ReactNode ;
2021 defaultValue ?: boolean ;
2122 shouldRecordHeights ?: boolean ;
22- useIdletime ?: boolean ;
23+ useIdleTime ?: boolean ;
2324 forceRender ?: boolean ;
2425} ;
2526
26- const runIdleTask = ( callback : ( ) => void ) => {
27- if ( typeof window !== "undefined" && typeof window . requestIdleCallback === "function" ) {
28- window . requestIdleCallback ( callback , { timeout : 300 } ) ;
29- return ;
30- }
31- globalThis . setTimeout ( callback , 0 ) ;
32- } ;
33-
3427function RenderIfVisible ( props : Props ) {
3528 const {
3629 defaultHeight = "300px" ,
@@ -44,12 +37,14 @@ function RenderIfVisible(props: Props) {
4437 //placeholder children
4538 placeholderChildren = null , //placeholder children
4639 defaultValue = false ,
47- useIdletime = false ,
40+ useIdleTime = false ,
4841 forceRender = false ,
4942 } = props ;
5043 const [ shouldVisible , setShouldVisible ] = useState < boolean > ( defaultValue ) ;
5144 const placeholderHeight = useRef < string > ( defaultHeight ) ;
5245 const intersectionRef = useRef < HTMLElement | null > ( null ) ;
46+ const visibilityIdleTaskRef = useRef < ReturnType < typeof runIdleTask > | null > ( null ) ;
47+ const heightIdleTaskRef = useRef < ReturnType < typeof runIdleTask > | null > ( null ) ;
5348
5449 const isVisible = shouldVisible || forceRender ;
5550
@@ -60,8 +55,11 @@ function RenderIfVisible(props: Props) {
6055 const observer = new IntersectionObserver (
6156 ( entries ) => {
6257 //DO no remove comments for future
63- if ( typeof window !== "undefined" && useIdletime ) {
64- runIdleTask ( ( ) => setShouldVisible ( entries [ entries . length - 1 ] . isIntersecting ) ) ;
58+ if ( typeof window !== "undefined" && useIdleTime ) {
59+ visibilityIdleTaskRef . current ?. cancel ( ) ;
60+ visibilityIdleTaskRef . current = runIdleTask ( ( ) =>
61+ setShouldVisible ( entries [ entries . length - 1 ] . isIntersecting )
62+ ) ;
6563 } else {
6664 setShouldVisible ( entries [ entries . length - 1 ] . isIntersecting ) ;
6765 }
@@ -73,18 +71,25 @@ function RenderIfVisible(props: Props) {
7371 ) ;
7472 observer . observe ( target ) ;
7573 return ( ) => {
74+ visibilityIdleTaskRef . current ?. cancel ( ) ;
75+ visibilityIdleTaskRef . current = null ;
7676 observer . unobserve ( target ) ;
7777 } ;
7878 }
79- } , [ intersectionRef , root , verticalOffset , horizontalOffset , useIdletime ] ) ;
79+ } , [ intersectionRef , root , verticalOffset , horizontalOffset , useIdleTime ] ) ;
8080
8181 //Set height after render
8282 useEffect ( ( ) => {
8383 if ( intersectionRef . current && isVisible && shouldRecordHeights ) {
84- runIdleTask ( ( ) => {
84+ heightIdleTaskRef . current ?. cancel ( ) ;
85+ heightIdleTaskRef . current = runIdleTask ( ( ) => {
8586 if ( intersectionRef . current ) placeholderHeight . current = `${ intersectionRef . current . offsetHeight } px` ;
8687 } ) ;
8788 }
89+ return ( ) => {
90+ heightIdleTaskRef . current ?. cancel ( ) ;
91+ heightIdleTaskRef . current = null ;
92+ } ;
8893 } , [ isVisible , intersectionRef , shouldRecordHeights ] ) ;
8994
9095 const child = isVisible ? < > { children } </ > : placeholderChildren ;
0 commit comments