Skip to content

Commit 0ed397b

Browse files
authored
fix(UI-1863): fix info popover not-displayed in triggers and connections tables (#1315)
## Description # Fix IconButton ref forwarding for popover functionality ## Problem Popovers were not displaying correctly in triggers and connections tables due to a React ref forwarding issue. The console showed warnings: ``` Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()? ``` This prevented the popover library from properly positioning and displaying popover content when hovering over info icons. ## Root Cause The `IconButton` component was not using `React.forwardRef()`, which meant that when `PopoverTrigger` with `asChild` prop tried to pass a ref to the IconButton, it failed. This broke the popover positioning mechanism that relies on getting a reference to the trigger element. ## Solution Implemented a **combined approach** that takes the best aspects of both comprehensive and minimal solutions: ### Key Changes 1. **Added proper ref forwarding to IconButton** - Used `React.forwardRef<HTMLButtonElement | HTMLAnchorElement>` for correct TypeScript types - Supports both button and link rendering scenarios - Maintains backward compatibility 2. **Enhanced Link component with minimal ref support** - Added `React.forwardRef` to Link component - Keeps interface simple and focused 3. **Maintained type safety** - Proper union types prevent future TypeScript errors - Future-proof design without over-engineering ## Linear Ticket https://linear.app/autokitteh/issue/UI-1863/fix-info-popover-display-in-triggers-and-connections-tables ## What type of PR is this? (check all applicable) - [ ] 💡 (feat) - A new feature (non-breaking change which adds functionality) - [ ] 🔄 (refactor) - Code Refactoring - A code change that neither fixes a bug nor adds a feature - [x] 🐞 (fix) - Bug Fix (non-breaking change which fixes an issue) - [ ] 🏎 (perf) - Optimization - [ ] 📄 (docs) - Documentation - Documentation only changes - [ ] 📄 (test) - Tests - Adding missing tests or correcting existing tests - [ ] 🎨 (style) - Styles - Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) - [ ] ⚙️ (ci) - Continuous Integrations - Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs) - [ ] ☑️ (chore) - Chores - Other changes that don't modify src or test files - [ ] ↩️ (revert) - Reverts - Reverts a previous commit(s). <!-- For a timely review/response, please avoid force-pushing additional commits if your PR already received reviews or comments. Before submitting a Pull Request, please ensure you've done the following: - 👷‍♀️ Create small PRs. In most cases this will be possible. - ✅ Provide tests for your changes. - 📝 Use descriptive commit messages (as described below). - 📗 Update any related documentation and include any relevant screenshots. Commit Message Structure (all lower-case): <type>(optional ticket number): <description> [optional body] -->
1 parent ed3cd2f commit 0ed397b

File tree

4 files changed

+91
-61
lines changed

4 files changed

+91
-61
lines changed

public/grammars/python.tmLanguage.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4210,4 +4210,4 @@
42104210
]
42114211
}
42124212
}
4213-
}
4213+
}

src/components/atoms/buttons/iconButton.tsx

Lines changed: 64 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,53 +6,71 @@ import { cn } from "@utilities";
66

77
import { Link } from "@components/atoms";
88

