import Link from 'next/link'; import React, { forwardRef, ReactNode, useCallback, useMemo, useState, } from 'react'; import { StyleSheet, Text as RNText, TextProps as RNTextProps, } from 'react-native'; import { UrlObject } from 'url'; import { useStyles } from '../hooks/useStyles'; import { useTheme } from '../hooks/useTheme'; import { Theme } from '../themes/theme'; const createStyles = (theme: Theme) => ({ h1: { ...theme.fontSize.big, color: theme.color.background, marginBottom: theme.spacing.medium, }, h2: { ...theme.fontSize.medium, color: theme.color.background, fontWeight: theme.fontWeight.medium, marginBottom: theme.spacing.medium, }, text: { ...theme.fontSize.medium, color: theme.color.background, }, p: { ...theme.fontSize.medium, color: theme.color.background, marginBottom: theme.spacing.medium, }, small: { ...theme.fontSize.small, color: theme.color.background, }, smallRed: { ...theme.fontSize.small, color: theme.color.red, }, smallBold: { ...theme.fontSize.small, color: theme.color.background, fontWeight: theme.fontWeight.medium, }, smallBoldRed: { ...theme.fontSize.small, color: theme.color.red, fontWeight: theme.fontWeight.medium, }, li: { ...theme.fontSize.medium, color: theme.color.background, marginBottom: theme.spacing.small, }, link: { ...theme.fontSize.medium, color: theme.color.blue, }, code: { ...theme.fontSize.small, fontFamily: theme.fontFamily.monospace, }, // Consolas, ‘Andale Mono WT’, ‘Andale Mono’, ‘Lucida Console’, ‘Lucida Sans Typewriter’, ‘DejaVu Sans Mono’, ‘Bitstream Vera Sans Mono’, ‘Liberation Mono’, ‘Nimbus Mono L’, Monaco, ‘Courier New’, Courier, monospace }); /** * It's like Next LinkProps except href is optional and passHref with prefetch not allowed. * The idea is simple. Because anchor is rendered via Text in RNfW, * we just added Next Link functionality into Text. * We had to copy-paste LinkProps, because props must be handled explicitly. */ interface TextNextLinkProps { href?: string | UrlObject; as?: string | UrlObject; replace?: boolean; scroll?: boolean; shallow?: boolean; // Next.js auto-prefetches automatically based on viewport. The prefetch attribute is // no longer needed. More: https://err.sh/zeit/next.js/prefetch-true-deprecated // prefetch?: boolean; } interface TextOwnProps { variant: keyof ReturnType; color?: keyof Theme['color']; children: ReactNode; } export type TextProps = RNTextProps & TextNextLinkProps & TextOwnProps; const styles = StyleSheet.create({ linkHover: { textDecorationLine: 'underline', }, }); const RNTextWithDOMRef = forwardRef( (props: RNTextProps & { children: ReactNode }, ref) => { return ( ); }, ); // TODO: isExternal auto-detection then Platform.select({ web: { href, target: '_blank' } }). export const Text = ({ // TextNextLinkProps href, as, replace, scroll, shallow, // TextOwnProps variant, color, children, ...props }: TextProps) => { const variantStyle = useStyles(createStyles)[variant]; const theme = useTheme(); const colorStyle = useMemo( () => color && StyleSheet.create({ color: { color: theme.color[color] } }).color, [color, theme.color], ); const [hasHover, setHasHover] = useState(false); const onMouseEnter = useCallback(() => { setHasHover(true); }, []); const onMouseLeave = useCallback(() => { setHasHover(false); }, []); const text = ( {children || '…'} ); if (!href) return text; return {text}; };