[WEB-4724] feat: tooltip component added to propel package (#7613)

* feat: tooltip component added to propel package

* chore: code refactor

* chore: code refactor

* fix: format error
This commit is contained in:
Anmol Singh Bhatia 2025-08-21 13:03:18 +05:30 committed by GitHub
parent 03479cf6b3
commit f10cd92610
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 121 additions and 0 deletions

View file

@ -18,6 +18,8 @@
"./menu": "./src/menu/index.ts",
"./table": "./src/table/index.ts",
"./tabs": "./src/tabs/index.ts",
"./popover": "./src/popover/index.ts",
"./tooltip": "./src/tooltip/index.ts",
"./styles/fonts": "./src/styles/fonts/index.css"
},
"dependencies": {

View file

@ -0,0 +1 @@
export * from "./root";

View file

@ -0,0 +1,118 @@
import * as React from "react";
import { Tooltip as BaseTooltip } from "@base-ui-components/react/tooltip";
import { cn } from "@plane/utils";
export type TPosition =
| "top"
| "right"
| "bottom"
| "left"
| "auto"
| "auto-end"
| "auto-start"
| "bottom-start"
| "bottom-end"
| "left-start"
| "left-end"
| "right-start"
| "right-end"
| "top-start"
| "top-end";
type Side = "top" | "bottom" | "left" | "right";
type Align = "start" | "center" | "end";
// placement conversion map
const PLACEMENT_MAP = new Map<TPosition, { side: Side; align: Align }>([
["auto", { side: "bottom", align: "center" }],
["auto-start", { side: "bottom", align: "start" }],
["auto-end", { side: "bottom", align: "end" }],
["top", { side: "top", align: "center" }],
["bottom", { side: "bottom", align: "center" }],
["left", { side: "left", align: "center" }],
["right", { side: "right", align: "center" }],
["top-start", { side: "top", align: "start" }],
["top-end", { side: "top", align: "end" }],
["bottom-start", { side: "bottom", align: "start" }],
["bottom-end", { side: "bottom", align: "end" }],
["left-start", { side: "left", align: "start" }],
["left-end", { side: "left", align: "end" }],
["right-start", { side: "right", align: "start" }],
["right-end", { side: "right", align: "end" }],
]);
type ITooltipProps = {
tooltipHeading?: string;
tooltipContent: string | React.ReactNode;
position?: TPosition;
children: React.ReactElement;
disabled?: boolean;
className?: string;
openDelay?: number;
closeDelay?: number;
isMobile?: boolean;
renderByDefault?: boolean;
side?: Side;
align?: Align;
sideOffset?: number;
};
// conversion function
export function convertPlacementToSideAndAlign(placement: TPosition): {
side: Side;
align: Align;
} {
return PLACEMENT_MAP.get(placement) || { side: "bottom", align: "center" };
}
export function Tooltip(props: ITooltipProps) {
const {
tooltipHeading,
tooltipContent,
position = "top",
children,
disabled = false,
className = "",
openDelay = 200,
side = "bottom",
align = "center",
sideOffset = 10,
closeDelay,
isMobile = false,
} = props;
const { finalSide, finalAlign } = React.useMemo(() => {
if (position) {
const converted = convertPlacementToSideAndAlign(position);
return { finalSide: converted.side, finalAlign: converted.align };
}
return { finalSide: side, finalAlign: align };
}, [position, side, align]);
return (
<BaseTooltip.Provider>
<BaseTooltip.Root delay={openDelay} closeDelay={closeDelay} disabled={disabled}>
<BaseTooltip.Trigger render={children} />
<BaseTooltip.Portal>
<BaseTooltip.Positioner
className={cn(
"z-tooltip max-w-xs gap-1 overflow-hidden break-words rounded-md bg-custom-background-100 p-2 text-xs text-custom-text-200 shadow-custom-shadow-xs",
{
hidden: isMobile,
},
className
)}
side={finalSide}
sideOffset={sideOffset}
align={finalAlign}
render={
<BaseTooltip.Popup>
{tooltipHeading && <h5 className="font-medium text-custom-text-100">{tooltipHeading}</h5>}
{tooltipContent}
</BaseTooltip.Popup>
}
/>
</BaseTooltip.Portal>
</BaseTooltip.Root>
</BaseTooltip.Provider>
);
}