Skip to content

Commit ec9131b

Browse files
committed
TextLink now supports optional shortcuts
1 parent a22e189 commit ec9131b

File tree

1 file changed

+53
-5
lines changed

1 file changed

+53
-5
lines changed

apps/webapp/app/components/primitives/TextLink.tsx

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { Link } from "@remix-run/react";
22
import { cn } from "~/utils/cn";
33
import { Icon, type RenderIcon } from "./Icon";
4+
import { useRef } from "react";
5+
import { type ShortcutDefinition, useShortcutKeys } from "~/hooks/useShortcutKeys";
6+
import { ShortcutKey } from "./ShortcutKey";
7+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./Tooltip";
48

59
const variations = {
610
primary:
@@ -17,6 +21,9 @@ type TextLinkProps = {
1721
trailingIconClassName?: string;
1822
variant?: keyof typeof variations;
1923
children: React.ReactNode;
24+
shortcut?: ShortcutDefinition;
25+
hideShortcutKey?: boolean;
26+
tooltip?: React.ReactNode;
2027
} & React.AnchorHTMLAttributes<HTMLAnchorElement>;
2128

2229
export function TextLink({
@@ -27,20 +34,61 @@ export function TextLink({
2734
trailingIcon,
2835
trailingIconClassName,
2936
variant = "primary",
37+
shortcut,
38+
hideShortcutKey,
39+
tooltip,
3040
...props
3141
}: TextLinkProps) {
42+
const innerRef = useRef<HTMLAnchorElement>(null);
3243
const classes = variations[variant];
33-
return to ? (
34-
<Link to={to} className={cn(classes, className)} {...props}>
44+
45+
if (shortcut) {
46+
useShortcutKeys({
47+
shortcut: shortcut,
48+
action: () => {
49+
if (innerRef.current) {
50+
innerRef.current.click();
51+
}
52+
},
53+
});
54+
}
55+
56+
const renderShortcutKey = () =>
57+
shortcut &&
58+
!hideShortcutKey && <ShortcutKey className="ml-1.5" shortcut={shortcut} variant="small" />;
59+
60+
const linkContent = (
61+
<>
3562
{children}{" "}
3663
{trailingIcon && <Icon icon={trailingIcon} className={cn("size-4", trailingIconClassName)} />}
64+
{shortcut && !tooltip && renderShortcutKey()}
65+
</>
66+
);
67+
68+
const linkElement = to ? (
69+
<Link ref={innerRef} to={to} className={cn(classes, className)} {...props}>
70+
{linkContent}
3771
</Link>
3872
) : href ? (
39-
<a href={href} className={cn(classes, className)} {...props}>
40-
{children}{" "}
41-
{trailingIcon && <Icon icon={trailingIcon} className={cn("size-4", trailingIconClassName)} />}
73+
<a ref={innerRef} href={href} className={cn(classes, className)} {...props}>
74+
{linkContent}
4275
</a>
4376
) : (
4477
<span>Need to define a path or href</span>
4578
);
79+
80+
if (tooltip) {
81+
return (
82+
<TooltipProvider>
83+
<Tooltip>
84+
<TooltipTrigger asChild>{linkElement}</TooltipTrigger>
85+
<TooltipContent className="text-dimmed flex items-center gap-3 py-1.5 pl-2.5 pr-3 text-xs">
86+
{tooltip} {shortcut && renderShortcutKey()}
87+
</TooltipContent>
88+
</Tooltip>
89+
</TooltipProvider>
90+
);
91+
}
92+
93+
return linkElement;
4694
}

0 commit comments

Comments
 (0)