chore: added optional tooltip to dropdowns (#3462)
This commit is contained in:
parent
7fd625e0e3
commit
eae32593cb
15 changed files with 673 additions and 420 deletions
|
|
@ -8,7 +8,7 @@ import { useApplication, useCycle } from "hooks/store";
|
|||
import { useDropdownKeyDown } from "hooks/use-dropdown-key-down";
|
||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||
// icons
|
||||
import { ContrastIcon } from "@plane/ui";
|
||||
import { ContrastIcon, Tooltip } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "helpers/common.helper";
|
||||
// types
|
||||
|
|
@ -32,6 +32,7 @@ type ButtonProps = {
|
|||
dropdownArrow: boolean;
|
||||
dropdownArrowClassName: string;
|
||||
placeholder: string;
|
||||
tooltip: boolean;
|
||||
};
|
||||
|
||||
type DropdownOptions =
|
||||
|
|
@ -51,21 +52,24 @@ const BorderButton = (props: ButtonProps) => {
|
|||
hideIcon = false,
|
||||
hideText = false,
|
||||
placeholder,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && <ContrastIcon className="h-3 w-3 flex-shrink-0" />}{" "}
|
||||
{!hideText && <span className="flex-grow truncate">{cycle?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<Tooltip tooltipHeading="Cycle" tooltipContent={cycle?.name ?? placeholder} disabled={!tooltip}>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && <ContrastIcon className="h-3 w-3 flex-shrink-0" />}{" "}
|
||||
{!hideText && <span className="flex-grow truncate">{cycle?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -78,18 +82,24 @@ const BackgroundButton = (props: ButtonProps) => {
|
|||
hideIcon = false,
|
||||
hideText = false,
|
||||
placeholder,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn("h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 bg-custom-background-80", className)}
|
||||
>
|
||||
{!hideIcon && <ContrastIcon className="h-3 w-3 flex-shrink-0" />}
|
||||
{!hideText && <span className="flex-grow truncate">{cycle?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<Tooltip tooltipHeading="Cycle" tooltipContent={cycle?.name ?? placeholder} disabled={!tooltip}>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && <ContrastIcon className="h-3 w-3 flex-shrink-0" />}
|
||||
{!hideText && <span className="flex-grow truncate">{cycle?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -102,21 +112,24 @@ const TransparentButton = (props: ButtonProps) => {
|
|||
hideIcon = false,
|
||||
hideText = false,
|
||||
placeholder,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && <ContrastIcon className="h-3 w-3 flex-shrink-0" />}
|
||||
{!hideText && <span className="flex-grow truncate">{cycle?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<Tooltip tooltipHeading="Cycle" tooltipContent={cycle?.name ?? placeholder} disabled={!tooltip}>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && <ContrastIcon className="h-3 w-3 flex-shrink-0" />}
|
||||
{!hideText && <span className="flex-grow truncate">{cycle?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -135,8 +148,9 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
|
|||
placeholder = "Cycle",
|
||||
placement,
|
||||
projectId,
|
||||
value,
|
||||
tabIndex,
|
||||
tooltip = false,
|
||||
value,
|
||||
} = props;
|
||||
// states
|
||||
const [query, setQuery] = useState("");
|
||||
|
|
@ -254,6 +268,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "border-without-text" ? (
|
||||
<BorderButton
|
||||
|
|
@ -264,6 +279,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
|
|||
hideIcon={hideIcon}
|
||||
hideText
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "background-with-text" ? (
|
||||
<BackgroundButton
|
||||
|
|
@ -273,6 +289,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "background-without-text" ? (
|
||||
<BackgroundButton
|
||||
|
|
@ -283,6 +300,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
|
|||
hideIcon={hideIcon}
|
||||
hideText
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "transparent-with-text" ? (
|
||||
<TransparentButton
|
||||
|
|
@ -292,6 +310,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "transparent-without-text" ? (
|
||||
<TransparentButton
|
||||
|
|
@ -302,6 +321,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
|
|||
hideIcon={hideIcon}
|
||||
hideText
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : null}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import { CalendarDays, X } from "lucide-react";
|
|||
// hooks
|
||||
import { useDropdownKeyDown } from "hooks/use-dropdown-key-down";
|
||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||
// ui
|
||||
import { Tooltip } from "@plane/ui";
|
||||
// helpers
|
||||
import { renderFormattedDate } from "helpers/date-time.helper";
|
||||
import { cn } from "helpers/common.helper";
|
||||
|
|
@ -33,6 +35,7 @@ type ButtonProps = {
|
|||
hideText?: boolean;
|
||||
onClear: () => void;
|
||||
placeholder: string;
|
||||
tooltip: boolean;
|
||||
};
|
||||
|
||||
const BorderButton = (props: ButtonProps) => {
|
||||
|
|
@ -46,27 +49,34 @@ const BorderButton = (props: ButtonProps) => {
|
|||
hideText = false,
|
||||
onClear,
|
||||
placeholder,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
|
||||
className
|
||||
)}
|
||||
<Tooltip
|
||||
tooltipHeading={placeholder}
|
||||
tooltipContent={date ? renderFormattedDate(date) : "None"}
|
||||
disabled={!tooltip}
|
||||
>
|
||||
{!hideIcon && icon}
|
||||
{!hideText && <span className="flex-grow truncate">{date ? renderFormattedDate(date) : placeholder}</span>}
|
||||
{isClearable && (
|
||||
<X
|
||||
className={cn("h-2 w-2 flex-shrink-0", clearIconClassName)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onClear();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && icon}
|
||||
{!hideText && <span className="flex-grow truncate">{date ? renderFormattedDate(date) : placeholder}</span>}
|
||||
{isClearable && (
|
||||
<X
|
||||
className={cn("h-2 w-2 flex-shrink-0", clearIconClassName)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onClear();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -81,24 +91,34 @@ const BackgroundButton = (props: ButtonProps) => {
|
|||
hideText = false,
|
||||
onClear,
|
||||
placeholder,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn("h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 bg-custom-background-80", className)}
|
||||
<Tooltip
|
||||
tooltipHeading={placeholder}
|
||||
tooltipContent={date ? renderFormattedDate(date) : "None"}
|
||||
disabled={!tooltip}
|
||||
>
|
||||
{!hideIcon && icon}
|
||||
{!hideText && <span className="flex-grow truncate">{date ? renderFormattedDate(date) : placeholder}</span>}
|
||||
{isClearable && (
|
||||
<X
|
||||
className={cn("h-2 w-2 flex-shrink-0", clearIconClassName)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onClear();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && icon}
|
||||
{!hideText && <span className="flex-grow truncate">{date ? renderFormattedDate(date) : placeholder}</span>}
|
||||
{isClearable && (
|
||||
<X
|
||||
className={cn("h-2 w-2 flex-shrink-0", clearIconClassName)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onClear();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -113,27 +133,34 @@ const TransparentButton = (props: ButtonProps) => {
|
|||
hideText = false,
|
||||
onClear,
|
||||
placeholder,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
<Tooltip
|
||||
tooltipHeading={placeholder}
|
||||
tooltipContent={date ? renderFormattedDate(date) : "None"}
|
||||
disabled={!tooltip}
|
||||
>
|
||||
{!hideIcon && icon}
|
||||
{!hideText && <span className="flex-grow truncate">{date ? renderFormattedDate(date) : placeholder}</span>}
|
||||
{isClearable && (
|
||||
<X
|
||||
className={cn("h-2 w-2 flex-shrink-0", clearIconClassName)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onClear();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && icon}
|
||||
{!hideText && <span className="flex-grow truncate">{date ? renderFormattedDate(date) : placeholder}</span>}
|
||||
{isClearable && (
|
||||
<X
|
||||
className={cn("h-2 w-2 flex-shrink-0", clearIconClassName)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onClear();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -144,6 +171,7 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
|||
buttonVariant,
|
||||
className = "",
|
||||
clearIconClassName = "",
|
||||
closeOnSelect = true,
|
||||
disabled = false,
|
||||
hideIcon = false,
|
||||
icon = <CalendarDays className="h-3 w-3 flex-shrink-0" />,
|
||||
|
|
@ -153,9 +181,9 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
|||
onChange,
|
||||
placeholder = "Date",
|
||||
placement,
|
||||
value,
|
||||
closeOnSelect = true,
|
||||
tabIndex,
|
||||
tooltip = false,
|
||||
value,
|
||||
} = props;
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
// refs
|
||||
|
|
@ -218,6 +246,7 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
|||
placeholder={placeholder}
|
||||
isClearable={isClearable && isDateSelected}
|
||||
onClear={() => onChange(null)}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "border-without-text" ? (
|
||||
<BorderButton
|
||||
|
|
@ -229,6 +258,7 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
|||
placeholder={placeholder}
|
||||
isClearable={isClearable && isDateSelected}
|
||||
onClear={() => onChange(null)}
|
||||
tooltip={tooltip}
|
||||
hideText
|
||||
/>
|
||||
) : buttonVariant === "background-with-text" ? (
|
||||
|
|
@ -241,6 +271,7 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
|||
placeholder={placeholder}
|
||||
isClearable={isClearable && isDateSelected}
|
||||
onClear={() => onChange(null)}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "background-without-text" ? (
|
||||
<BackgroundButton
|
||||
|
|
@ -252,6 +283,7 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
|||
placeholder={placeholder}
|
||||
isClearable={isClearable && isDateSelected}
|
||||
onClear={() => onChange(null)}
|
||||
tooltip={tooltip}
|
||||
hideText
|
||||
/>
|
||||
) : buttonVariant === "transparent-with-text" ? (
|
||||
|
|
@ -264,6 +296,7 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
|||
placeholder={placeholder}
|
||||
isClearable={isClearable && isDateSelected}
|
||||
onClear={() => onChange(null)}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "transparent-without-text" ? (
|
||||
<TransparentButton
|
||||
|
|
@ -275,6 +308,7 @@ export const DateDropdown: React.FC<Props> = (props) => {
|
|||
placeholder={placeholder}
|
||||
isClearable={isClearable && isDateSelected}
|
||||
onClear={() => onChange(null)}
|
||||
tooltip={tooltip}
|
||||
hideText
|
||||
/>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import sortBy from "lodash/sortBy";
|
|||
import { useApplication, useEstimate } from "hooks/store";
|
||||
import { useDropdownKeyDown } from "hooks/use-dropdown-key-down";
|
||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||
// ui
|
||||
import { Tooltip } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "helpers/common.helper";
|
||||
// types
|
||||
|
|
@ -30,6 +32,7 @@ type ButtonProps = {
|
|||
hideIcon?: boolean;
|
||||
hideText?: boolean;
|
||||
placeholder: string;
|
||||
tooltip: boolean;
|
||||
};
|
||||
|
||||
type DropdownOptions =
|
||||
|
|
@ -49,21 +52,30 @@ const BorderButton = (props: ButtonProps) => {
|
|||
hideIcon = false,
|
||||
hideText = false,
|
||||
placeholder,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
|
||||
className
|
||||
)}
|
||||
<Tooltip
|
||||
tooltipHeading="Estimate"
|
||||
tooltipContent={estimatePoint !== null ? estimatePoint : placeholder}
|
||||
disabled={!tooltip}
|
||||
>
|
||||
{!hideIcon && <Triangle className="h-3 w-3 flex-shrink-0" />}
|
||||
{!hideText && <span className="flex-grow truncate">{estimatePoint !== null ? estimatePoint : placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && <Triangle className="h-3 w-3 flex-shrink-0" />}
|
||||
{!hideText && (
|
||||
<span className="flex-grow truncate">{estimatePoint !== null ? estimatePoint : placeholder}</span>
|
||||
)}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -76,18 +88,30 @@ const BackgroundButton = (props: ButtonProps) => {
|
|||
hideIcon = false,
|
||||
hideText = false,
|
||||
placeholder,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn("h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 bg-custom-background-80", className)}
|
||||
<Tooltip
|
||||
tooltipHeading="Estimate"
|
||||
tooltipContent={estimatePoint !== null ? estimatePoint : placeholder}
|
||||
disabled={!tooltip}
|
||||
>
|
||||
{!hideIcon && <Triangle className="h-3 w-3 flex-shrink-0" />}
|
||||
{!hideText && <span className="flex-grow truncate">{estimatePoint !== null ? estimatePoint : placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && <Triangle className="h-3 w-3 flex-shrink-0" />}
|
||||
{!hideText && (
|
||||
<span className="flex-grow truncate">{estimatePoint !== null ? estimatePoint : placeholder}</span>
|
||||
)}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -100,21 +124,30 @@ const TransparentButton = (props: ButtonProps) => {
|
|||
hideIcon = false,
|
||||
hideText = false,
|
||||
placeholder,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
<Tooltip
|
||||
tooltipHeading="Estimate"
|
||||
tooltipContent={estimatePoint !== null ? estimatePoint : placeholder}
|
||||
disabled={!tooltip}
|
||||
>
|
||||
{!hideIcon && <Triangle className="h-3 w-3 flex-shrink-0" />}
|
||||
{!hideText && <span className="flex-grow truncate">{estimatePoint !== null ? estimatePoint : placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && <Triangle className="h-3 w-3 flex-shrink-0" />}
|
||||
{!hideText && (
|
||||
<span className="flex-grow truncate">{estimatePoint !== null ? estimatePoint : placeholder}</span>
|
||||
)}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -133,8 +166,9 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
|||
placeholder = "Estimate",
|
||||
placement,
|
||||
projectId,
|
||||
value,
|
||||
tabIndex,
|
||||
tooltip = false,
|
||||
value,
|
||||
} = props;
|
||||
// states
|
||||
const [query, setQuery] = useState("");
|
||||
|
|
@ -242,6 +276,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "border-without-text" ? (
|
||||
<BorderButton
|
||||
|
|
@ -252,6 +287,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
|||
hideIcon={hideIcon}
|
||||
hideText
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "background-with-text" ? (
|
||||
<BackgroundButton
|
||||
|
|
@ -261,6 +297,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "background-without-text" ? (
|
||||
<BackgroundButton
|
||||
|
|
@ -271,6 +308,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
|||
hideIcon={hideIcon}
|
||||
hideText
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "transparent-with-text" ? (
|
||||
<TransparentButton
|
||||
|
|
@ -280,6 +318,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "transparent-without-text" ? (
|
||||
<TransparentButton
|
||||
|
|
@ -290,6 +329,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
|||
hideIcon={hideIcon}
|
||||
hideText
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : null}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { ChevronDown } from "lucide-react";
|
|||
// hooks
|
||||
import { useMember } from "hooks/store";
|
||||
// ui
|
||||
import { Avatar, AvatarGroup, UserGroupIcon } from "@plane/ui";
|
||||
import { Avatar, AvatarGroup, Tooltip, UserGroupIcon } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "helpers/common.helper";
|
||||
|
||||
|
|
@ -14,16 +14,17 @@ type ButtonProps = {
|
|||
placeholder: string;
|
||||
hideIcon?: boolean;
|
||||
hideText?: boolean;
|
||||
tooltip: boolean;
|
||||
userIds: string | string[] | null;
|
||||
};
|
||||
|
||||
const ButtonAvatars = observer(({ userIds }: { userIds: string | string[] | null }) => {
|
||||
const ButtonAvatars = observer(({ tooltip, userIds }: { tooltip: boolean; userIds: string | string[] | null }) => {
|
||||
const { getUserDetails } = useMember();
|
||||
|
||||
if (Array.isArray(userIds)) {
|
||||
if (userIds.length > 0)
|
||||
return (
|
||||
<AvatarGroup size="md">
|
||||
<AvatarGroup size="md" showTooltip={!tooltip}>
|
||||
{userIds.map((userId) => {
|
||||
const userDetails = getUserDetails(userId);
|
||||
|
||||
|
|
@ -35,7 +36,7 @@ const ButtonAvatars = observer(({ userIds }: { userIds: string | string[] | null
|
|||
} else {
|
||||
if (userIds) {
|
||||
const userDetails = getUserDetails(userIds);
|
||||
return <Avatar src={userDetails?.avatar} name={userDetails?.display_name} size="md" />;
|
||||
return <Avatar src={userDetails?.avatar} name={userDetails?.display_name} size="md" showTooltip={!tooltip} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -51,6 +52,7 @@ export const BorderButton = observer((props: ButtonProps) => {
|
|||
hideText = false,
|
||||
placeholder,
|
||||
userIds,
|
||||
tooltip,
|
||||
} = props;
|
||||
// store hooks
|
||||
const { getUserDetails } = useMember();
|
||||
|
|
@ -58,22 +60,28 @@ export const BorderButton = observer((props: ButtonProps) => {
|
|||
const isMultiple = Array.isArray(userIds);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
|
||||
className
|
||||
)}
|
||||
<Tooltip
|
||||
tooltipHeading={placeholder}
|
||||
tooltipContent={`${userIds?.length ?? 0} assignee${userIds?.length !== 1 ? "s" : ""}`}
|
||||
disabled={!tooltip}
|
||||
>
|
||||
{!hideIcon && <ButtonAvatars userIds={userIds} />}
|
||||
{!hideText && (
|
||||
<span className="flex-grow truncate">
|
||||
{userIds ? (isMultiple ? placeholder : getUserDetails(userIds)?.display_name) : placeholder}
|
||||
</span>
|
||||
)}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && <ButtonAvatars tooltip={tooltip} userIds={userIds} />}
|
||||
{!hideText && (
|
||||
<span className="flex-grow truncate">
|
||||
{userIds ? (isMultiple ? placeholder : getUserDetails(userIds)?.display_name) : placeholder}
|
||||
</span>
|
||||
)}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -86,6 +94,7 @@ export const BackgroundButton = observer((props: ButtonProps) => {
|
|||
hideText = false,
|
||||
placeholder,
|
||||
userIds,
|
||||
tooltip,
|
||||
} = props;
|
||||
// store hooks
|
||||
const { getUserDetails } = useMember();
|
||||
|
|
@ -93,19 +102,28 @@ export const BackgroundButton = observer((props: ButtonProps) => {
|
|||
const isMultiple = Array.isArray(userIds);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn("h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 bg-custom-background-80", className)}
|
||||
<Tooltip
|
||||
tooltipHeading={placeholder}
|
||||
tooltipContent={`${userIds?.length ?? 0} assignee${userIds?.length !== 1 ? "s" : ""}`}
|
||||
disabled={!tooltip}
|
||||
>
|
||||
{!hideIcon && <ButtonAvatars userIds={userIds} />}
|
||||
{!hideText && (
|
||||
<span className="flex-grow truncate">
|
||||
{userIds ? (isMultiple ? placeholder : getUserDetails(userIds)?.display_name) : placeholder}
|
||||
</span>
|
||||
)}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && <ButtonAvatars tooltip={tooltip} userIds={userIds} />}
|
||||
{!hideText && (
|
||||
<span className="flex-grow truncate">
|
||||
{userIds ? (isMultiple ? placeholder : getUserDetails(userIds)?.display_name) : placeholder}
|
||||
</span>
|
||||
)}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -118,6 +136,7 @@ export const TransparentButton = observer((props: ButtonProps) => {
|
|||
hideText = false,
|
||||
placeholder,
|
||||
userIds,
|
||||
tooltip,
|
||||
} = props;
|
||||
// store hooks
|
||||
const { getUserDetails } = useMember();
|
||||
|
|
@ -125,21 +144,27 @@ export const TransparentButton = observer((props: ButtonProps) => {
|
|||
const isMultiple = Array.isArray(userIds);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
<Tooltip
|
||||
tooltipHeading={placeholder}
|
||||
tooltipContent={`${userIds?.length ?? 0} assignee${userIds?.length !== 1 ? "s" : ""}`}
|
||||
disabled={!tooltip}
|
||||
>
|
||||
{!hideIcon && <ButtonAvatars userIds={userIds} />}
|
||||
{!hideText && (
|
||||
<span className="flex-grow truncate">
|
||||
{userIds ? (isMultiple ? placeholder : getUserDetails(userIds)?.display_name) : placeholder}
|
||||
</span>
|
||||
)}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && <ButtonAvatars tooltip={tooltip} userIds={userIds} />}
|
||||
{!hideText && (
|
||||
<span className="flex-grow truncate">
|
||||
{userIds ? (isMultiple ? placeholder : getUserDetails(userIds)?.display_name) : placeholder}
|
||||
</span>
|
||||
)}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -36,8 +36,9 @@ export const ProjectMemberDropdown: React.FC<Props> = observer((props) => {
|
|||
placeholder = "Members",
|
||||
placement,
|
||||
projectId,
|
||||
value,
|
||||
tabIndex,
|
||||
tooltip = false,
|
||||
value,
|
||||
} = props;
|
||||
// states
|
||||
const [query, setQuery] = useState("");
|
||||
|
|
@ -146,6 +147,7 @@ export const ProjectMemberDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "border-without-text" ? (
|
||||
<BorderButton
|
||||
|
|
@ -155,6 +157,7 @@ export const ProjectMemberDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
hideText
|
||||
/>
|
||||
) : buttonVariant === "background-with-text" ? (
|
||||
|
|
@ -165,6 +168,7 @@ export const ProjectMemberDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "background-without-text" ? (
|
||||
<BackgroundButton
|
||||
|
|
@ -174,6 +178,7 @@ export const ProjectMemberDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
hideText
|
||||
/>
|
||||
) : buttonVariant === "transparent-with-text" ? (
|
||||
|
|
@ -184,6 +189,7 @@ export const ProjectMemberDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "transparent-without-text" ? (
|
||||
<TransparentButton
|
||||
|
|
@ -193,6 +199,7 @@ export const ProjectMemberDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
hideText
|
||||
/>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,9 @@ export const WorkspaceMemberDropdown: React.FC<MemberDropdownProps> = observer((
|
|||
onChange,
|
||||
placeholder = "Members",
|
||||
placement,
|
||||
value,
|
||||
tabIndex,
|
||||
tooltip = false,
|
||||
value,
|
||||
} = props;
|
||||
// states
|
||||
const [query, setQuery] = useState("");
|
||||
|
|
@ -133,6 +134,7 @@ export const WorkspaceMemberDropdown: React.FC<MemberDropdownProps> = observer((
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "border-without-text" ? (
|
||||
<BorderButton
|
||||
|
|
@ -142,6 +144,7 @@ export const WorkspaceMemberDropdown: React.FC<MemberDropdownProps> = observer((
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
hideText
|
||||
/>
|
||||
) : buttonVariant === "background-with-text" ? (
|
||||
|
|
@ -152,6 +155,7 @@ export const WorkspaceMemberDropdown: React.FC<MemberDropdownProps> = observer((
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "background-without-text" ? (
|
||||
<BackgroundButton
|
||||
|
|
@ -161,6 +165,7 @@ export const WorkspaceMemberDropdown: React.FC<MemberDropdownProps> = observer((
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
hideText
|
||||
/>
|
||||
) : buttonVariant === "transparent-with-text" ? (
|
||||
|
|
@ -171,6 +176,7 @@ export const WorkspaceMemberDropdown: React.FC<MemberDropdownProps> = observer((
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "transparent-without-text" ? (
|
||||
<TransparentButton
|
||||
|
|
@ -180,6 +186,7 @@ export const WorkspaceMemberDropdown: React.FC<MemberDropdownProps> = observer((
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
hideText
|
||||
/>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { useApplication, useModule } from "hooks/store";
|
|||
import { useDropdownKeyDown } from "hooks/use-dropdown-key-down";
|
||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||
// icons
|
||||
import { DiceIcon } from "@plane/ui";
|
||||
import { DiceIcon, Tooltip } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "helpers/common.helper";
|
||||
// types
|
||||
|
|
@ -40,6 +40,7 @@ type ButtonProps = {
|
|||
hideText?: boolean;
|
||||
module: IModule | null;
|
||||
placeholder: string;
|
||||
tooltip: boolean;
|
||||
};
|
||||
|
||||
const BorderButton = (props: ButtonProps) => {
|
||||
|
|
@ -51,21 +52,24 @@ const BorderButton = (props: ButtonProps) => {
|
|||
hideText = false,
|
||||
module,
|
||||
placeholder,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && <DiceIcon className="h-3 w-3 flex-shrink-0" />}
|
||||
{!hideText && <span className="flex-grow truncate">{module?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<Tooltip tooltipHeading="Module" tooltipContent={module?.name ?? placeholder} disabled={!tooltip}>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && <DiceIcon className="h-3 w-3 flex-shrink-0" />}
|
||||
{!hideText && <span className="flex-grow truncate">{module?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -78,18 +82,24 @@ const BackgroundButton = (props: ButtonProps) => {
|
|||
hideText = false,
|
||||
module,
|
||||
placeholder,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn("h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 bg-custom-background-80", className)}
|
||||
>
|
||||
{!hideIcon && <DiceIcon className="h-3 w-3 flex-shrink-0" />}
|
||||
{!hideText && <span className="flex-grow truncate">{module?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<Tooltip tooltipHeading="Module" tooltipContent={module?.name ?? placeholder} disabled={!tooltip}>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && <DiceIcon className="h-3 w-3 flex-shrink-0" />}
|
||||
{!hideText && <span className="flex-grow truncate">{module?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -102,21 +112,24 @@ const TransparentButton = (props: ButtonProps) => {
|
|||
hideText = false,
|
||||
module,
|
||||
placeholder,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && <DiceIcon className="h-3 w-3 flex-shrink-0" />}
|
||||
{!hideText && <span className="flex-grow truncate">{module?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<Tooltip tooltipHeading="Module" tooltipContent={module?.name ?? placeholder} disabled={!tooltip}>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && <DiceIcon className="h-3 w-3 flex-shrink-0" />}
|
||||
{!hideText && <span className="flex-grow truncate">{module?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -135,8 +148,9 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
|
|||
placeholder = "Module",
|
||||
placement,
|
||||
projectId,
|
||||
value,
|
||||
tabIndex,
|
||||
tooltip = false,
|
||||
value,
|
||||
} = props;
|
||||
// states
|
||||
const [query, setQuery] = useState("");
|
||||
|
|
@ -253,6 +267,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "border-without-text" ? (
|
||||
<BorderButton
|
||||
|
|
@ -263,6 +278,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
|
|||
hideIcon={hideIcon}
|
||||
hideText
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "background-with-text" ? (
|
||||
<BackgroundButton
|
||||
|
|
@ -272,6 +288,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "background-without-text" ? (
|
||||
<BackgroundButton
|
||||
|
|
@ -282,6 +299,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
|
|||
hideIcon={hideIcon}
|
||||
hideText
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "transparent-with-text" ? (
|
||||
<TransparentButton
|
||||
|
|
@ -291,6 +309,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "transparent-without-text" ? (
|
||||
<TransparentButton
|
||||
|
|
@ -301,6 +320,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
|
|||
hideIcon={hideIcon}
|
||||
hideText
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : null}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@ import { Fragment, ReactNode, useRef, useState } from "react";
|
|||
import { Combobox } from "@headlessui/react";
|
||||
import { usePopper } from "react-popper";
|
||||
import { Check, ChevronDown, Search } from "lucide-react";
|
||||
import { useTheme } from "next-themes";
|
||||
// hooks
|
||||
import { useDropdownKeyDown } from "hooks/use-dropdown-key-down";
|
||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||
// icons
|
||||
import { PriorityIcon } from "@plane/ui";
|
||||
import { PriorityIcon, Tooltip } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "helpers/common.helper";
|
||||
// types
|
||||
|
|
@ -14,7 +15,6 @@ import { TIssuePriorities } from "@plane/types";
|
|||
import { TDropdownProps } from "./types";
|
||||
// constants
|
||||
import { ISSUE_PRIORITIES } from "constants/issue";
|
||||
import { useTheme } from "next-themes";
|
||||
|
||||
type Props = TDropdownProps & {
|
||||
button?: ReactNode;
|
||||
|
|
@ -33,6 +33,7 @@ type ButtonProps = {
|
|||
hideText?: boolean;
|
||||
highlightUrgent: boolean;
|
||||
priority: TIssuePriorities;
|
||||
tooltip: boolean;
|
||||
};
|
||||
|
||||
const BorderButton = (props: ButtonProps) => {
|
||||
|
|
@ -44,6 +45,7 @@ const BorderButton = (props: ButtonProps) => {
|
|||
hideText = false,
|
||||
highlightUrgent,
|
||||
priority,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
const priorityDetails = ISSUE_PRIORITIES.find((p) => p.key === priority);
|
||||
|
|
@ -57,47 +59,49 @@ const BorderButton = (props: ButtonProps) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 border-[0.5px] rounded text-xs px-2 py-0.5",
|
||||
priorityClasses[priority],
|
||||
{
|
||||
// compact the icons if text is hidden
|
||||
"px-0.5": hideText,
|
||||
// highlight the whole button if text is hidden and priority is urgent
|
||||
"bg-red-500 border-red-500": priority === "urgent" && hideText && highlightUrgent,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<div
|
||||
className={cn({
|
||||
// highlight just the icon if text is visible and priority is urgent
|
||||
"bg-red-500 p-1 rounded": priority === "urgent" && !hideText && highlightUrgent,
|
||||
})}
|
||||
>
|
||||
<PriorityIcon
|
||||
priority={priority}
|
||||
size={12}
|
||||
className={cn("flex-shrink-0", {
|
||||
// increase the icon size if text is hidden
|
||||
"h-3.5 w-3.5": hideText,
|
||||
// centre align the icons if text is hidden
|
||||
"translate-x-[0.0625rem]": hideText && priority === "high",
|
||||
"translate-x-0.5": hideText && priority === "medium",
|
||||
"translate-x-1": hideText && priority === "low",
|
||||
// highlight the icon if priority is urgent
|
||||
"text-white": priority === "urgent" && highlightUrgent,
|
||||
<Tooltip tooltipHeading="Priority" tooltipContent={priorityDetails?.title ?? "None"} disabled={!tooltip}>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 border-[0.5px] rounded text-xs px-2 py-0.5",
|
||||
priorityClasses[priority],
|
||||
{
|
||||
// compact the icons if text is hidden
|
||||
"px-0.5": hideText,
|
||||
// highlight the whole button if text is hidden and priority is urgent
|
||||
"bg-red-500 border-red-500": priority === "urgent" && hideText && highlightUrgent,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<div
|
||||
className={cn({
|
||||
// highlight just the icon if text is visible and priority is urgent
|
||||
"bg-red-500 p-1 rounded": priority === "urgent" && !hideText && highlightUrgent,
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{priorityDetails?.title}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
>
|
||||
<PriorityIcon
|
||||
priority={priority}
|
||||
size={12}
|
||||
className={cn("flex-shrink-0", {
|
||||
// increase the icon size if text is hidden
|
||||
"h-3.5 w-3.5": hideText,
|
||||
// centre align the icons if text is hidden
|
||||
"translate-x-[0.0625rem]": hideText && priority === "high",
|
||||
"translate-x-0.5": hideText && priority === "medium",
|
||||
"translate-x-1": hideText && priority === "low",
|
||||
// highlight the icon if priority is urgent
|
||||
"text-white": priority === "urgent" && highlightUrgent,
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{priorityDetails?.title}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -110,6 +114,7 @@ const BackgroundButton = (props: ButtonProps) => {
|
|||
hideText = false,
|
||||
highlightUrgent,
|
||||
priority,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
const priorityDetails = ISSUE_PRIORITIES.find((p) => p.key === priority);
|
||||
|
|
@ -123,47 +128,49 @@ const BackgroundButton = (props: ButtonProps) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5",
|
||||
priorityClasses[priority],
|
||||
{
|
||||
// compact the icons if text is hidden
|
||||
"px-0.5": hideText,
|
||||
// highlight the whole button if text is hidden and priority is urgent
|
||||
"bg-red-500 border-red-500": priority === "urgent" && hideText && highlightUrgent,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<div
|
||||
className={cn({
|
||||
// highlight just the icon if text is visible and priority is urgent
|
||||
"bg-red-500 p-1 rounded": priority === "urgent" && !hideText && highlightUrgent,
|
||||
})}
|
||||
>
|
||||
<PriorityIcon
|
||||
priority={priority}
|
||||
size={12}
|
||||
className={cn("flex-shrink-0", {
|
||||
// increase the icon size if text is hidden
|
||||
"h-3.5 w-3.5": hideText,
|
||||
// centre align the icons if text is hidden
|
||||
"translate-x-[0.0625rem]": hideText && priority === "high",
|
||||
"translate-x-0.5": hideText && priority === "medium",
|
||||
"translate-x-1": hideText && priority === "low",
|
||||
// highlight the icon if priority is urgent
|
||||
"text-white": priority === "urgent" && highlightUrgent,
|
||||
<Tooltip tooltipHeading="Priority" tooltipContent={priorityDetails?.title ?? "None"} disabled={!tooltip}>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5",
|
||||
priorityClasses[priority],
|
||||
{
|
||||
// compact the icons if text is hidden
|
||||
"px-0.5": hideText,
|
||||
// highlight the whole button if text is hidden and priority is urgent
|
||||
"bg-red-500 border-red-500": priority === "urgent" && hideText && highlightUrgent,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<div
|
||||
className={cn({
|
||||
// highlight just the icon if text is visible and priority is urgent
|
||||
"bg-red-500 p-1 rounded": priority === "urgent" && !hideText && highlightUrgent,
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{priorityDetails?.title}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
>
|
||||
<PriorityIcon
|
||||
priority={priority}
|
||||
size={12}
|
||||
className={cn("flex-shrink-0", {
|
||||
// increase the icon size if text is hidden
|
||||
"h-3.5 w-3.5": hideText,
|
||||
// centre align the icons if text is hidden
|
||||
"translate-x-[0.0625rem]": hideText && priority === "high",
|
||||
"translate-x-0.5": hideText && priority === "medium",
|
||||
"translate-x-1": hideText && priority === "low",
|
||||
// highlight the icon if priority is urgent
|
||||
"text-white": priority === "urgent" && highlightUrgent,
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{priorityDetails?.title}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -176,6 +183,7 @@ const TransparentButton = (props: ButtonProps) => {
|
|||
hideText = false,
|
||||
highlightUrgent,
|
||||
priority,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
const priorityDetails = ISSUE_PRIORITIES.find((p) => p.key === priority);
|
||||
|
|
@ -189,47 +197,49 @@ const TransparentButton = (props: ButtonProps) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
|
||||
priorityClasses[priority],
|
||||
{
|
||||
// compact the icons if text is hidden
|
||||
"px-0.5": hideText,
|
||||
// highlight the whole button if text is hidden and priority is urgent
|
||||
"bg-red-500 border-red-500": priority === "urgent" && hideText && highlightUrgent,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<div
|
||||
className={cn({
|
||||
// highlight just the icon if text is visible and priority is urgent
|
||||
"bg-red-500 p-1 rounded": priority === "urgent" && !hideText && highlightUrgent,
|
||||
})}
|
||||
>
|
||||
<PriorityIcon
|
||||
priority={priority}
|
||||
size={12}
|
||||
className={cn("flex-shrink-0", {
|
||||
// increase the icon size if text is hidden
|
||||
"h-3.5 w-3.5": hideText,
|
||||
// centre align the icons if text is hidden
|
||||
"translate-x-[0.0625rem]": hideText && priority === "high",
|
||||
"translate-x-0.5": hideText && priority === "medium",
|
||||
"translate-x-1": hideText && priority === "low",
|
||||
// highlight the icon if priority is urgent
|
||||
"text-white": priority === "urgent" && highlightUrgent,
|
||||
<Tooltip tooltipHeading="Priority" tooltipContent={priorityDetails?.title ?? "None"} disabled={!tooltip}>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
|
||||
priorityClasses[priority],
|
||||
{
|
||||
// compact the icons if text is hidden
|
||||
"px-0.5": hideText,
|
||||
// highlight the whole button if text is hidden and priority is urgent
|
||||
"bg-red-500 border-red-500": priority === "urgent" && hideText && highlightUrgent,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<div
|
||||
className={cn({
|
||||
// highlight just the icon if text is visible and priority is urgent
|
||||
"bg-red-500 p-1 rounded": priority === "urgent" && !hideText && highlightUrgent,
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{priorityDetails?.title}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
>
|
||||
<PriorityIcon
|
||||
priority={priority}
|
||||
size={12}
|
||||
className={cn("flex-shrink-0", {
|
||||
// increase the icon size if text is hidden
|
||||
"h-3.5 w-3.5": hideText,
|
||||
// centre align the icons if text is hidden
|
||||
"translate-x-[0.0625rem]": hideText && priority === "high",
|
||||
"translate-x-0.5": hideText && priority === "medium",
|
||||
"translate-x-1": hideText && priority === "low",
|
||||
// highlight the icon if priority is urgent
|
||||
"text-white": priority === "urgent" && highlightUrgent,
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{priorityDetails?.title}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -247,8 +257,9 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
|
|||
highlightUrgent = true,
|
||||
onChange,
|
||||
placement,
|
||||
value,
|
||||
tabIndex,
|
||||
tooltip = false,
|
||||
value,
|
||||
} = props;
|
||||
// states
|
||||
const [query, setQuery] = useState("");
|
||||
|
|
@ -341,6 +352,7 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
|
|||
dropdownArrow={dropdownArrow && !disabled}
|
||||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "border-without-text" ? (
|
||||
<BorderButton
|
||||
|
|
@ -352,6 +364,7 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
|
|||
dropdownArrow={dropdownArrow && !disabled}
|
||||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
tooltip={tooltip}
|
||||
hideText
|
||||
/>
|
||||
) : buttonVariant === "background-with-text" ? (
|
||||
|
|
@ -364,6 +377,7 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
|
|||
dropdownArrow={dropdownArrow && !disabled}
|
||||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "background-without-text" ? (
|
||||
<BackgroundButton
|
||||
|
|
@ -375,6 +389,7 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
|
|||
dropdownArrow={dropdownArrow && !disabled}
|
||||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
tooltip={tooltip}
|
||||
hideText
|
||||
/>
|
||||
) : buttonVariant === "transparent-with-text" ? (
|
||||
|
|
@ -387,6 +402,7 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
|
|||
dropdownArrow={dropdownArrow && !disabled}
|
||||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "transparent-without-text" ? (
|
||||
<TransparentButton
|
||||
|
|
@ -398,6 +414,7 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
|
|||
dropdownArrow={dropdownArrow && !disabled}
|
||||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
tooltip={tooltip}
|
||||
hideText
|
||||
/>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import { Check, ChevronDown, Search } from "lucide-react";
|
|||
import { useProject } from "hooks/store";
|
||||
import { useDropdownKeyDown } from "hooks/use-dropdown-key-down";
|
||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||
// ui
|
||||
import { Tooltip } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "helpers/common.helper";
|
||||
import { renderEmoji } from "helpers/emoji.helper";
|
||||
|
|
@ -30,6 +32,7 @@ type ButtonProps = {
|
|||
hideText?: boolean;
|
||||
placeholder: string;
|
||||
project: IProject | null;
|
||||
tooltip: boolean;
|
||||
};
|
||||
|
||||
const BorderButton = (props: ButtonProps) => {
|
||||
|
|
@ -41,25 +44,28 @@ const BorderButton = (props: ButtonProps) => {
|
|||
hideText = false,
|
||||
placeholder,
|
||||
project,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<span className="grid place-items-center flex-shrink-0">
|
||||
{project?.emoji ? renderEmoji(project?.emoji) : project?.icon_prop ? renderEmoji(project?.icon_prop) : null}
|
||||
</span>
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{project?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<Tooltip tooltipHeading="Project" tooltipContent={project?.name ?? placeholder} disabled={!tooltip}>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<span className="grid place-items-center flex-shrink-0">
|
||||
{project?.emoji ? renderEmoji(project?.emoji) : project?.icon_prop ? renderEmoji(project?.icon_prop) : null}
|
||||
</span>
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{project?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -72,22 +78,28 @@ const BackgroundButton = (props: ButtonProps) => {
|
|||
hideText = false,
|
||||
placeholder,
|
||||
project,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn("h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 bg-custom-background-80", className)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<span className="grid place-items-center flex-shrink-0">
|
||||
{project?.emoji ? renderEmoji(project?.emoji) : project?.icon_prop ? renderEmoji(project?.icon_prop) : null}
|
||||
</span>
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{project?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<Tooltip tooltipHeading="Project" tooltipContent={project?.name ?? placeholder} disabled={!tooltip}>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<span className="grid place-items-center flex-shrink-0">
|
||||
{project?.emoji ? renderEmoji(project?.emoji) : project?.icon_prop ? renderEmoji(project?.icon_prop) : null}
|
||||
</span>
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{project?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -100,25 +112,28 @@ const TransparentButton = (props: ButtonProps) => {
|
|||
hideText = false,
|
||||
placeholder,
|
||||
project,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<span className="grid place-items-center flex-shrink-0">
|
||||
{project?.emoji ? renderEmoji(project?.emoji) : project?.icon_prop ? renderEmoji(project?.icon_prop) : null}
|
||||
</span>
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{project?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<Tooltip tooltipHeading="Project" tooltipContent={project?.name ?? placeholder} disabled={!tooltip}>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<span className="grid place-items-center flex-shrink-0">
|
||||
{project?.emoji ? renderEmoji(project?.emoji) : project?.icon_prop ? renderEmoji(project?.icon_prop) : null}
|
||||
</span>
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{project?.name ?? placeholder}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -136,8 +151,9 @@ export const ProjectDropdown: React.FC<Props> = observer((props) => {
|
|||
onChange,
|
||||
placeholder = "Project",
|
||||
placement,
|
||||
value,
|
||||
tabIndex,
|
||||
tooltip = false,
|
||||
value,
|
||||
} = props;
|
||||
// states
|
||||
const [query, setQuery] = useState("");
|
||||
|
|
@ -239,6 +255,7 @@ export const ProjectDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "border-without-text" ? (
|
||||
<BorderButton
|
||||
|
|
@ -249,6 +266,7 @@ export const ProjectDropdown: React.FC<Props> = observer((props) => {
|
|||
hideIcon={hideIcon}
|
||||
hideText
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "background-with-text" ? (
|
||||
<BackgroundButton
|
||||
|
|
@ -258,6 +276,7 @@ export const ProjectDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "background-without-text" ? (
|
||||
<BackgroundButton
|
||||
|
|
@ -268,6 +287,7 @@ export const ProjectDropdown: React.FC<Props> = observer((props) => {
|
|||
hideIcon={hideIcon}
|
||||
hideText
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "transparent-with-text" ? (
|
||||
<TransparentButton
|
||||
|
|
@ -277,6 +297,7 @@ export const ProjectDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "transparent-without-text" ? (
|
||||
<TransparentButton
|
||||
|
|
@ -287,6 +308,7 @@ export const ProjectDropdown: React.FC<Props> = observer((props) => {
|
|||
hideIcon={hideIcon}
|
||||
hideText
|
||||
placeholder={placeholder}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : null}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { useApplication, useProjectState } from "hooks/store";
|
|||
import { useDropdownKeyDown } from "hooks/use-dropdown-key-down";
|
||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||
// icons
|
||||
import { StateGroupIcon } from "@plane/ui";
|
||||
import { StateGroupIcon, Tooltip } from "@plane/ui";
|
||||
// helpers
|
||||
import { cn } from "helpers/common.helper";
|
||||
// types
|
||||
|
|
@ -31,65 +31,111 @@ type ButtonProps = {
|
|||
hideIcon?: boolean;
|
||||
hideText?: boolean;
|
||||
state: IState | undefined;
|
||||
tooltip: boolean;
|
||||
};
|
||||
|
||||
const BorderButton = (props: ButtonProps) => {
|
||||
const { className, dropdownArrow, dropdownArrowClassName, hideIcon = false, hideText = false, state } = props;
|
||||
const {
|
||||
className,
|
||||
dropdownArrow,
|
||||
dropdownArrowClassName,
|
||||
hideIcon = false,
|
||||
hideText = false,
|
||||
state,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<StateGroupIcon stateGroup={state?.group ?? "backlog"} color={state?.color} className="h-3 w-3 flex-shrink-0" />
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{state?.name ?? "State"}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<Tooltip tooltipHeading="State" tooltipContent={state?.name ?? "State"} disabled={!tooltip}>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<StateGroupIcon
|
||||
stateGroup={state?.group ?? "backlog"}
|
||||
color={state?.color}
|
||||
className="h-3 w-3 flex-shrink-0"
|
||||
/>
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{state?.name ?? "State"}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
const BackgroundButton = (props: ButtonProps) => {
|
||||
const { className, dropdownArrow, dropdownArrowClassName, hideIcon = false, hideText = false, state } = props;
|
||||
const {
|
||||
className,
|
||||
dropdownArrow,
|
||||
dropdownArrowClassName,
|
||||
hideIcon = false,
|
||||
hideText = false,
|
||||
state,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn("h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 bg-custom-background-80", className)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<StateGroupIcon stateGroup={state?.group ?? "backlog"} color={state?.color} className="h-3 w-3 flex-shrink-0" />
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{state?.name ?? "State"}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<Tooltip tooltipHeading="State" tooltipContent={state?.name ?? "State"} disabled={!tooltip}>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<StateGroupIcon
|
||||
stateGroup={state?.group ?? "backlog"}
|
||||
color={state?.color}
|
||||
className="h-3 w-3 flex-shrink-0"
|
||||
/>
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{state?.name ?? "State"}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
const TransparentButton = (props: ButtonProps) => {
|
||||
const { className, dropdownArrow, dropdownArrowClassName, hideIcon = false, hideText = false, state } = props;
|
||||
const {
|
||||
className,
|
||||
dropdownArrow,
|
||||
dropdownArrowClassName,
|
||||
hideIcon = false,
|
||||
hideText = false,
|
||||
state,
|
||||
tooltip,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<StateGroupIcon stateGroup={state?.group ?? "backlog"} color={state?.color} className="h-3 w-3 flex-shrink-0" />
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{state?.name ?? "State"}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<Tooltip tooltipHeading="State" tooltipContent={state?.name ?? "State"} disabled={!tooltip}>
|
||||
<div
|
||||
className={cn(
|
||||
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!hideIcon && (
|
||||
<StateGroupIcon
|
||||
stateGroup={state?.group ?? "backlog"}
|
||||
color={state?.color}
|
||||
className="h-3 w-3 flex-shrink-0"
|
||||
/>
|
||||
)}
|
||||
{!hideText && <span className="flex-grow truncate">{state?.name ?? "State"}</span>}
|
||||
{dropdownArrow && (
|
||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -107,8 +153,9 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
|
|||
onChange,
|
||||
placement,
|
||||
projectId,
|
||||
value,
|
||||
tabIndex,
|
||||
tooltip = false,
|
||||
value,
|
||||
} = props;
|
||||
// states
|
||||
const [query, setQuery] = useState("");
|
||||
|
|
@ -204,6 +251,7 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrow={dropdownArrow && !disabled}
|
||||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "border-without-text" ? (
|
||||
<BorderButton
|
||||
|
|
@ -212,6 +260,7 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrow={dropdownArrow && !disabled}
|
||||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
tooltip={tooltip}
|
||||
hideText
|
||||
/>
|
||||
) : buttonVariant === "background-with-text" ? (
|
||||
|
|
@ -221,6 +270,7 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrow={dropdownArrow && !disabled}
|
||||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "background-without-text" ? (
|
||||
<BackgroundButton
|
||||
|
|
@ -229,6 +279,7 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrow={dropdownArrow && !disabled}
|
||||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
tooltip={tooltip}
|
||||
hideText
|
||||
/>
|
||||
) : buttonVariant === "transparent-with-text" ? (
|
||||
|
|
@ -238,6 +289,7 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
|
|||
dropdownArrow={dropdownArrow && !disabled}
|
||||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
) : buttonVariant === "transparent-without-text" ? (
|
||||
<TransparentButton
|
||||
|
|
@ -245,6 +297,8 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
|
|||
className={buttonClassName}
|
||||
dropdownArrow={dropdownArrow && !disabled}
|
||||
dropdownArrowClassName={dropdownArrowClassName}
|
||||
hideIcon={hideIcon}
|
||||
tooltip={tooltip}
|
||||
hideText
|
||||
/>
|
||||
) : null}
|
||||
|
|
|
|||
1
web/components/dropdowns/types.d.ts
vendored
1
web/components/dropdowns/types.d.ts
vendored
|
|
@ -18,4 +18,5 @@ export type TDropdownProps = {
|
|||
placeholder?: string;
|
||||
placement?: Placement;
|
||||
tabIndex?: number;
|
||||
tooltip?: boolean;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue