[WEB-2316] chore: Render Tooltips and Drop downs in certain places on hover hover to improve rendering performance (#5456)
* render tooltips and dropdowns in certain places post hover to improve performance * fix useEffect hooks
This commit is contained in:
parent
33ab6029dc
commit
693085577d
14 changed files with 684 additions and 515 deletions
73
packages/ui/src/dropdowns/combo-box.tsx
Normal file
73
packages/ui/src/dropdowns/combo-box.tsx
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import { Combobox } from "@headlessui/react";
|
||||
import React, {
|
||||
ElementType,
|
||||
Fragment,
|
||||
KeyboardEventHandler,
|
||||
ReactNode,
|
||||
Ref,
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
|
||||
type Props = {
|
||||
as?: ElementType | undefined;
|
||||
ref?: Ref<HTMLElement> | undefined;
|
||||
tabIndex?: number | undefined;
|
||||
className?: string | undefined;
|
||||
value?: string | string[] | null;
|
||||
onChange?: (value: any) => void;
|
||||
disabled?: boolean | undefined;
|
||||
onKeyDown?: KeyboardEventHandler<HTMLDivElement> | undefined;
|
||||
multiple?: boolean;
|
||||
renderByDefault?: boolean;
|
||||
button: ReactNode;
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
const ComboDropDown = forwardRef((props: Props, ref) => {
|
||||
const { button, renderByDefault = true, children, ...rest } = props;
|
||||
|
||||
const dropDownButtonRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const [shouldRender, setShouldRender] = useState(renderByDefault);
|
||||
|
||||
const onHover = () => {
|
||||
setShouldRender(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const element = dropDownButtonRef.current;
|
||||
|
||||
if (!element) return;
|
||||
|
||||
element.addEventListener("mouseenter", onHover);
|
||||
|
||||
return () => {
|
||||
element?.removeEventListener("mouseenter", onHover);
|
||||
};
|
||||
}, [dropDownButtonRef, shouldRender]);
|
||||
|
||||
if (!shouldRender) {
|
||||
return (
|
||||
<div ref={dropDownButtonRef} className="h-full flex items-center">
|
||||
{button}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
//@ts-ignore
|
||||
<Combobox {...rest} ref={ref}>
|
||||
<Combobox.Button as={Fragment}>{button}</Combobox.Button>
|
||||
{children}
|
||||
</Combobox>
|
||||
);
|
||||
});
|
||||
|
||||
const ComboOptions = Combobox.Options;
|
||||
const ComboOption = Combobox.Option;
|
||||
const ComboInput = Combobox.Input;
|
||||
|
||||
export { ComboDropDown, ComboOptions, ComboOption, ComboInput };
|
||||
|
|
@ -2,3 +2,4 @@ export * from "./context-menu";
|
|||
export * from "./custom-menu";
|
||||
export * from "./custom-select";
|
||||
export * from "./custom-search-select";
|
||||
export * from "./combo-box";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React from "react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Tooltip2 } from "@blueprintjs/popover2";
|
||||
// helpers
|
||||
import { cn } from "../../helpers";
|
||||
|
|
@ -42,37 +42,67 @@ export const Tooltip: React.FC<ITooltipProps> = ({
|
|||
openDelay = 200,
|
||||
closeDelay,
|
||||
isMobile = false,
|
||||
}) => (
|
||||
<Tooltip2
|
||||
disabled={disabled}
|
||||
hoverOpenDelay={openDelay}
|
||||
hoverCloseDelay={closeDelay}
|
||||
content={
|
||||
<div
|
||||
className={cn(
|
||||
"relative block z-50 max-w-xs gap-1 overflow-hidden break-words rounded-md bg-custom-background-100 p-2 text-xs text-custom-text-200 shadow-md",
|
||||
{
|
||||
hidden: isMobile,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{tooltipHeading && <h5 className="font-medium text-custom-text-100">{tooltipHeading}</h5>}
|
||||
{tooltipContent}
|
||||
}) => {
|
||||
const toolTipRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const [shouldRender, setShouldRender] = useState(false);
|
||||
|
||||
const onHover = () => {
|
||||
setShouldRender(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const element = toolTipRef.current;
|
||||
|
||||
if (!element) return;
|
||||
|
||||
element.addEventListener("mouseenter", onHover);
|
||||
|
||||
return () => {
|
||||
element?.removeEventListener("mouseenter", onHover);
|
||||
};
|
||||
}, [toolTipRef, shouldRender]);
|
||||
|
||||
if (!shouldRender) {
|
||||
return (
|
||||
<div ref={toolTipRef} className="h-full flex items-center">
|
||||
{children}
|
||||
</div>
|
||||
}
|
||||
position={position}
|
||||
renderTarget={({
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
isOpen: isTooltipOpen,
|
||||
ref: eleReference,
|
||||
...tooltipProps
|
||||
}) =>
|
||||
React.cloneElement(children, {
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip2
|
||||
disabled={disabled}
|
||||
hoverOpenDelay={openDelay}
|
||||
hoverCloseDelay={closeDelay}
|
||||
content={
|
||||
<div
|
||||
className={cn(
|
||||
"relative block z-50 max-w-xs gap-1 overflow-hidden break-words rounded-md bg-custom-background-100 p-2 text-xs text-custom-text-200 shadow-md",
|
||||
{
|
||||
hidden: isMobile,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{tooltipHeading && <h5 className="font-medium text-custom-text-100">{tooltipHeading}</h5>}
|
||||
{tooltipContent}
|
||||
</div>
|
||||
}
|
||||
position={position}
|
||||
renderTarget={({
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
isOpen: isTooltipOpen,
|
||||
ref: eleReference,
|
||||
...tooltipProps,
|
||||
...children.props,
|
||||
})
|
||||
}
|
||||
/>
|
||||
);
|
||||
...tooltipProps
|
||||
}) =>
|
||||
React.cloneElement(children, {
|
||||
ref: eleReference,
|
||||
...tooltipProps,
|
||||
...children.props,
|
||||
})
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue