Commit 50676eb5 authored by tom's avatar tom

link overlay component

parent 2fff1760
...@@ -32,8 +32,8 @@ const RESTRICTED_MODULES = { ...@@ -32,8 +32,8 @@ const RESTRICTED_MODULES = {
{ {
name: '@chakra-ui/react', name: '@chakra-ui/react',
importNames: [ importNames: [
'Menu', 'useToast', 'useDisclosure', 'useClipboard', 'Tooltip', 'Skeleton', 'IconButton', 'Button', 'ButtonGroup', 'Link', 'Tag', 'Switch', 'Menu', 'useToast', 'useDisclosure', 'useClipboard', 'Tooltip', 'Skeleton', 'IconButton', 'Button', 'ButtonGroup', 'Link', 'LinkBox', 'LinkOverlay',
'Image', 'Popover', 'PopoverTrigger', 'PopoverContent', 'PopoverBody', 'PopoverFooter', 'Tag', 'Switch', 'Image', 'Popover', 'PopoverTrigger', 'PopoverContent', 'PopoverBody', 'PopoverFooter',
'DrawerRoot', 'DrawerBody', 'DrawerContent', 'DrawerOverlay', 'DrawerBackdrop', 'DrawerTrigger', 'Drawer', 'DrawerRoot', 'DrawerBody', 'DrawerContent', 'DrawerOverlay', 'DrawerBackdrop', 'DrawerTrigger', 'Drawer',
'Alert', 'AlertIcon', 'AlertTitle', 'AlertDescription', 'Alert', 'AlertIcon', 'AlertTitle', 'AlertDescription',
'Heading', 'Badge', 'Tabs', 'Show', 'Hide', 'Checkbox', 'Heading', 'Badge', 'Tabs', 'Show', 'Hide', 'Checkbox',
......
import type { LinkProps as ChakraLinkProps } from '@chakra-ui/react'; import type { LinkProps as ChakraLinkProps } from '@chakra-ui/react';
import { Link as ChakraLink } from '@chakra-ui/react'; import { Link as ChakraLink, LinkBox as ChakraLinkBox, LinkOverlay as ChakraLinkOverlay } from '@chakra-ui/react';
import NextLink from 'next/link'; import NextLink from 'next/link';
import type { LinkProps as NextLinkProps } from 'next/link'; import type { LinkProps as NextLinkProps } from 'next/link';
import React from 'react'; import React from 'react';
...@@ -21,7 +21,7 @@ export const LinkExternalIcon = ({ color }: { color?: ChakraLinkProps['color'] } ...@@ -21,7 +21,7 @@ export const LinkExternalIcon = ({ color }: { color?: ChakraLinkProps['color'] }
/> />
); );
export interface LinkProps extends Pick<NextLinkProps, 'shallow' | 'prefetch' | 'scroll'>, ChakraLinkProps { interface LinkPropsChakra extends ChakraLinkProps {
loading?: boolean; loading?: boolean;
external?: boolean; external?: boolean;
iconColor?: ChakraLinkProps['color']; iconColor?: ChakraLinkProps['color'];
...@@ -29,9 +29,28 @@ export interface LinkProps extends Pick<NextLinkProps, 'shallow' | 'prefetch' | ...@@ -29,9 +29,28 @@ export interface LinkProps extends Pick<NextLinkProps, 'shallow' | 'prefetch' |
disabled?: boolean; disabled?: boolean;
} }
interface LinkPropsNext extends Pick<NextLinkProps, 'shallow' | 'prefetch' | 'scroll'> {}
export interface LinkProps extends LinkPropsChakra, LinkPropsNext {}
const splitProps = (props: LinkProps): { chakra: LinkPropsChakra; next: NextLinkProps } => {
const { scroll = true, shallow = false, prefetch = false, ...rest } = props;
return {
chakra: rest,
next: {
href: rest.href as NextLinkProps['href'],
scroll,
shallow,
prefetch,
},
};
};
export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>( export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
function Link(props, ref) { function Link(props, ref) {
const { external, loading, href, children, scroll = true, iconColor, noIcon, shallow, prefetch = false, disabled, ...rest } = props; const { chakra, next } = splitProps(props);
const { external, loading, href, children, disabled, noIcon, iconColor, ...rest } = chakra;
if (external) { if (external) {
return ( return (
...@@ -60,13 +79,8 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>( ...@@ -60,13 +79,8 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
{ ...(disabled ? { 'data-disabled': true } : {}) } { ...(disabled ? { 'data-disabled': true } : {}) }
{ ...rest } { ...rest }
> >
{ href ? ( { next.href ? (
<NextLink <NextLink { ...next }>
href={ href as NextLinkProps['href'] }
scroll={ scroll }
shallow={ shallow }
prefetch={ prefetch }
>
{ children } { children }
</NextLink> </NextLink>
) : ) :
...@@ -77,3 +91,26 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>( ...@@ -77,3 +91,26 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
); );
}, },
); );
export const LinkBox = ChakraLinkBox;
export const LinkOverlay = React.forwardRef<HTMLAnchorElement, LinkProps>(
function LinkOverlay(props, ref) {
const { chakra, next } = splitProps(props);
const { children, external, ...rest } = chakra;
if (external) {
return (
<ChakraLinkOverlay ref={ ref } target="_blank" rel="noopener noreferrer" { ...rest }>
{ children }
</ChakraLinkOverlay>
);
}
return (
<ChakraLinkOverlay ref={ ref } asChild={ Boolean(next.href) } { ...rest }>
{ next.href ? <NextLink { ...next }>{ children }</NextLink> : children }
</ChakraLinkOverlay>
);
},
);
import { LinkBox, Flex, LinkOverlay, Text } from '@chakra-ui/react'; import { Flex, Text } from '@chakra-ui/react';
import type { MouseEvent } from 'react'; import type { MouseEvent } from 'react';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { MarketplaceAppPreview } from 'types/client/marketplace'; import type { MarketplaceAppPreview } from 'types/client/marketplace';
import { route } from 'nextjs-routes';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import { useColorModeValue } from 'toolkit/chakra/color-mode'; import { useColorModeValue } from 'toolkit/chakra/color-mode';
import { IconButton } from 'toolkit/chakra/icon-button'; import { IconButton } from 'toolkit/chakra/icon-button';
import { Image } from 'toolkit/chakra/image'; import { Image } from 'toolkit/chakra/image';
import { Link } from 'toolkit/chakra/link'; import { Link, LinkBox, LinkOverlay } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton'; import { Skeleton } from 'toolkit/chakra/skeleton';
import NextLink from 'ui/shared/NextLink';
import FavoriteIcon from '../FavoriteIcon'; import FavoriteIcon from '../FavoriteIcon';
import MarketplaceAppIntegrationIcon from '../MarketplaceAppIntegrationIcon'; import MarketplaceAppIntegrationIcon from '../MarketplaceAppIntegrationIcon';
...@@ -60,7 +61,7 @@ const FeaturedApp = ({ ...@@ -60,7 +61,7 @@ const FeaturedApp = ({
} }
return ( return (
<LinkBox role="group"> <LinkBox>
<Flex <Flex
gap={ 6 } gap={ 6 }
borderRadius="md" borderRadius="md"
...@@ -94,17 +95,13 @@ const FeaturedApp = ({ ...@@ -94,17 +95,13 @@ const FeaturedApp = ({
fontFamily="heading" fontFamily="heading"
lineHeight="36px" lineHeight="36px"
> >
{ external ? ( <LinkOverlay
<LinkOverlay href={ url } target="_blank" marginRight={ 2 }> href={ external ? url : route({ pathname: '/apps/[id]', query: { id } }) }
{ title } marginRight={ 2 }
</LinkOverlay> external={ external }
) : ( >
<NextLink href={{ pathname: '/apps/[id]', query: { id } }} passHref legacyBehavior>
<LinkOverlay marginRight={ 2 }>
{ title } { title }
</LinkOverlay> </LinkOverlay>
</NextLink>
) }
<MarketplaceAppIntegrationIcon external={ external } internalWallet={ internalWallet }/> <MarketplaceAppIntegrationIcon external={ external } internalWallet={ internalWallet }/>
</Skeleton> </Skeleton>
......
import { LinkBox, Flex, Text } from '@chakra-ui/react'; import { Flex, Text } from '@chakra-ui/react';
import type { MouseEvent } from 'react'; import type { MouseEvent } from 'react';
import React from 'react'; import React from 'react';
...@@ -7,7 +7,7 @@ import type { MarketplaceAppPreview } from 'types/client/marketplace'; ...@@ -7,7 +7,7 @@ import type { MarketplaceAppPreview } from 'types/client/marketplace';
import { useColorModeValue } from 'toolkit/chakra/color-mode'; import { useColorModeValue } from 'toolkit/chakra/color-mode';
import { IconButton } from 'toolkit/chakra/icon-button'; import { IconButton } from 'toolkit/chakra/icon-button';
import { Image } from 'toolkit/chakra/image'; import { Image } from 'toolkit/chakra/image';
import { Link } from 'toolkit/chakra/link'; import { Link, LinkBox } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton'; import { Skeleton } from 'toolkit/chakra/skeleton';
import FavoriteIcon from '../FavoriteIcon'; import FavoriteIcon from '../FavoriteIcon';
......
import { LinkBox, chakra, Flex, Text } from '@chakra-ui/react'; import { chakra, Flex, Text } from '@chakra-ui/react';
import type { MouseEvent } from 'react'; import type { MouseEvent } from 'react';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
...@@ -9,7 +9,7 @@ import isBrowser from 'lib/isBrowser'; ...@@ -9,7 +9,7 @@ import isBrowser from 'lib/isBrowser';
import { useColorModeValue } from 'toolkit/chakra/color-mode'; import { useColorModeValue } from 'toolkit/chakra/color-mode';
import { IconButton } from 'toolkit/chakra/icon-button'; import { IconButton } from 'toolkit/chakra/icon-button';
import { Image } from 'toolkit/chakra/image'; import { Image } from 'toolkit/chakra/image';
import { Link } from 'toolkit/chakra/link'; import { Link, LinkBox } from 'toolkit/chakra/link';
import { Skeleton } from 'toolkit/chakra/skeleton'; import { Skeleton } from 'toolkit/chakra/skeleton';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
......
import { LinkOverlay, chakra } from '@chakra-ui/react'; import { chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { MouseEvent } from 'react'; import type { MouseEvent } from 'react';
import NextLink from 'ui/shared/NextLink'; import { route } from 'nextjs-routes';
import { LinkOverlay } from 'toolkit/chakra/link';
type Props = { type Props = {
id: string; id: string;
...@@ -18,17 +20,16 @@ const MarketplaceAppCardLink = ({ url, external, id, title, onClick, className } ...@@ -18,17 +20,16 @@ const MarketplaceAppCardLink = ({ url, external, id, title, onClick, className }
onClick?.(event, id); onClick?.(event, id);
}, [ onClick, id ]); }, [ onClick, id ]);
// TODO @tom2drum create LinkOverlay component return (
return external ? ( <LinkOverlay
<LinkOverlay href={ url } marginRight={ 2 } className={ className } target="_blank"> href={ external ? url : route({ pathname: '/apps/[id]', query: { id } }) }
{ title } marginRight={ 2 }
</LinkOverlay> className={ className }
) : ( external={ external }
<NextLink href={{ pathname: '/apps/[id]', query: { id } }} passHref legacyBehavior> onClick={ handleClick }
<LinkOverlay onClick={ handleClick } marginRight={ 2 } className={ className }> >
{ title } { title }
</LinkOverlay> </LinkOverlay>
</NextLink>
); );
}; };
......
import { chakra, LinkOverlay } from '@chakra-ui/react'; import { chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { LinkOverlay } from 'toolkit/chakra/link';
import { mediaStyleProps } from './utils'; import { mediaStyleProps } from './utils';
interface Props { interface Props {
......
...@@ -10,7 +10,7 @@ import * as blockMock from 'mocks/blocks/block'; ...@@ -10,7 +10,7 @@ import * as blockMock from 'mocks/blocks/block';
import * as ensMock from 'mocks/ens/domain'; import * as ensMock from 'mocks/ens/domain';
import * as poolMock from 'mocks/pools/pool'; import * as poolMock from 'mocks/pools/pool';
import * as txMock from 'mocks/txs/tx'; import * as txMock from 'mocks/txs/tx';
import { Link } from 'toolkit/chakra/link'; import { Link, LinkBox, LinkOverlay } from 'toolkit/chakra/link';
import CutLinkDetails from 'toolkit/components/CutLink/CutLinkDetails'; import CutLinkDetails from 'toolkit/components/CutLink/CutLinkDetails';
import CutLinkList from 'toolkit/components/CutLink/CutLinkList'; import CutLinkList from 'toolkit/components/CutLink/CutLinkList';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
...@@ -249,6 +249,22 @@ const LinkShowcase = () => { ...@@ -249,6 +249,22 @@ const LinkShowcase = () => {
<PoolEntity pool={ poolMock.noIcons } isLoading/> <PoolEntity pool={ poolMock.noIcons } isLoading/>
</Sample> </Sample>
</SamplesStack> </SamplesStack>
<SectionSubHeader>Link overlay</SectionSubHeader>
<SamplesStack>
<Sample label="Internal link">
<LinkBox p={ 2 } display="flex" flexDirection="column" columnGap={ 2 } borderWidth="1px" borderColor="border.divider" borderRadius="base">
<LinkOverlay href="/blocks">Main link</LinkOverlay>
<Link href="/txs">Inner link</Link>
</LinkBox>
</Sample>
<Sample label="External link">
<LinkBox p={ 2 } display="flex" flexDirection="column" columnGap={ 2 } borderWidth="1px" borderColor="border.divider" borderRadius="base">
<LinkOverlay href="https://blockscout.com" external>Main link</LinkOverlay>
<Link href="https://blockscout.com/txs" external>Inner link</Link>
</LinkBox>
</Sample>
</SamplesStack>
</Section> </Section>
</Container> </Container>
); );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment