// @flow strict import * as React from 'react'; import type {ColorTypes} from '../../types/typography'; import {TEXT_COLORS} from '../../types/typography'; import classify from '../../utils/classify'; import {ConditionalWrapper} from '../ConditionalWrapper'; import type {IconSize, IconType} from '../Icon'; import {Icon, ICON_SIZE} from '../Icon'; import css from '../../styles/typography.module.css'; export const LINK_AS = Object.freeze({ bodyLarge: 'bodyLarge', bodyMedium: 'bodyMedium', bodySmall: 'bodySmall', buttonTextExtraSmall: 'buttonTextExtraSmall', buttonTextMedium: 'buttonTextMedium', buttonTextSmall: 'buttonTextSmall', formInputMedium: 'formInputMedium', formInputSmall: 'formInputSmall', formLabelMedium: 'formLabelMedium', formLabelSmall: 'formLabelSmall', jumboMedium: 'jumboMedium', subTitleExtraSmall: 'subTitleExtraSmall', subTitleLarge: 'subTitleLarge', subTitleMedium: 'subTitleMedium', subTitleSmall: 'subTitleSmall', titleMedium: 'titleMedium', }); export type LinkAs = $Values; export const ANCHOR_REL = Object.freeze({ alternate: 'alternate', author: 'author', bookmark: 'bookmark', external: 'external', help: 'help', license: 'license', next: 'next', nofollow: 'nofollow', noopener: 'noopener', noreferrer: 'noreferrer', search: 'search', tag: 'tag', }); export type AnchorRel = $Values; export const ANCHOR_TARGET = Object.freeze({ _blank: '_blank', _self: '_self', _parent: '_parent', _top: '_top', framename: 'framename', }); export type AnchorTarget = $Values; export type BaseLinkProps = { children: React.Node, onClick?: ?(SyntheticEvent) => mixed, tabIndex?: number, disabled?: boolean, className?: string, as?: LinkAs, rel?: AnchorRel, target?: AnchorTarget, iconLeftName?: string, iconLeftSize?: IconSize, iconLeftType?: IconType, iconRightName?: string, iconRightSize?: IconSize, iconRightType?: IconType, /** * IMPORTANT: If you are using `to` make sure to provide link component from your router * if you want to prevent full page reloads in a Single Page Application (SPA). * * Using `href` in anchor tags causes the browser to navigate to a new URL, * resulting in a full page reload. However, in a Single Page Application (SPA), we aim to provide a seamless * user experience without such reloads. * * To achieve client-side navigation and prevent page reloads, use client-side routing libraries * (e.g., React Router) and their navigation components (e.g., or with an onClick handler) * to handle navigation within your SPA. These components work without triggering full page reloads * and maintain the SPA's performance and user experience. * */ to?: string, href?: string, ... }; export type LinkProps = { ...BaseLinkProps, color?: ColorTypes, underline?: boolean, /** * Provide your router's link component * * import {Link} from 'src/rerouter'; * import {Link as GenesisLink} from '@spaced-out/ui-design-system/lib/components/Link'; * * */ linkComponent?: React.AbstractComponent, ... }; export const Link: React$AbstractComponent = React.forwardRef( ( { color = TEXT_COLORS.clickable, children, className, as = 'buttonTextExtraSmall', underline = true, tabIndex = 0, disabled, onClick, linkComponent: LinkComponent = DefaultLink, iconLeftName, iconLeftSize = ICON_SIZE.small, iconLeftType, iconRightName, iconRightSize = ICON_SIZE.small, iconRightType, ...props }: LinkProps, ref, ) => { const linkRef = React.useRef(null); React.useImperativeHandle(ref, () => linkRef.current); React.useEffect(() => { if (disabled) { linkRef.current?.blur(); } }, [disabled]); const handleClick = (event: SyntheticEvent) => { if (disabled) { event.preventDefault(); return; } onClick?.(event); }; /** * By spec anchor tag wont call onClick on enter key press when the element is focussed * as a workaround we would need to listen to key press event and call onClick * manually, one workaround to avoid this is to have empty href along with onClick * but that would break accessibility */ const handleKeyPress = (event) => { if (event.key === 'Enter' && onClick) { handleClick(event); } }; return ( {!!iconLeftName && ( )} ( {children} )} > {children} {!!iconRightName && ( )} ); }, ); const DefaultLink = React.forwardRef( ({children, href, to, ...props}, ref) => { const resolvedHref = to ?? href; return ( {children} ); }, );