ui: Tooltip style fixes

* Remove offset, using margin instead. This means
  we're specifying the gap between the tooltip
  _box_ and its target, rather than the gap
  between the tooltip _arrow_ and its target.
* Fix missing assignments of the --origin variable
  which broke the enter/leave animations of the
  tooltip.
* Introduce some CSS variables to remove magic
  numbers so that the styling is easier to adjust
  in the future.
* Remove `fill: canvas` in the light theme which
  caused the tooltip arrow background to be
  hardcoded to white regardless of theme.
* Reorganize stylesheet to bring related styles
  closer together.

Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com>
This commit is contained in:
MT Lewis
2025-07-21 10:26:02 +01:00
parent a8f3aa0507
commit 335c8942ab
3 changed files with 91 additions and 58 deletions
+38 -23
View File
@@ -10512,6 +10512,7 @@
font-size: var(--bui-font-size-3);
font-family: var(--bui-font-regular);
color: var(--bui-fg-primary);
--tooltip-offset: var(--bui-space-3);
border-radius: 4px;
outline: none;
transition: transform .2s, opacity .2s;
@@ -10522,45 +10523,59 @@
transform: var(--origin);
opacity: 0;
}
&[data-placement="top"] {
margin-bottom: var(--tooltip-offset);
--origin: translateY(4px);
}
&[data-placement="right"] {
margin-left: var(--tooltip-offset);
--origin: translateX(-4px);
}
&[data-placement="bottom"] {
margin-top: var(--tooltip-offset);
--origin: translateY(-4px);
}
&[data-placement="left"] {
margin-right: var(--tooltip-offset);
--origin: translateX(4px);
}
}
.bui-TooltipArrow {
& svg {
--tooltip-arrow-overlap: -2px;
display: block;
}
&[data-placement="top"] {
transform: translateY(4px);
& path:first-child {
fill: var(--bui-bg-surface-1);
}
& svg {
transform: translateY(-2px);
& path:nth-child(2) {
fill: var(--bui-gray-3);
}
}
&[data-placement="bottom"] {
& svg {
transform: rotate(180deg)translateY(-2px);
}
&[data-placement="top"] svg {
margin-top: var(--tooltip-arrow-overlap);
}
&[data-placement="right"] {
& svg {
transform: rotate(90deg)translateY(-7px);
}
&[data-placement="bottom"] svg {
margin-bottom: var(--tooltip-arrow-overlap);
transform: rotate(180deg);
}
&[data-placement="left"] {
& svg {
transform: rotate(-90deg)translateY(-7px);
}
&[data-placement="right"] svg {
margin-right: var(--tooltip-arrow-overlap);
transform: rotate(90deg);
}
& svg path:first-child {
fill: canvas;
}
& svg path:nth-child(2) {
fill: var(--bui-gray-3);
&[data-placement="left"] svg {
margin-left: var(--tooltip-arrow-overlap);
transform: rotate(-90deg);
}
}
@@ -36,52 +36,71 @@
transform: var(--origin);
opacity: 0;
}
}
.bui-TooltipArrow {
svg {
display: block;
/* The tooltip is rendered overlaying the main
tooltip element by 1px. This causes the borders
to overlap, which causes minor visual artifacts
with transparent border colors. To mitigate this,
we split the stroke and fill across separate
elements in order to guarantee that the stroke is
always overlaying a consistent color. */
}
--tooltip-offset: var(--bui-space-3);
&[data-placement='top'] {
transform: translateY(4px);
& svg {
transform: translateY(-2px);
}
}
&[data-placement='bottom'] {
& svg {
transform: rotate(180deg) translateY(-2px);
}
margin-bottom: var(--tooltip-offset);
--origin: translateY(4px);
}
&[data-placement='right'] {
& svg {
transform: rotate(90deg) translateY(-7px);
}
margin-left: var(--tooltip-offset);
--origin: translateX(-4px);
}
&[data-placement='bottom'] {
margin-top: var(--tooltip-offset);
--origin: translateY(-4px);
}
&[data-placement='left'] {
& svg {
transform: rotate(-90deg) translateY(-7px);
margin-right: var(--tooltip-offset);
--origin: translateX(4px);
}
}
.bui-TooltipArrow {
& svg {
display: block;
/* The tooltip is rendered overlaying the main
tooltip element by 1px. This causes the borders
to overlap, which causes minor visual artifacts
with transparent border colors. To mitigate this,
we split the stroke and fill across separate
elements in order to guarantee that the stroke is
always overlaying a consistent color. */
path:nth-child(1) {
fill: var(--bui-bg-surface-1);
}
path:nth-child(2) {
fill: var(--bui-gray-3);
}
/* The arrow svg overlaps the tooltip by 2px, so we
need to adjust the margins accordingly. */
--tooltip-arrow-overlap: -2px;
}
svg path:nth-child(1) {
fill: canvas;
&[data-placement='top'] svg {
margin-top: var(--tooltip-arrow-overlap);
}
svg path:nth-child(2) {
fill: var(--bui-gray-3);
&[data-placement='bottom'] svg {
margin-bottom: var(--tooltip-arrow-overlap);
transform: rotate(180deg);
}
&[data-placement='right'] svg {
margin-right: var(--tooltip-arrow-overlap);
transform: rotate(90deg);
}
&[data-placement='left'] svg {
margin-left: var(--tooltip-arrow-overlap);
transform: rotate(-90deg);
}
}
@@ -34,18 +34,17 @@ export const TooltipTrigger = (props: TooltipTriggerComponentProps) => {
/** @public */
export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
({ className, children, offset = 12, ...rest }, ref) => {
({ className, children, ...rest }, ref) => {
const { classNames } = useStyles('Tooltip');
return (
<AriaTooltip
className={clsx(classNames.tooltip, className)}
offset={offset}
{...rest}
ref={ref}
>
<OverlayArrow className={classNames.arrow}>
<svg width="20" height="10" viewBox="0 0 20 10" fill="none">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
<path d="M10.3356 7.39793L15.1924 3.02682C15.9269 2.36577 16.8801 2 17.8683 2H20V7.94781e-07L1.74846e-07 -9.53674e-07L0 2L1.4651 2C2.4532 2 3.4064 2.36577 4.1409 3.02682L8.9977 7.39793C9.378 7.7402 9.9553 7.74021 10.3356 7.39793Z" />
<path d="M11.0046 8.14124C10.2439 8.82575 9.08939 8.82578 8.32869 8.14122L3.47189 3.77011C2.92109 3.27432 2.20619 2.99999 1.46509 2.99999L4.10999 3L8.99769 7.39793C9.37799 7.7402 9.95529 7.7402 10.3356 7.39793L15.2226 3L17.8683 2.99999C17.1271 2.99999 16.4122 3.27432 15.8614 3.77011L11.0046 8.14124Z" />
</svg>