Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions apps/web/core/components/core/render-if-visible-HOC.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import type { ReactNode, MutableRefObject } from "react";
import React, { useState, useRef, useEffect } from "react";
import { cn } from "@plane/utils";
import { safeCancelIdleCallback, safeRequestIdleCallback } from "@/lib/polyfills";

type Props = {
defaultHeight?: string;
Expand Down Expand Up @@ -47,12 +48,15 @@ function RenderIfVisible(props: Props) {

// Set visibility with intersection observer
useEffect(() => {
if (intersectionRef.current) {
const node = intersectionRef.current;
if (node) {
let idleHandle: number | undefined;
const observer = new IntersectionObserver(
(entries) => {
//DO no remove comments for future
if (typeof window !== undefined && window.requestIdleCallback && useIdletime) {
window.requestIdleCallback(() => setShouldVisible(entries[entries.length - 1].isIntersecting), {
if (useIdletime) {
if (idleHandle !== undefined) safeCancelIdleCallback(idleHandle);
idleHandle = safeRequestIdleCallback(() => setShouldVisible(entries[entries.length - 1].isIntersecting), {
timeout: 300,
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.
} else {
Expand All @@ -64,20 +68,18 @@ function RenderIfVisible(props: Props) {
rootMargin: `${verticalOffset}% ${horizontalOffset}% ${verticalOffset}% ${horizontalOffset}%`,
}
);
observer.observe(intersectionRef.current);
observer.observe(node);
return () => {
if (intersectionRef.current) {
// eslint-disable-next-line react-hooks/exhaustive-deps
observer.unobserve(intersectionRef.current);
}
observer.unobserve(node);
if (idleHandle !== undefined) safeCancelIdleCallback(idleHandle);
};
}
}, [intersectionRef, children, root, verticalOffset, horizontalOffset]);
}, [intersectionRef, children, root, verticalOffset, horizontalOffset, useIdletime]);

//Set height after render
useEffect(() => {
if (intersectionRef.current && isVisible && shouldRecordHeights) {
window.requestIdleCallback(() => {
safeRequestIdleCallback(() => {
if (intersectionRef.current) placeholderHeight.current = `${intersectionRef.current.offsetHeight}px`;
});
}
Expand Down
29 changes: 28 additions & 1 deletion apps/web/core/lib/polyfills/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,31 @@ if (typeof window !== "undefined" && window) {
};
}

export {};
// Defensive wrappers for use at call sites that may run before the side-effect
// above is applied (e.g., lazy-loaded chunks like gantt-layout-loader that can
// execute before app/provider.tsx finishes evaluating).
export const safeRequestIdleCallback: typeof window.requestIdleCallback = (cb, options) => {
if (typeof window !== "undefined" && window.requestIdleCallback) {
return window.requestIdleCallback(cb, options);
}
const start = Date.now();
// setTimeout's return type is `number | NodeJS.Timeout` depending on the resolved
// typings; in a browser context (the only path that reaches this fallback) it is
// always `number`. Cast to satisfy the DOM-shaped IdleCallbackHandle return.
return setTimeout(
() =>
cb({
didTimeout: false,
timeRemaining: () => Math.max(0, 50 - (Date.now() - start)),
}),
1
) as unknown as number;
};

export const safeCancelIdleCallback: typeof window.cancelIdleCallback = (id) => {
if (typeof window !== "undefined" && window.cancelIdleCallback) {
window.cancelIdleCallback(id);
return;
}
clearTimeout(id);
};