[WEB-2444] improvement: performance improvement for useOutsideClickDetector and usePeekOverviewOutsideClickDetector. (#5595)

* [WEB-2444] improvement: performace improvement for `useOutsideClickDetector` and `usePeekOverviewOutsideClickDetector`.

* Move outside click detector to plane helpers package.

* chore: remove plane helpers yarn.lock
This commit is contained in:
Prateek Shourya 2024-09-12 20:10:04 +05:30 committed by GitHub
parent 441385fc95
commit b2533b94ce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
53 changed files with 148 additions and 198 deletions

View file

@ -0,0 +1 @@
export * from "./use-outside-click-detector";

View file

@ -0,0 +1,29 @@
import React, { useEffect } from "react";
export const useOutsideClickDetector = (
ref: React.RefObject<HTMLElement>,
callback: () => void,
useCapture = false
) => {
const handleClick = (event: MouseEvent) => {
if (ref.current && !ref.current.contains(event.target as Node)) {
// check for the closest element with attribute name data-prevent-outside-click
const preventOutsideClickElement = (
event.target as HTMLElement | undefined
)?.closest("[data-prevent-outside-click]");
// if the closest element with attribute name data-prevent-outside-click is found, return
if (preventOutsideClickElement) {
return;
}
// else call the callback
callback();
}
};
useEffect(() => {
document.addEventListener("mousedown", handleClick, useCapture);
return () => {
document.removeEventListener("mousedown", handleClick, useCapture);
};
});
};

View file

@ -0,0 +1 @@
export * from "./hooks";

View file

@ -0,0 +1,15 @@
{
"name": "@plane/helpers",
"version": "0.22.0",
"description": "Helper functions shared across multiple apps internally",
"main": "index.ts",
"private": true,
"devDependencies": {
"@types/node": "^22.5.4",
"@types/react": "^18.3.5",
"typescript": "^5.6.2"
},
"dependencies": {
"react": "^18.3.1"
}
}

View file

@ -26,6 +26,7 @@
"@blueprintjs/popover2": "^1.13.3",
"@headlessui/react": "^1.7.3",
"@popperjs/core": "^2.11.8",
"@plane/helpers": "*",
"clsx": "^2.0.0",
"emoji-picker-react": "^4.5.16",
"lodash": "^4.17.21",

View file

@ -4,12 +4,13 @@ import sortBy from "lodash/sortBy";
import { Combobox } from "@headlessui/react";
// popper-js
import { usePopper } from "react-popper";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// components
import { DropdownButton } from "./common";
import { DropdownOptions } from "./common/options";
// hooks
import { useDropdownKeyPressed } from "../hooks/use-dropdown-key-pressed";
import useOutsideClickDetector from "../hooks/use-outside-click-detector";
// helper
import { cn } from "../../helpers";
// types

View file

@ -4,12 +4,13 @@ import sortBy from "lodash/sortBy";
import { Combobox } from "@headlessui/react";
// popper-js
import { usePopper } from "react-popper";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// components
import { DropdownButton } from "./common";
import { DropdownOptions } from "./common/options";
// hooks
import { useDropdownKeyPressed } from "../hooks/use-dropdown-key-pressed";
import useOutsideClickDetector from "../hooks/use-outside-click-detector";
// helper
import { cn } from "../../helpers";
// types

View file

@ -1,11 +1,12 @@
import React, { useEffect, useRef, useState } from "react";
import ReactDOM from "react-dom";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// components
import { ContextMenuItem } from "./item";
// helpers
import { cn } from "../../../helpers";
// hooks
import useOutsideClickDetector from "../../hooks/use-outside-click-detector";
import { usePlatformOS } from "../../hooks/use-platform-os";
export type TContextMenuItem = {

View file

@ -3,9 +3,10 @@ import ReactDOM from "react-dom";
import { Menu } from "@headlessui/react";
import { usePopper } from "react-popper";
import { ChevronDown, MoreHorizontal } from "lucide-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// hooks
import { useDropdownKeyDown } from "../hooks/use-dropdown-key-down";
import useOutsideClickDetector from "../hooks/use-outside-click-detector";
// helpers
import { cn } from "../../helpers";
// types

View file

@ -3,9 +3,10 @@ import { usePopper } from "react-popper";
import { Combobox } from "@headlessui/react";
import { Check, ChevronDown, Search } from "lucide-react";
import { createPortal } from "react-dom";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// hooks
import { useDropdownKeyDown } from "../hooks/use-dropdown-key-down";
import useOutsideClickDetector from "../hooks/use-outside-click-detector";
// helpers
import { cn } from "../../helpers";
// types

View file

@ -2,9 +2,10 @@ import React, { useRef, useState } from "react";
import { usePopper } from "react-popper";
import { Listbox } from "@headlessui/react";
import { Check, ChevronDown } from "lucide-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// hooks
import { useDropdownKeyDown } from "../hooks/use-dropdown-key-down";
import useOutsideClickDetector from "../hooks/use-outside-click-detector";
// helpers
import { cn } from "../../helpers";
// types

View file

@ -2,10 +2,11 @@ import React, { useRef, useState } from "react";
import { usePopper } from "react-popper";
import { Popover, Tab } from "@headlessui/react";
import EmojiPicker from "emoji-picker-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// helpers
import { cn } from "../../helpers";
// hooks
import useOutsideClickDetector from "../hooks/use-outside-click-detector";
import { LucideIconsList } from "./lucide-icons-list";
// helpers
import { EmojiIconPickerTypes, TABS_LIST, TCustomEmojiPicker } from "./emoji-icon-helper";

View file

@ -2,12 +2,13 @@ import React, { useRef, useState } from "react";
import { usePopper } from "react-popper";
import EmojiPicker from "emoji-picker-react";
import { Popover, Tab } from "@headlessui/react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// components
import { IconsList } from "./icons-list";
// helpers
import { cn } from "../../helpers";
// hooks
import useOutsideClickDetector from "../hooks/use-outside-click-detector";
import { EmojiIconPickerTypes, TABS_LIST, TCustomEmojiPicker } from "./emoji-icon-helper";
export const CustomEmojiIconPicker: React.FC<TCustomEmojiPicker> = (props) => {

View file

@ -1,42 +0,0 @@
import React, { useEffect } from "react";
// TODO: move it to helpers package
const useOutsideClickDetector = (ref: React.RefObject<HTMLElement>, callback: () => void, useCapture = false) => {
const handleClick = (event: MouseEvent) => {
if (ref.current && !ref.current.contains(event.target as Node)) {
// get all the element with attribute name data-prevent-outside-click
const preventOutsideClickElements = document.querySelectorAll("[data-prevent-outside-click]");
// check if the click target is any of the elements with attribute name data-prevent-outside-click
for (let i = 0; i < preventOutsideClickElements.length; i++) {
if (preventOutsideClickElements[i].contains(event.target as Node)) {
// if the click target is any of the elements with attribute name data-prevent-outside-click, return
return;
}
}
// get all the element with attribute name data-delay-outside-click
const delayOutsideClickElements = document.querySelectorAll("[data-delay-outside-click]");
// check if the click target is any of the elements with attribute name data-delay-outside-click
for (let i = 0; i < delayOutsideClickElements.length; i++) {
if (delayOutsideClickElements[i].contains(event.target as Node)) {
// if the click target is any of the elements with attribute name data-delay-outside-click, delay the callback
setTimeout(() => {
callback();
}, 1);
return;
}
}
// else, call the callback immediately
callback();
}
};
useEffect(() => {
document.addEventListener("mousedown", handleClick, useCapture);
return () => {
document.removeEventListener("mousedown", handleClick, useCapture);
};
});
};
export default useOutsideClickDetector;