mirror of
https://github.com/makeplane/plane.git
synced 2025-12-23 15:19:37 +01:00
[WEB-2316] chore: Render Tooltips and Drop downs in certain places on hover hover to improve rendering performance (#5456)
* render tooltips and dropdowns in certain places post hover to improve performance * fix useEffect hooks
This commit is contained in:
73
packages/ui/src/dropdowns/combo-box.tsx
Normal file
73
packages/ui/src/dropdowns/combo-box.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import { Combobox } from "@headlessui/react";
|
||||
import React, {
|
||||
ElementType,
|
||||
Fragment,
|
||||
KeyboardEventHandler,
|
||||
ReactNode,
|
||||
Ref,
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
|
||||
type Props = {
|
||||
as?: ElementType | undefined;
|
||||
ref?: Ref<HTMLElement> | undefined;
|
||||
tabIndex?: number | undefined;
|
||||
className?: string | undefined;
|
||||
value?: string | string[] | null;
|
||||
onChange?: (value: any) => void;
|
||||
disabled?: boolean | undefined;
|
||||
onKeyDown?: KeyboardEventHandler<HTMLDivElement> | undefined;
|
||||
multiple?: boolean;
|
||||
renderByDefault?: boolean;
|
||||
button: ReactNode;
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
const ComboDropDown = forwardRef((props: Props, ref) => {
|
||||
const { button, renderByDefault = true, children, ...rest } = props;
|
||||
|
||||
const dropDownButtonRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const [shouldRender, setShouldRender] = useState(renderByDefault);
|
||||
|
||||
const onHover = () => {
|
||||
setShouldRender(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const element = dropDownButtonRef.current;
|
||||
|
||||
if (!element) return;
|
||||
|
||||
element.addEventListener("mouseenter", onHover);
|
||||
|
||||
return () => {
|
||||
element?.removeEventListener("mouseenter", onHover);
|
||||
};
|
||||
}, [dropDownButtonRef, shouldRender]);
|
||||
|
||||
if (!shouldRender) {
|
||||
return (
|
||||
<div ref={dropDownButtonRef} className="h-full flex items-center">
|
||||
{button}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
//@ts-ignore
|
||||
<Combobox {...rest} ref={ref}>
|
||||
<Combobox.Button as={Fragment}>{button}</Combobox.Button>
|
||||
{children}
|
||||
</Combobox>
|
||||
);
|
||||
});
|
||||
|
||||
const ComboOptions = Combobox.Options;
|
||||
const ComboOption = Combobox.Option;
|
||||
const ComboInput = Combobox.Input;
|
||||
|
||||
export { ComboDropDown, ComboOptions, ComboOption, ComboInput };
|
||||
@@ -2,3 +2,4 @@ export * from "./context-menu";
|
||||
export * from "./custom-menu";
|
||||
export * from "./custom-select";
|
||||
export * from "./custom-search-select";
|
||||
export * from "./combo-box";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Tooltip2 } from "@blueprintjs/popover2";
|
||||
// helpers
|
||||
import { cn } from "../../helpers";
|
||||
@@ -42,7 +42,36 @@ export const Tooltip: React.FC<ITooltipProps> = ({
|
||||
openDelay = 200,
|
||||
closeDelay,
|
||||
isMobile = false,
|
||||
}) => (
|
||||
}) => {
|
||||
const toolTipRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const [shouldRender, setShouldRender] = useState(false);
|
||||
|
||||
const onHover = () => {
|
||||
setShouldRender(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const element = toolTipRef.current;
|
||||
|
||||
if (!element) return;
|
||||
|
||||
element.addEventListener("mouseenter", onHover);
|
||||
|
||||
return () => {
|
||||
element?.removeEventListener("mouseenter", onHover);
|
||||
};
|
||||
}, [toolTipRef, shouldRender]);
|
||||
|
||||
if (!shouldRender) {
|
||||
return (
|
||||
<div ref={toolTipRef} className="h-full flex items-center">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip2
|
||||
disabled={disabled}
|
||||
hoverOpenDelay={openDelay}
|
||||
@@ -76,3 +105,4 @@ export const Tooltip: React.FC<ITooltipProps> = ({
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { Fragment, ReactNode, useRef, useState } from "react";
|
||||
import { ReactNode, useRef, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { ChevronDown } from "lucide-react";
|
||||
import { Combobox } from "@headlessui/react";
|
||||
// ui
|
||||
import { ContrastIcon } from "@plane/ui";
|
||||
import { ComboDropDown, ContrastIcon } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
@@ -26,6 +25,7 @@ type Props = TDropdownProps & {
|
||||
projectId: string | undefined;
|
||||
value: string | null;
|
||||
canRemoveCycle?: boolean;
|
||||
renderByDefault?: boolean;
|
||||
};
|
||||
|
||||
export const CycleDropdown: React.FC<Props> = observer((props) => {
|
||||
@@ -48,6 +48,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
|
||||
tabIndex,
|
||||
value,
|
||||
canRemoveCycle = true,
|
||||
renderByDefault = true,
|
||||
} = props;
|
||||
// states
|
||||
|
||||
@@ -72,18 +73,8 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<Combobox
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn("h-full", className)}
|
||||
value={value}
|
||||
onChange={dropdownOnChange}
|
||||
disabled={disabled}
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
<Combobox.Button as={Fragment}>
|
||||
const comboButton = (
|
||||
<>
|
||||
{button ? (
|
||||
<button
|
||||
ref={setReferenceElement}
|
||||
@@ -128,7 +119,22 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
|
||||
</DropdownButton>
|
||||
</button>
|
||||
)}
|
||||
</Combobox.Button>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<ComboDropDown
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn("h-full", className)}
|
||||
value={value}
|
||||
onChange={dropdownOnChange}
|
||||
disabled={disabled}
|
||||
onKeyDown={handleKeyDown}
|
||||
button={comboButton}
|
||||
renderByDefault={renderByDefault}
|
||||
>
|
||||
{isOpen && projectId && (
|
||||
<CycleOptions
|
||||
isOpen={isOpen}
|
||||
@@ -138,6 +144,6 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
|
||||
canRemoveCycle={canRemoveCycle}
|
||||
/>
|
||||
)}
|
||||
</Combobox>
|
||||
</ComboDropDown>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ import { usePopper } from "react-popper";
|
||||
import { ArrowRight, CalendarDays } from "lucide-react";
|
||||
import { Combobox } from "@headlessui/react";
|
||||
// ui
|
||||
import { Button } from "@plane/ui";
|
||||
import { Button, ComboDropDown } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
import { renderFormattedDate } from "@/helpers/date-time.helper";
|
||||
@@ -49,6 +49,7 @@ type Props = {
|
||||
from: Date | undefined;
|
||||
to: Date | undefined;
|
||||
};
|
||||
renderByDefault?: boolean;
|
||||
};
|
||||
|
||||
export const DateRangeDropdown: React.FC<Props> = (props) => {
|
||||
@@ -80,6 +81,7 @@ export const DateRangeDropdown: React.FC<Props> = (props) => {
|
||||
showTooltip = false,
|
||||
tabIndex,
|
||||
value,
|
||||
renderByDefault = true,
|
||||
} = props;
|
||||
// states
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
@@ -131,20 +133,7 @@ export const DateRangeDropdown: React.FC<Props> = (props) => {
|
||||
setDateRange(value);
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<Combobox
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn("h-full", className)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
if (!isOpen) handleKeyDown(e);
|
||||
} else handleKeyDown(e);
|
||||
}}
|
||||
disabled={disabled}
|
||||
>
|
||||
<Combobox.Button as={React.Fragment}>
|
||||
const comboButton = (
|
||||
<button
|
||||
ref={setReferenceElement}
|
||||
type="button"
|
||||
@@ -173,27 +162,37 @@ export const DateRangeDropdown: React.FC<Props> = (props) => {
|
||||
variant={buttonVariant}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
"h-full flex items-center justify-center gap-1 rounded-sm flex-grow",
|
||||
buttonFromDateClassName
|
||||
)}
|
||||
className={cn("h-full flex items-center justify-center gap-1 rounded-sm flex-grow", buttonFromDateClassName)}
|
||||
>
|
||||
{!hideIcon.from && icon}
|
||||
{dateRange.from ? renderFormattedDate(dateRange.from) : placeholder.from}
|
||||
</span>
|
||||
<ArrowRight className="h-3 w-3 flex-shrink-0" />
|
||||
<span
|
||||
className={cn(
|
||||
"h-full flex items-center justify-center gap-1 rounded-sm flex-grow",
|
||||
buttonToDateClassName
|
||||
)}
|
||||
className={cn("h-full flex items-center justify-center gap-1 rounded-sm flex-grow", buttonToDateClassName)}
|
||||
>
|
||||
{!hideIcon.to && icon}
|
||||
{dateRange.to ? renderFormattedDate(dateRange.to) : placeholder.to}
|
||||
</span>
|
||||
</DropdownButton>
|
||||
</button>
|
||||
</Combobox.Button>
|
||||
);
|
||||
|
||||
return (
|
||||
<ComboDropDown
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn("h-full", className)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
if (!isOpen) handleKeyDown(e);
|
||||
} else handleKeyDown(e);
|
||||
}}
|
||||
button={comboButton}
|
||||
disabled={disabled}
|
||||
renderByDefault={renderByDefault}
|
||||
>
|
||||
{isOpen && (
|
||||
<Combobox.Options className="fixed z-10" static>
|
||||
<div
|
||||
@@ -250,6 +249,6 @@ export const DateRangeDropdown: React.FC<Props> = (props) => {
|
||||
</div>
|
||||
</Combobox.Options>
|
||||
)}
|
||||
</Combobox>
|
||||
</ComboDropDown>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,6 +4,8 @@ import { createPortal } from "react-dom";
|
||||
import { usePopper } from "react-popper";
|
||||
import { CalendarDays, X } from "lucide-react";
|
||||
import { Combobox } from "@headlessui/react";
|
||||
// ui
|
||||
import { ComboDropDown } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
import { renderFormattedDate, getDate } from "@/helpers/date-time.helper";
|
||||
@@ -27,6 +29,7 @@ type Props = TDropdownProps & {
|
||||
value: Date | string | null;
|
||||
closeOnSelect?: boolean;
|
||||
formatToken?: string;
|
||||
renderByDefault?: boolean;
|
||||
};
|
||||
|
||||
export const DateDropdown: React.FC<Props> = (props) => {
|
||||
@@ -51,6 +54,7 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
||||
tabIndex,
|
||||
value,
|
||||
formatToken,
|
||||
renderByDefault = true,
|
||||
} = props;
|
||||
// states
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
@@ -98,20 +102,7 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
||||
if (minDate) disabledDays.push({ before: minDate });
|
||||
if (maxDate) disabledDays.push({ after: maxDate });
|
||||
|
||||
return (
|
||||
<Combobox
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn("h-full", className)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
if (!isOpen) handleKeyDown(e);
|
||||
} else handleKeyDown(e);
|
||||
}}
|
||||
disabled={disabled}
|
||||
>
|
||||
<Combobox.Button as={React.Fragment}>
|
||||
const comboButton = (
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
@@ -135,9 +126,7 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
||||
>
|
||||
{!hideIcon && icon}
|
||||
{BUTTON_VARIANTS_WITH_TEXT.includes(buttonVariant) && (
|
||||
<span className="flex-grow truncate">
|
||||
{value ? renderFormattedDate(value, formatToken) : placeholder}
|
||||
</span>
|
||||
<span className="flex-grow truncate">{value ? renderFormattedDate(value, formatToken) : placeholder}</span>
|
||||
)}
|
||||
{isClearable && !disabled && isDateSelected && (
|
||||
<X
|
||||
@@ -151,7 +140,23 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
||||
)}
|
||||
</DropdownButton>
|
||||
</button>
|
||||
</Combobox.Button>
|
||||
);
|
||||
|
||||
return (
|
||||
<ComboDropDown
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn("h-full", className)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
if (!isOpen) handleKeyDown(e);
|
||||
} else handleKeyDown(e);
|
||||
}}
|
||||
button={comboButton}
|
||||
disabled={disabled}
|
||||
renderByDefault={renderByDefault}
|
||||
>
|
||||
{isOpen &&
|
||||
createPortal(
|
||||
<Combobox.Options data-prevent-outside-click static>
|
||||
@@ -176,6 +181,6 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
||||
</Combobox.Options>,
|
||||
document.body
|
||||
)}
|
||||
</Combobox>
|
||||
</ComboDropDown>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Fragment, ReactNode, useRef, useState } from "react";
|
||||
import { ReactNode, useRef, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import { usePopper } from "react-popper";
|
||||
import { Check, ChevronDown, Search, Triangle } from "lucide-react";
|
||||
import { Combobox } from "@headlessui/react";
|
||||
// ui
|
||||
import { ComboDropDown } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
@@ -27,6 +29,7 @@ type Props = TDropdownProps & {
|
||||
onClose?: () => void;
|
||||
projectId: string | undefined;
|
||||
value: string | undefined | null;
|
||||
renderByDefault?: boolean;
|
||||
};
|
||||
|
||||
type DropdownOptions =
|
||||
@@ -56,6 +59,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
||||
showTooltip = false,
|
||||
tabIndex,
|
||||
value,
|
||||
renderByDefault = true,
|
||||
} = props;
|
||||
// states
|
||||
const [query, setQuery] = useState("");
|
||||
@@ -142,18 +146,8 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<Combobox
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn("h-full w-full", className)}
|
||||
value={value}
|
||||
onChange={dropdownOnChange}
|
||||
disabled={disabled}
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
<Combobox.Button as={Fragment}>
|
||||
const comboButton = (
|
||||
<>
|
||||
{button ? (
|
||||
<button
|
||||
ref={setReferenceElement}
|
||||
@@ -195,7 +189,22 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
||||
</DropdownButton>
|
||||
</button>
|
||||
)}
|
||||
</Combobox.Button>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<ComboDropDown
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn("h-full w-full", className)}
|
||||
value={value}
|
||||
onChange={dropdownOnChange}
|
||||
disabled={disabled}
|
||||
onKeyDown={handleKeyDown}
|
||||
button={comboButton}
|
||||
renderByDefault={renderByDefault}
|
||||
>
|
||||
{isOpen && (
|
||||
<Combobox.Options className="fixed z-10" static>
|
||||
<div
|
||||
@@ -263,6 +272,6 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
||||
</div>
|
||||
</Combobox.Options>
|
||||
)}
|
||||
</Combobox>
|
||||
</ComboDropDown>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Fragment, useRef, useState } from "react";
|
||||
import { useRef, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { ChevronDown, LucideIcon } from "lucide-react";
|
||||
// headless ui
|
||||
import { Combobox } from "@headlessui/react";
|
||||
// ui
|
||||
import { ComboDropDown } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
@@ -21,6 +21,7 @@ type Props = {
|
||||
projectId?: string;
|
||||
icon?: LucideIcon;
|
||||
onClose?: () => void;
|
||||
renderByDefault?: boolean;
|
||||
} & MemberDropdownProps;
|
||||
|
||||
export const MemberDropdown: React.FC<Props> = observer((props) => {
|
||||
@@ -46,6 +47,7 @@ export const MemberDropdown: React.FC<Props> = observer((props) => {
|
||||
tabIndex,
|
||||
value,
|
||||
icon,
|
||||
renderByDefault = true,
|
||||
} = props;
|
||||
// states
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
@@ -96,17 +98,8 @@ export const MemberDropdown: React.FC<Props> = observer((props) => {
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Combobox
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn("h-full", className)}
|
||||
onChange={dropdownOnChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
{...comboboxProps}
|
||||
>
|
||||
<Combobox.Button as={Fragment}>
|
||||
const comboButton = (
|
||||
<>
|
||||
{button ? (
|
||||
<button
|
||||
ref={setReferenceElement}
|
||||
@@ -150,7 +143,21 @@ export const MemberDropdown: React.FC<Props> = observer((props) => {
|
||||
</DropdownButton>
|
||||
</button>
|
||||
)}
|
||||
</Combobox.Button>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<ComboDropDown
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn("h-full", className)}
|
||||
onChange={dropdownOnChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
button={comboButton}
|
||||
renderByDefault={renderByDefault}
|
||||
{...comboboxProps}
|
||||
>
|
||||
{isOpen && (
|
||||
<MemberOptions
|
||||
isOpen={isOpen}
|
||||
@@ -159,6 +166,6 @@ export const MemberDropdown: React.FC<Props> = observer((props) => {
|
||||
referenceElement={referenceElement}
|
||||
/>
|
||||
)}
|
||||
</Combobox>
|
||||
</ComboDropDown>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import { Fragment, ReactNode, useEffect, useRef, useState } from "react";
|
||||
import { ReactNode, useEffect, useRef, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { ChevronDown, X } from "lucide-react";
|
||||
import { Combobox } from "@headlessui/react";
|
||||
// ui
|
||||
import { DiceIcon, Tooltip } from "@plane/ui";
|
||||
import { ComboDropDown, DiceIcon, Tooltip } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
@@ -27,6 +26,7 @@ type Props = TDropdownProps & {
|
||||
projectId: string | undefined;
|
||||
showCount?: boolean;
|
||||
onClose?: () => void;
|
||||
renderByDefault?: boolean;
|
||||
} & (
|
||||
| {
|
||||
multiple: false;
|
||||
@@ -170,6 +170,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
|
||||
showTooltip = false,
|
||||
tabIndex,
|
||||
value,
|
||||
renderByDefault = true,
|
||||
} = props;
|
||||
// states
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
@@ -207,16 +208,8 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
return (
|
||||
<Combobox
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn("h-full", className)}
|
||||
onKeyDown={handleKeyDown}
|
||||
{...comboboxProps}
|
||||
>
|
||||
<Combobox.Button as={Fragment}>
|
||||
const comboButton = (
|
||||
<>
|
||||
{button ? (
|
||||
<button
|
||||
ref={setReferenceElement}
|
||||
@@ -273,7 +266,20 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
|
||||
</DropdownButton>
|
||||
</button>
|
||||
)}
|
||||
</Combobox.Button>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<ComboDropDown
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn("h-full", className)}
|
||||
onKeyDown={handleKeyDown}
|
||||
button={comboButton}
|
||||
renderByDefault={renderByDefault}
|
||||
{...comboboxProps}
|
||||
>
|
||||
{isOpen && projectId && (
|
||||
<ModuleOptions
|
||||
isOpen={isOpen}
|
||||
@@ -283,6 +289,6 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
|
||||
multiple={multiple}
|
||||
/>
|
||||
)}
|
||||
</Combobox>
|
||||
</ComboDropDown>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Combobox } from "@headlessui/react";
|
||||
// types
|
||||
import { TIssuePriorities } from "@plane/types";
|
||||
// ui
|
||||
import { PriorityIcon, Tooltip } from "@plane/ui";
|
||||
import { ComboDropDown, PriorityIcon, Tooltip } from "@plane/ui";
|
||||
// constants
|
||||
import { ISSUE_PRIORITIES } from "@/constants/issue";
|
||||
// helpers
|
||||
@@ -29,6 +29,7 @@ type Props = TDropdownProps & {
|
||||
onChange: (val: TIssuePriorities) => void;
|
||||
onClose?: () => void;
|
||||
value: TIssuePriorities | undefined | null;
|
||||
renderByDefault?: boolean;
|
||||
};
|
||||
|
||||
type ButtonProps = {
|
||||
@@ -305,6 +306,7 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
|
||||
showTooltip = false,
|
||||
tabIndex,
|
||||
value = "none",
|
||||
renderByDefault = true,
|
||||
} = props;
|
||||
// states
|
||||
const [query, setQuery] = useState("");
|
||||
@@ -366,24 +368,8 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
|
||||
? BackgroundButton
|
||||
: TransparentButton;
|
||||
|
||||
return (
|
||||
<Combobox
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn(
|
||||
"h-full",
|
||||
{
|
||||
"bg-custom-background-80": isOpen,
|
||||
},
|
||||
className
|
||||
)}
|
||||
value={value}
|
||||
onChange={dropdownOnChange}
|
||||
disabled={disabled}
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
<Combobox.Button as={Fragment}>
|
||||
const comboButton = (
|
||||
<>
|
||||
{button ? (
|
||||
<button
|
||||
ref={setReferenceElement}
|
||||
@@ -422,7 +408,28 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
|
||||
/>
|
||||
</button>
|
||||
)}
|
||||
</Combobox.Button>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<ComboDropDown
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn(
|
||||
"h-full",
|
||||
{
|
||||
"bg-custom-background-80": isOpen,
|
||||
},
|
||||
className
|
||||
)}
|
||||
value={value}
|
||||
onChange={dropdownOnChange}
|
||||
disabled={disabled}
|
||||
onKeyDown={handleKeyDown}
|
||||
button={comboButton}
|
||||
renderByDefault={renderByDefault}
|
||||
>
|
||||
{isOpen && (
|
||||
<Combobox.Options className="fixed z-10" static>
|
||||
<div
|
||||
@@ -471,6 +478,6 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
|
||||
</div>
|
||||
</Combobox.Options>
|
||||
)}
|
||||
</Combobox>
|
||||
</ComboDropDown>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -5,6 +5,8 @@ import { Check, ChevronDown, Search } from "lucide-react";
|
||||
import { Combobox } from "@headlessui/react";
|
||||
// types
|
||||
import { IProject } from "@plane/types";
|
||||
// ui
|
||||
import { ComboDropDown } from "@plane/ui";
|
||||
// components
|
||||
import { Logo } from "@/components/common";
|
||||
// helpers
|
||||
@@ -27,6 +29,7 @@ type Props = TDropdownProps & {
|
||||
onClose?: () => void;
|
||||
renderCondition?: (project: IProject) => boolean;
|
||||
value: string | null;
|
||||
renderByDefault?: boolean;
|
||||
};
|
||||
|
||||
export const ProjectDropdown: React.FC<Props> = observer((props) => {
|
||||
@@ -48,6 +51,7 @@ export const ProjectDropdown: React.FC<Props> = observer((props) => {
|
||||
showTooltip = false,
|
||||
tabIndex,
|
||||
value,
|
||||
renderByDefault = true,
|
||||
} = props;
|
||||
// states
|
||||
const [query, setQuery] = useState("");
|
||||
@@ -112,18 +116,8 @@ export const ProjectDropdown: React.FC<Props> = observer((props) => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<Combobox
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn("h-full", className)}
|
||||
value={value}
|
||||
onChange={dropdownOnChange}
|
||||
disabled={disabled}
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
<Combobox.Button as={Fragment}>
|
||||
const comboButton = (
|
||||
<>
|
||||
{button ? (
|
||||
<button
|
||||
ref={setReferenceElement}
|
||||
@@ -169,7 +163,22 @@ export const ProjectDropdown: React.FC<Props> = observer((props) => {
|
||||
</DropdownButton>
|
||||
</button>
|
||||
)}
|
||||
</Combobox.Button>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<ComboDropDown
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn("h-full", className)}
|
||||
value={value}
|
||||
onChange={dropdownOnChange}
|
||||
disabled={disabled}
|
||||
onKeyDown={handleKeyDown}
|
||||
button={comboButton}
|
||||
renderByDefault={renderByDefault}
|
||||
>
|
||||
{isOpen && (
|
||||
<Combobox.Options className="fixed z-10" static>
|
||||
<div
|
||||
@@ -225,6 +234,6 @@ export const ProjectDropdown: React.FC<Props> = observer((props) => {
|
||||
</div>
|
||||
</Combobox.Options>
|
||||
)}
|
||||
</Combobox>
|
||||
</ComboDropDown>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ import { usePopper } from "react-popper";
|
||||
import { Check, ChevronDown, Search } from "lucide-react";
|
||||
import { Combobox } from "@headlessui/react";
|
||||
// ui
|
||||
import { Spinner, StateGroupIcon } from "@plane/ui";
|
||||
import { ComboDropDown, Spinner, StateGroupIcon } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
@@ -29,6 +29,7 @@ type Props = TDropdownProps & {
|
||||
projectId: string | undefined;
|
||||
showDefaultState?: boolean;
|
||||
value: string | undefined | null;
|
||||
renderByDefault?: boolean;
|
||||
};
|
||||
|
||||
export const StateDropdown: React.FC<Props> = observer((props) => {
|
||||
@@ -50,6 +51,7 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
|
||||
showTooltip = false,
|
||||
tabIndex,
|
||||
value,
|
||||
renderByDefault = true,
|
||||
} = props;
|
||||
// states
|
||||
const [query, setQuery] = useState("");
|
||||
@@ -125,18 +127,8 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
|
||||
handleClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<Combobox
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn("h-full", className)}
|
||||
value={stateValue}
|
||||
onChange={dropdownOnChange}
|
||||
disabled={disabled}
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
<Combobox.Button as={Fragment}>
|
||||
const comboButton = (
|
||||
<>
|
||||
{button ? (
|
||||
<button
|
||||
ref={setReferenceElement}
|
||||
@@ -183,17 +175,29 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
|
||||
<span className="flex-grow truncate">{selectedState?.name ?? "State"}</span>
|
||||
)}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown
|
||||
className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</DropdownButton>
|
||||
</button>
|
||||
)}
|
||||
</Combobox.Button>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<ComboDropDown
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
tabIndex={tabIndex}
|
||||
className={cn("h-full", className)}
|
||||
value={stateValue}
|
||||
onChange={dropdownOnChange}
|
||||
disabled={disabled}
|
||||
onKeyDown={handleKeyDown}
|
||||
button={comboButton}
|
||||
renderByDefault={renderByDefault}
|
||||
>
|
||||
{isOpen && (
|
||||
<Combobox.Options className="fixed z-10" static>
|
||||
<div
|
||||
@@ -246,6 +250,6 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
|
||||
</div>
|
||||
</Combobox.Options>
|
||||
)}
|
||||
</Combobox>
|
||||
</ComboDropDown>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -284,6 +284,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
||||
projectId={issue.project_id}
|
||||
disabled={isReadOnly}
|
||||
buttonVariant="border-with-text"
|
||||
renderByDefault={isMobile}
|
||||
showTooltip
|
||||
/>
|
||||
</div>
|
||||
@@ -298,6 +299,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
||||
disabled={isReadOnly}
|
||||
buttonVariant="border-without-text"
|
||||
buttonClassName="border"
|
||||
renderByDefault={isMobile}
|
||||
showTooltip
|
||||
/>
|
||||
</div>
|
||||
@@ -312,6 +314,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
||||
defaultOptions={defaultLabelOptions}
|
||||
onChange={handleLabel}
|
||||
disabled={isReadOnly}
|
||||
renderByDefault={isMobile}
|
||||
hideDropdownArrow
|
||||
/>
|
||||
</div>
|
||||
@@ -328,6 +331,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
||||
icon={<CalendarClock className="h-3 w-3 flex-shrink-0" />}
|
||||
buttonVariant={issue.start_date ? "border-with-text" : "border-without-text"}
|
||||
disabled={isReadOnly}
|
||||
renderByDefault={isMobile}
|
||||
showTooltip
|
||||
/>
|
||||
</div>
|
||||
@@ -346,6 +350,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
||||
buttonClassName={shouldHighlightIssueDueDate(issue.target_date, stateDetails?.group) ? "text-red-500" : ""}
|
||||
clearIconClassName="!text-custom-text-100"
|
||||
disabled={isReadOnly}
|
||||
renderByDefault={isMobile}
|
||||
showTooltip
|
||||
/>
|
||||
</div>
|
||||
@@ -365,6 +370,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
||||
showTooltip={issue?.assignee_ids?.length === 0}
|
||||
placeholder="Assignees"
|
||||
tooltipContent=""
|
||||
renderByDefault={isMobile}
|
||||
/>
|
||||
</div>
|
||||
</WithDisplayPropertiesHOC>
|
||||
@@ -379,6 +385,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
||||
value={issue?.module_ids ?? []}
|
||||
onChange={handleModule}
|
||||
disabled={isReadOnly}
|
||||
renderByDefault={isMobile}
|
||||
multiple
|
||||
buttonVariant="border-with-text"
|
||||
showCount
|
||||
@@ -399,6 +406,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
||||
onChange={handleCycle}
|
||||
disabled={isReadOnly}
|
||||
buttonVariant="border-with-text"
|
||||
renderByDefault={isMobile}
|
||||
showTooltip
|
||||
/>
|
||||
</div>
|
||||
@@ -415,6 +423,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
||||
projectId={issue.project_id}
|
||||
disabled={isReadOnly}
|
||||
buttonVariant="border-with-text"
|
||||
renderByDefault={isMobile}
|
||||
showTooltip
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Combobox } from "@headlessui/react";
|
||||
// types
|
||||
import { IIssueLabel } from "@plane/types";
|
||||
// ui
|
||||
import { Tooltip } from "@plane/ui";
|
||||
import { ComboDropDown, Tooltip } from "@plane/ui";
|
||||
// hooks
|
||||
import { useLabel } from "@/hooks/store";
|
||||
import { useDropdownKeyDown } from "@/hooks/use-dropdown-key-down";
|
||||
@@ -32,6 +32,7 @@ export interface IIssuePropertyLabels {
|
||||
noLabelBorder?: boolean;
|
||||
placeholderText?: string;
|
||||
onClose?: () => void;
|
||||
renderByDefault?: boolean;
|
||||
}
|
||||
|
||||
export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((props) => {
|
||||
@@ -50,6 +51,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
|
||||
maxRender = 2,
|
||||
noLabelBorder = false,
|
||||
placeholderText,
|
||||
renderByDefault = true,
|
||||
} = props;
|
||||
// router
|
||||
const { workspaceSlug: routerWorkspaceSlug } = useParams();
|
||||
@@ -217,18 +219,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Combobox
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
className={`w-auto max-w-full flex-shrink-0 text-left ${className}`}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
onKeyDown={handleKeyDown}
|
||||
multiple
|
||||
>
|
||||
<Combobox.Button as={Fragment}>
|
||||
const comboButton = (
|
||||
<button
|
||||
ref={setReferenceElement}
|
||||
type="button"
|
||||
@@ -244,8 +235,21 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
|
||||
{label}
|
||||
{!hideDropdownArrow && !disabled && <ChevronDown className="h-3 w-3" aria-hidden="true" />}
|
||||
</button>
|
||||
</Combobox.Button>
|
||||
);
|
||||
|
||||
return (
|
||||
<ComboDropDown
|
||||
as="div"
|
||||
ref={dropdownRef}
|
||||
className={`w-auto max-w-full flex-shrink-0 text-left ${className}`}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
onKeyDown={handleKeyDown}
|
||||
button={comboButton}
|
||||
renderByDefault={renderByDefault}
|
||||
multiple
|
||||
>
|
||||
{isOpen && (
|
||||
<Combobox.Options className="fixed z-10" static>
|
||||
<div
|
||||
@@ -307,6 +311,6 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
|
||||
</div>
|
||||
</Combobox.Options>
|
||||
)}
|
||||
</Combobox>
|
||||
</ComboDropDown>
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user