[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:
parent
441385fc95
commit
b2533b94ce
53 changed files with 148 additions and 198 deletions
1
packages/helpers/hooks/index.ts
Normal file
1
packages/helpers/hooks/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./use-outside-click-detector";
|
||||
29
packages/helpers/hooks/use-outside-click-detector.tsx
Normal file
29
packages/helpers/hooks/use-outside-click-detector.tsx
Normal 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);
|
||||
};
|
||||
});
|
||||
};
|
||||
1
packages/helpers/index.ts
Normal file
1
packages/helpers/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./hooks";
|
||||
15
packages/helpers/package.json
Normal file
15
packages/helpers/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
Loading…
Add table
Add a link
Reference in a new issue