import { ReactNode } from 'react'; import btoa from 'btoa'; import styled, { css } from 'styled-components'; import { color, SpaceProps, TextColorProps } from 'styled-system'; import { getThemeColor, hexToRgb, ThemeProps } from '@t3n/theme'; import { LinkStyle } from '@t3n/theme/src/theme/linkStyles'; import { TextProps, textStyle } from '../Text'; export type LinkVariantType = 'primary' | 'secondary' | 'highlight' | 'inverse'; export interface LinkProps extends TextColorProps, SpaceProps { small?: TextProps['small']; disabled?: boolean; variant?: LinkVariantType; children: ReactNode; } export type LinkState = 'default' | 'hover' | 'focus' | 'visited'; const underline = (rgbColor: string) => `background-image: url('data:image/svg+xml;base64,${btoa( ``, )}');`; const underlineColor = (value: string) => ({ theme }: ThemeProps) => { const c = getThemeColor(value)({ theme }) || value; if (/^rgb/.test(c)) return c; if (/^#/.test(c)) return hexToRgb(c); return 'rgb(255,255,255)'; }; export const createLinkStyle = (linkStyleConfig: LinkStyle) => css< Omit >` ${({ theme }) => color({ color: linkStyleConfig.default.color, theme })} ${({ theme, disabled }) => disabled ? '' : underline( underlineColor(linkStyleConfig.default.underlineColor)({ theme }), )} &:hover { ${({ theme }) => color({ color: linkStyleConfig.hover.color, theme })} ${({ theme }: ThemeProps) => underline( underlineColor(linkStyleConfig.hover.underlineColor)({ theme }), )} } &:focus { ${({ theme }) => color({ color: linkStyleConfig.focus.color, theme })} ${({ theme }: ThemeProps) => underline( underlineColor(linkStyleConfig.focus.underlineColor)({ theme }), )} } &:visited { ${({ theme }) => color({ color: linkStyleConfig.visited.color, theme })} ${({ theme }: ThemeProps) => underline( underlineColor(linkStyleConfig.visited.underlineColor)({ theme }), )} &:focus { ${({ theme }) => color({ color: linkStyleConfig.focus.color, theme })} ${({ theme }: ThemeProps) => underline( underlineColor(linkStyleConfig.focus.underlineColor)({ theme }), )} } } `; export const linkStyle = css` text-decoration: none; pointer-events: ${({ disabled }) => (disabled ? 'none' : 'auto')}; opacity: ${({ disabled }) => (disabled ? 0.5 : 1)}; background-repeat: repeat-x; background-size: 1px 1px; background-position: 0 100%; cursor: pointer; ${textStyle} ${({ variant: variantProp, theme }) => { switch (variantProp) { case 'secondary': return createLinkStyle(theme.linkStyles.secondary); case 'inverse': return createLinkStyle(theme.linkStyles.inverse); case 'highlight': return createLinkStyle(theme.linkStyles.highlight); default: return createLinkStyle(theme.linkStyles.primary); } }} `; const Link = styled.a.attrs((props) => ({ variant: 'primary', ...props, }))` ${linkStyle} `; export default Link;