9-
export const IconButton = ({
10-
ariaLabel,
11-
children,
12-
className,
13-
disabled,
14-
href,
15-
onClick,
16-
onKeyDown,
17-
onMouseEnter,
18-
onMouseLeave,
19-
title,
20-
type = "button",
21-
variant,
22-
id,
23-
}: IconButtonProps) => {
24-
const iconButtonClass = cn(
25-
"flex shrink-0 items-center justify-center rounded-full p-2 outline-0 transition duration-300 hover:bg-gray-850",
9+
export const IconButton = React.forwardRef<HTMLButtonElement | HTMLAnchorElement, IconButtonProps>(
10+
(
2611
{
27-
"bg-black": variant === ButtonVariant.filled,
28-
"border border-gray-750 hover:border-transparent": variant === ButtonVariant.outline,
29-
"cursor-not-allowed opacity-40": disabled,
30-
"hover:border-gray-750": disabled && variant === ButtonVariant.outline,
31-
"hover:bg-transparen border hover:border-black/50": variant === ButtonVariant.flatText,
12+
ariaLabel,
13+
children,
14+
className,
15+
disabled,
16+
href,
17+
onClick,
18+
onKeyDown,
19+
onMouseEnter,
20+
onMouseLeave,
21+
title,
22+
type = "button",
23+
variant,
24+
id,
3225
},
33-
className
34-
);
26+
ref
27+
) => {
28+
const iconButtonClass = cn(
29+
"flex shrink-0 items-center justify-center rounded-full p-2 outline-0 transition duration-300 hover:bg-gray-850",
30+
{
31+
"bg-black": variant === ButtonVariant.filled,
32+
"border border-gray-750 hover:border-transparent": variant === ButtonVariant.outline,
33+
"cursor-not-allowed opacity-40": disabled,
34+
"hover:border-gray-750": disabled && variant === ButtonVariant.outline,
35+
"hover:bg-transparen border hover:border-black/50": variant === ButtonVariant.flatText,
36+
},
37+
className
38+
);
3539

36-
const Component = href ? Link : "button";
37-
const linkHref = href ? { to: href } : { to: "" };
40+
if (href) {
41+
return (
42+
<Link
43+
ariaLabel={ariaLabel}
44+
className={iconButtonClass}
45+
id={id}
46+
ref={ref as React.ForwardedRef<HTMLAnchorElement>}
47+
title={title}
48+
to={href}
49+
>
50+
{children}
51+
</Link>
52+
);
53+
}
3854

39-
return (
40-
<Component
41-
aria-label={ariaLabel}
42-
className={iconButtonClass}
43-
disabled={disabled}
44-
onClick={onClick}
45-
onKeyDown={onKeyDown}
46-
onMouseEnter={onMouseEnter}
47-
onMouseLeave={onMouseLeave}
48-
role="button"
49-
tabIndex={0}
50-
title={title}
51-
type={type}
52-
{...linkHref}
53-
id={id}
54-
>
55-
{children}
56-
</Component>
57-
);
58-
};
55+
return (
56+
<button
57+
aria-label={ariaLabel}
58+
className={iconButtonClass}
59+
disabled={disabled}
60+
id={id}
61+
onClick={onClick}
62+
onKeyDown={onKeyDown}
63+
onMouseEnter={onMouseEnter}
64+
onMouseLeave={onMouseLeave}
65+
ref={ref as React.ForwardedRef<HTMLButtonElement>}
66+
tabIndex={0}
67+
title={title}
68+
type={type}
69+
>
70+
{children}
71+
</button>
72+
);
73+
}
74+
);
75+
76+
IconButton.displayName = "IconButton";

src/components/atoms/link.tsx

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,29 @@ import { Link as LinkReact } from "react-router-dom";
55
import { LinkProps } from "@interfaces/components";
66
import { cn } from "@utilities";
77

8-
export const Link = ({ ariaLabel, children, className, disabled, target, title, to, id }: LinkProps) => {
9-
const linkClass = cn(
10-
{
11-
"pointer-events-none cursor-not-allowed select-none": disabled,
12-
},
13-
className
14-
);
8+
export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
9+
({ ariaLabel, children, className, disabled, target, title, to, id }, ref) => {
10+
const linkClass = cn(
11+
{
12+
"pointer-events-none cursor-not-allowed select-none": disabled,
13+
},
14+
className
15+
);
1516

16-
return (
17-
<LinkReact aria-label={ariaLabel} className={linkClass} id={id} target={target} title={title} to={to}>
18-
{children}
19-
</LinkReact>
20-
);
21-
};
17+
return (
18+
<LinkReact
19+
aria-label={ariaLabel}
20+
className={linkClass}
21+
id={id}
22+
ref={ref}
23+
target={target}
24+
title={title}
25+
to={to}
26+
>
27+
{children}
28+
</LinkReact>
29+
);
30+
}
31+
);
32+
33+
Link.displayName = "Link";

src/components/organisms/tour/tourPopover.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export const TourPopover = ({
6060
onSkip?.();
6161
};
6262

63-
const popoverClassName = cn("z-[100] w-80 rounded-lg bg-gray-850 p-4 text-white shadow-lg", { hidden: !visible });
63+
const popoverClassName = cn("z-overlay w-80 rounded-lg bg-gray-850 p-4 text-white shadow-lg", { hidden: !visible });
6464

6565
return (
6666
<PopoverContext.Provider value={popover}>

0 commit comments

Comments
 (0)