mirror of
https://github.com/makeplane/plane
synced 2025-08-07 19:59:33 +00:00
[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:
@@ -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 {}
|
||||
|
||||
|
||||
@@ -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
2
admin/next-env.d.ts
vendored
@@ -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.
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
"packages/tsconfig",
|
||||
"packages/ui",
|
||||
"packages/types",
|
||||
"packages/constants"
|
||||
"packages/constants",
|
||||
"packages/helpers"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "turbo run build",
|
||||
|
||||
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;
|
||||
@@ -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;
|
||||
@@ -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";
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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={() => {
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"@nivo/scatterplot": "0.80.0",
|
||||
"@plane/constants": "*",
|
||||
"@plane/editor": "*",
|
||||
"@plane/helpers": "*",
|
||||
"@plane/types": "*",
|
||||
"@plane/ui": "*",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
|
||||
Reference in New Issue
Block a user