[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
53 changed files with 148 additions and 198 deletions

View File

@@ -2,11 +2,12 @@
import { FC, useEffect, useRef } from "react";
import { observer } from "mobx-react";
// hooks
import { HelpSection, SidebarMenu, SidebarDropdown } from "@/components/admin-sidebar";
import { useTheme } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// components
import { HelpSection, SidebarMenu, SidebarDropdown } from "@/components/admin-sidebar";
// hooks
import { useTheme } from "@/hooks/store";
export interface IInstanceSidebar {}

View File

@@ -1,21 +0,0 @@
"use client";
import React, { useEffect } from "react";
const useOutsideClickDetector = (ref: React.RefObject<HTMLElement>, callback: () => void) => {
const handleClick = (event: MouseEvent) => {
if (ref.current && !ref.current.contains(event.target as Node)) {
callback();
}
};
useEffect(() => {
document.addEventListener("mousedown", handleClick);
return () => {
document.removeEventListener("mousedown", handleClick);
};
});
};
export default useOutsideClickDetector;

2
admin/next-env.d.ts vendored
View File

@@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.

View File

@@ -15,6 +15,7 @@
"@plane/types": "*",
"@plane/ui": "*",
"@plane/constants": "*",
"@plane/helpers": "*",
"@tailwindcss/typography": "^0.5.9",
"@types/lodash": "^4.17.0",
"autoprefixer": "10.4.14",

View File

@@ -14,7 +14,8 @@
"packages/tsconfig",
"packages/ui",
"packages/types",
"packages/constants"
"packages/constants",
"packages/helpers"
],
"scripts": {
"build": "turbo run build",

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;

View File

@@ -1,21 +0,0 @@
"use client";
import { useEffect } from "react";
const useOutSideClick = (ref: any, callback: any) => {
const handleClick = (e: any) => {
if (ref.current && !ref.current.contains(e.target)) {
callback();
}
};
useEffect(() => {
document.addEventListener("click", handleClick);
return () => {
document.removeEventListener("click", handleClick);
};
});
};
export default useOutSideClick;

View File

@@ -1,5 +1,7 @@
import { FC, useEffect, useRef } from "react";
import { observer } from "mobx-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// components
import {
SidebarDropdown,
@@ -14,7 +16,6 @@ import { SidebarFavoritesMenu } from "@/components/workspace/sidebar/favorites/f
import { cn } from "@/helpers/common.helper";
// hooks
import { useAppTheme, useUserPermissions } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
// plane web components
import useSize from "@/hooks/use-window-size";
import { SidebarAppSwitcher } from "@/plane-web/components/sidebar";

View File

@@ -6,6 +6,8 @@ import Link from "next/link";
import { usePathname } from "next/navigation";
// icons
import { ChevronLeft, LogOut, MoveLeft, Plus, UserPlus } from "lucide-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// ui
import { TOAST_TYPE, Tooltip, setToast } from "@plane/ui";
// components
@@ -16,7 +18,6 @@ import { PROFILE_ACTION_LINKS } from "@/constants/profile";
import { cn } from "@/helpers/common.helper";
// hooks
import { useAppTheme, useUser, useUserSettings, useWorkspace } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { usePlatformOS } from "@/hooks/use-platform-os";
const WORKSPACE_ACTION_LINKS = [

View File

@@ -1,6 +1,8 @@
import { FC, useEffect, useRef } from "react";
import { observer } from "mobx-react";
import { UseFormRegister, UseFormSetFocus } from "react-hook-form";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// types
import { TIssue } from "@plane/types";
// components
@@ -17,7 +19,6 @@ import { EIssueLayoutTypes } from "@/constants/issue";
// hooks
import { useProject } from "@/hooks/store";
import useKeypress from "@/hooks/use-keypress";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
export type TQuickAddIssueFormRoot = {
isOpen: boolean;

View File

@@ -9,6 +9,8 @@ import { Control, Controller } from "react-hook-form";
import useSWR from "swr";
// headless ui
import { Tab, Popover } from "@headlessui/react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// ui
import { Button, Input, Loader } from "@plane/ui";
// constants
@@ -16,7 +18,6 @@ import { MAX_FILE_SIZE } from "@/constants/common";
// hooks
import { useWorkspace, useInstance } from "@/hooks/store";
import { useDropdownKeyDown } from "@/hooks/use-dropdown-key-down";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
// services
import { FileService } from "@/services/file.service";

View File

@@ -3,6 +3,8 @@ import { observer } from "mobx-react";
import { useParams } from "next/navigation";
// icons
import { ListFilter, Search, X } from "lucide-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// types
import type { TCycleFilters } from "@plane/types";
// components
@@ -14,7 +16,6 @@ import { cn } from "@/helpers/common.helper";
import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks
import { useCycleFilter } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
export const ArchivedCyclesHeader: FC = observer(() => {
// router

View File

@@ -2,6 +2,8 @@ import { useCallback, useEffect, useRef, useState } from "react";
import { observer } from "mobx-react";
// icons
import { ListFilter, Search, X } from "lucide-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// types
import { TCycleFilters } from "@plane/types";
// components
@@ -12,7 +14,6 @@ import { cn } from "@/helpers/common.helper";
import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks
import { useCycleFilter } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
type Props = {
projectId: string;

View File

@@ -5,9 +5,9 @@ import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
import { attachInstruction, extractInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item";
import { observer } from "mobx-react";
import { useOutsideClickDetector } from "@plane/helpers";
import { DropIndicator, TOAST_TYPE, setToast } from "@plane/ui";
import { HIGHLIGHT_WITH_LINE, highlightIssueOnDrop } from "@/components/issues/issue-layouts/utils";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
type Props = {
id: string;

View File

@@ -2,10 +2,11 @@ import React, { useEffect, useRef, useState } from "react";
import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
import { draggable } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
import { observer } from "mobx-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// components
import { CalendarIssueBlock } from "@/components/issues";
import { useIssueDetail } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { TRenderQuickActions } from "../list/list-view-types";
import { HIGHLIGHT_CLASS } from "../utils";
// types

View File

@@ -5,6 +5,8 @@ import { useState, useRef, forwardRef } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { MoreHorizontal } from "lucide-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// types
import { TIssue } from "@plane/types";
// ui
@@ -15,7 +17,6 @@ import { cn } from "@/helpers/common.helper";
import { useIssueDetail, useIssues, useProjectState } from "@/hooks/store";
import { useIssueStoreType } from "@/hooks/use-issue-layout-store";
import useIssuePeekOverviewRedirection from "@/hooks/use-issue-peek-overview-redirection";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues/issue-details";

View File

@@ -96,6 +96,7 @@ export const IssueGanttSidebarBlock: React.FC<Props> = observer((props) => {
return (
<ControlLink
id={`issue-${issueId}`}
href={`/${workspaceSlug}/projects/${issueDetails?.project_id}/issues/${issueDetails?.id}`}
onClick={handleIssuePeekOverview}
className="line-clamp-1 w-full cursor-pointer text-sm text-custom-text-100"

View File

@@ -5,6 +5,8 @@ import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// types
import { TIssue, IIssueDisplayProperties, IIssueMap } from "@plane/types";
// ui
@@ -17,7 +19,6 @@ import { cn } from "@/helpers/common.helper";
// hooks
import { useIssueDetail, useKanbanView } from "@/hooks/store";
import useIssuePeekOverviewRedirection from "@/hooks/use-issue-peek-overview-redirection";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";
@@ -187,6 +188,7 @@ export const KanbanIssueBlock: React.FC<IssueBlockProps> = observer((props) => {
<>
<DropIndicator isVisible={!isCurrentBlockDragging && isDraggingOverBlock} />
<div
id={`issue-${issueId}`}
// make Z-index higher at the beginning of drag, to have a issue drag image of issue block without any overlaps
className={cn("group/kanban-block relative mb-2", { "z-[1]": isCurrentBlockDragging })}
onDragStart={() => {

View File

@@ -5,6 +5,8 @@ import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
import { attachInstruction, extractInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item";
import { observer } from "mobx-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// types
import { IIssueDisplayProperties, TIssue, TIssueMap } from "@plane/types";
// components
@@ -14,7 +16,6 @@ import { IssueBlock } from "@/components/issues/issue-layouts/list";
// hooks
import { useIssueDetail } from "@/hooks/store";
import { TSelectionHelper } from "@/hooks/use-multiple-select";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
// types
import { HIGHLIGHT_CLASS, getIssueBlockId, isIssueNew } from "../utils";
import { TRenderQuickActions } from "./list-view-types";

View File

@@ -7,6 +7,8 @@ import { useParams } from "next/navigation";
import { usePopper } from "react-popper";
import { Check, ChevronDown, Search, Tags } from "lucide-react";
import { Combobox } from "@headlessui/react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// types
import { IIssueLabel } from "@plane/types";
// ui
@@ -14,7 +16,6 @@ import { ComboDropDown, Tooltip } from "@plane/ui";
// hooks
import { useLabel } from "@/hooks/store";
import { useDropdownKeyDown } from "@/hooks/use-dropdown-key-down";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { usePlatformOS } from "@/hooks/use-platform-os";
export interface IIssuePropertyLabels {

View File

@@ -4,6 +4,8 @@ import { Dispatch, MouseEvent, MutableRefObject, SetStateAction, useRef, useStat
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { ChevronRight, MoreHorizontal } from "lucide-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// types
import { IIssueDisplayProperties, TIssue } from "@plane/types";
// ui
@@ -19,7 +21,6 @@ import { cn } from "@/helpers/common.helper";
import { useIssueDetail, useProject } from "@/hooks/store";
import useIssuePeekOverviewRedirection from "@/hooks/use-issue-peek-overview-redirection";
import { TSelectionHelper } from "@/hooks/use-multiple-select";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { IssueIdentifier } from "@/plane-web/components/issues";

View File

@@ -4,6 +4,8 @@ import { useParams } from "next/navigation";
import { usePopper } from "react-popper";
import { Check, Component, Plus, Search, Tag } from "lucide-react";
import { Combobox } from "@headlessui/react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// components
import { IssueLabelsList } from "@/components/ui";
// helpers
@@ -11,7 +13,6 @@ import { cn } from "@/helpers/common.helper";
// hooks
import { useLabel } from "@/hooks/store";
import { useDropdownKeyDown } from "@/hooks/use-dropdown-key-down";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { usePlatformOS } from "@/hooks/use-platform-os";
type Props = {

View File

@@ -2,14 +2,14 @@
import { MutableRefObject, useRef, useState } from "react";
import { LucideIcon, X } from "lucide-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// types
import { IIssueLabel } from "@plane/types";
// ui
import { CustomMenu, DragHandle } from "@plane/ui";
// helpers
import { cn } from "@/helpers/common.helper";
// hooks
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
// components
import { LabelName } from "./label-name";

View File

@@ -3,6 +3,8 @@ import { observer } from "mobx-react";
import { useParams } from "next/navigation";
// icons
import { ListFilter, Search, X } from "lucide-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// types
import type { TModuleFilters } from "@plane/types";
// components
@@ -14,7 +16,6 @@ import { cn } from "@/helpers/common.helper";
import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks
import { useMember, useModuleFilter } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
export const ArchivedModulesHeader: FC = observer(() => {
// router

View File

@@ -5,8 +5,10 @@ import { observer } from "mobx-react";
import { useParams } from "next/navigation";
// icons
import { ListFilter, Search, X } from "lucide-react";
// helpers
// editor
import { cn } from "@plane/editor";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// types
import { TModuleFilters } from "@plane/types";
// ui
@@ -20,7 +22,6 @@ import { MODULE_VIEW_LAYOUTS } from "@/constants/module";
import { calculateTotalFilters } from "@/helpers/filter.helper";
// hooks
import { useMember, useModuleFilter } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { usePlatformOS } from "@/hooks/use-platform-os";
export const ModuleViewHeader: FC = observer(() => {

View File

@@ -1,9 +1,9 @@
import { FC, useState, useRef, useEffect } from "react";
import { Search, X } from "lucide-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// helpers
import { cn } from "@/helpers/common.helper";
// hooks
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
type Props = {
searchQuery: string;

View File

@@ -8,26 +8,23 @@ import { useParams } from "next/navigation";
import { ChevronDown, Pencil } from "lucide-react";
// headless ui
import { Disclosure, Transition } from "@headlessui/react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// types
import { IUserProfileProjectSegregation } from "@plane/types";
// plane ui
import { Loader, Tooltip } from "@plane/ui";
// components
import { Logo } from "@/components/common";
// fetch-keys
// helpers
import { cn } from "@/helpers/common.helper";
import { renderFormattedDate } from "@/helpers/date-time.helper";
// hooks
import { useAppTheme, useProject, useUser } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { usePlatformOS } from "@/hooks/use-platform-os";
// services
// components
import { ProfileSidebarTime } from "./time";
// services
type TProfileSidebar = {
userProjectsData: IUserProfileProjectSegregation | undefined;
className?: string;

View File

@@ -4,6 +4,8 @@ import { useEffect, useRef, useState } from "react";
import { observer } from "mobx-react";
import { usePathname } from "next/navigation";
import { Search, Briefcase, X } from "lucide-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// ui
import { Breadcrumbs, Button, Header } from "@plane/ui";
// components
@@ -12,7 +14,6 @@ import { BreadcrumbLink } from "@/components/common";
import { cn } from "@/helpers/common.helper";
// hooks
import { useCommandPalette, useEventTracker, useProjectFilter, useUserPermissions } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
import HeaderFilters from "./filters";

View File

@@ -2,11 +2,12 @@ import React, { useEffect, useRef, useState } from "react";
import { observer } from "mobx-react";
// icons
import { ListFilter, Search, X } from "lucide-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// helpers
import { cn } from "@/helpers/common.helper";
// hooks
import { useMember, useProjectView } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { FiltersDropdown } from "../issues";
import { ViewFiltersSelection } from "./filters/filter-selection";
import { ViewOrderByDropdown } from "./filters/order-by";

View File

@@ -9,16 +9,16 @@ import uniqBy from "lodash/uniqBy";
import { useParams } from "next/navigation";
import { PenSquare, Star, MoreHorizontal, ChevronRight, GripVertical } from "lucide-react";
import { Disclosure, Transition } from "@headlessui/react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// ui
import { IFavorite } from "@plane/types";
import { CustomMenu, Tooltip, DropIndicator, setToast, TOAST_TYPE, FavoriteFolderIcon, DragHandle } from "@plane/ui";
// helpers
import { cn } from "@/helpers/common.helper";
// hooks
import { useAppTheme } from "@/hooks/store";
import { useFavorite } from "@/hooks/store/use-favorite";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { usePlatformOS } from "@/hooks/use-platform-os";
// constants
import { FavoriteRoot } from "./favorite-items";

View File

@@ -4,6 +4,8 @@ import React, { FC, useEffect, useRef, useState } from "react";
import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
import { observer } from "mobx-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// ui
import { IFavorite } from "@plane/types";
// components
@@ -16,7 +18,6 @@ import {
// hooks
import { useAppTheme } from "@/hooks/store";
import { useFavoriteItemDetails } from "@/hooks/use-favorite-item-details";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
type Props = {
workspaceSlug: string;

View File

@@ -2,9 +2,12 @@ import { useEffect, useRef } from "react";
import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { Controller, SubmitHandler, useForm } from "react-hook-form";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// plane ui
import { FavoriteFolderIcon, Input, setToast, TOAST_TYPE } from "@plane/ui";
// hooks
import { useFavorite } from "@/hooks/store/use-favorite";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
type TForm = {
name: string;

View File

@@ -23,6 +23,8 @@ import {
Layers,
} from "lucide-react";
import { Disclosure, Transition } from "@headlessui/react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// ui
import {
CustomMenu,
@@ -45,7 +47,6 @@ import { SidebarNavItem } from "@/components/sidebar";
import { cn } from "@/helpers/common.helper";
// hooks
import { useAppTheme, useEventTracker, useProject, useUserPermissions } from "@/hooks/store";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { usePlatformOS } from "@/hooks/use-platform-os";
// constants
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";

View File

@@ -6,6 +6,8 @@ import Link from "next/link";
import { useParams, usePathname } from "next/navigation";
import { ArchiveIcon, ChevronRight, MoreHorizontal, Settings } from "lucide-react";
import { Disclosure, Transition } from "@headlessui/react";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
// ui
import { CustomMenu, Tooltip } from "@plane/ui";
// components
@@ -18,7 +20,6 @@ import { cn } from "@/helpers/common.helper";
// hooks
import { useAppTheme, useEventTracker, useUserPermissions } from "@/hooks/store";
import useLocalStorage from "@/hooks/use-local-storage";
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
import { usePlatformOS } from "@/hooks/use-platform-os";
// plane web components
import { UpgradeBadge } from "@/plane-web/components/workspace";

View File

@@ -1,7 +1,8 @@
import { useEffect } from "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";
import { usePlatformOS } from "./use-platform-os";
type TArguments = {

View File

@@ -1,7 +1,6 @@
import React, { useCallback, useEffect } from "react";
// hook
import useOutsideClickDetector from "./use-outside-click-detector";
// plane helpers
import { useOutsideClickDetector } from "@plane/helpers";
/**
* Custom hook for dynamic dropdown position calculation.

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) => {
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);
return () => {
document.removeEventListener("mousedown", handleClick);
};
});
};
export default useOutsideClickDetector;

View File

@@ -7,14 +7,13 @@ const usePeekOverviewOutsideClickDetector = (
) => {
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;
}
// 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;
}
// check if the click target is the current issue element or its children
let targetElement = event.target as HTMLElement | null;
@@ -25,17 +24,13 @@ const usePeekOverviewOutsideClickDetector = (
}
targetElement = targetElement.parentElement;
}
// get all the element with attribute name data-prevent-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;
}
const delayOutsideClickElement = (event.target as HTMLElement | undefined)?.closest("[data-delay-outside-click]");
if (delayOutsideClickElement) {
// if the click target is the closest element with attribute name data-delay-outside-click, delay the callback
setTimeout(() => {
callback();
}, 0);
return;
}
// else, call the callback immediately
callback();

View File

@@ -3,6 +3,7 @@ import set from "lodash/set";
import { action, makeObservable, observable, runInAction, computed } from "mobx";
// types
import { IUser } from "@plane/types";
import { TUserPermissions } from "@plane/types/src/enums";
// constants
// helpers
import { API_BASE_URL } from "@/helpers/common.helper";
@@ -16,7 +17,6 @@ import { IAccountStore } from "@/store/user/account.store";
import { ProfileStore, IUserProfileStore } from "@/store/user/profile.store";
import { IUserPermissionStore, UserPermissionStore } from "./permissions.store";
import { IUserSettingsStore, UserSettingsStore } from "./settings.store";
import { TUserPermissions } from "@plane/types/src/enums";
type TUserErrorStatus = {
status: string;

View File

@@ -27,6 +27,7 @@
"@nivo/scatterplot": "0.80.0",
"@plane/constants": "*",
"@plane/editor": "*",
"@plane/helpers": "*",
"@plane/types": "*",
"@plane/ui": "*",
"@popperjs/core": "^2.11.8",