Files
Marko Lisica fb3932f37a Update CustomLink styles (#48838)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #35328

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

## Testing

- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved link hover and `:focus-visible` underline/outline behavior
for more consistent accessibility across tables, buttons, and modals.
  * Fixed script name hover underline clipping in the run script modal.
* **Style**
* Refreshed `CustomLink` styling with an emphasized variant and improved
underline behavior, plus updated related link/table/button styling for a
unified look.
* Updated “Connect Fleet” info-banner messaging and CTAs for calendar
and conditional access automations; refreshed “No scripts available”
empty state.
* **Tests**
  * Updated modal tests to match revised link text and accessible names.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-13 17:07:39 +02:00

113 lines
2.7 KiB
TypeScript

import React from "react";
import Icon from "components/Icon";
import classnames from "classnames";
import { Colors } from "styles/var/colors";
interface ICustomLinkProps {
url?: string;
text: string;
className?: string;
/** open the link in a new tab
* @default false
*/
newTab?: boolean;
/** Emphasizes the link appearance by changing the color to an accent color */
emphasized?: boolean;
/** Icon wraps on new line with last word */
multiline?: boolean;
/** Restricts access via keyboard when CustomLink is part of disabled UI */
disableKeyboardNavigation?: boolean;
/**
* Changes the appearance of the link.
*
* @default "default"
*/
variant?: "tooltip-link" | "banner-link" | "flash-message-link" | "default";
}
const baseClass = "custom-link";
const CustomLink = ({
url,
text,
className,
newTab = false,
multiline = false,
emphasized = false,
disableKeyboardNavigation = false,
variant = "default",
}: ICustomLinkProps): JSX.Element => {
const getIconColor = (): Colors => {
switch (variant) {
case "tooltip-link":
return "core-fleet-white";
case "flash-message-link":
return "core-fleet-black";
case "banner-link":
return "core-fleet-black";
default:
return "ui-fleet-black-75";
}
};
const customLinkClass = classnames(baseClass, className, {
[`${baseClass}--${variant}`]: variant !== "default",
[`${baseClass}--multiline`]: multiline,
[`${baseClass}--emphasized`]: emphasized,
});
// Needed to not trigger clickable parent elements
// e.g. cell/row handlers with a tooltip that has a custom link inside
const handleClick = (e: React.MouseEvent) => {
e.stopPropagation();
};
const target = newTab ? "_blank" : "";
const multilineText = text.substring(0, text.lastIndexOf(" ") + 1);
const lastWord = text.substring(text.lastIndexOf(" ") + 1, text.length);
const content = multiline ? (
<>
{multilineText}
<span className={`${baseClass}__no-wrap`}>
<span className={`${baseClass}__last-word`}>{lastWord}</span>
{newTab && (
<Icon
name="external-link"
className={`${baseClass}__external-icon`}
color={getIconColor()}
/>
)}
</span>
</>
) : (
<>
{text}
{newTab && (
<Icon
name="external-link"
className={`${baseClass}__external-icon`}
color={getIconColor()}
/>
)}
</>
);
return (
<a
href={url}
target={target}
rel="noopener noreferrer"
className={customLinkClass}
tabIndex={disableKeyboardNavigation ? -1 : 0}
onClick={handleClick}
>
{content}
</a>
);
};
export default CustomLink;