init next 13 (#613)
* init next 13 * layout responsive by default again * more next13 things * push up * remove beehiiv embed * make lgtm happy * halfway through push up * push up
This commit is contained in:
@@ -64,3 +64,10 @@ yalc.lock
|
||||
public/sitemap*.xml
|
||||
# Sentry
|
||||
.sentryclirc
|
||||
|
||||
.vscode
|
||||
|
||||
|
||||
|
||||
# future_app dir
|
||||
future_app/
|
||||
Vendored
+3
-2
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
}
|
||||
"typescript.tsdk": "./node_modules/typescript/lib",
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true
|
||||
}
|
||||
@@ -1,94 +1,8 @@
|
||||
import {
|
||||
Box,
|
||||
BoxProps,
|
||||
ImageProps as ChakraImageProps,
|
||||
chakra,
|
||||
} from "@chakra-ui/react";
|
||||
import NextImage, { ImageProps } from "next/image";
|
||||
import { useMemo } from "react";
|
||||
import useDimensions from "react-cool-dimensions";
|
||||
import { isBrowser } from "utils/isBrowser";
|
||||
import { chakra } from "@chakra-ui/react";
|
||||
import NextImage from "next/image";
|
||||
|
||||
const ChakraNextUnwrappedImage = chakra(NextImage, {
|
||||
shouldForwardProp: (prop) =>
|
||||
[
|
||||
"width",
|
||||
"height",
|
||||
"src",
|
||||
"alt",
|
||||
"quality",
|
||||
"placeholder",
|
||||
"blurDataURL",
|
||||
"loader ",
|
||||
"layout",
|
||||
"sizes",
|
||||
"onLoadingComplete",
|
||||
"priority",
|
||||
].includes(prop),
|
||||
export const ChakraNextImage = chakra(NextImage, {
|
||||
baseStyle: { objectFit: "contain!important", maxW: "100%", zIndex: 1 },
|
||||
});
|
||||
|
||||
const previousLoadedImagesSet = new Set<string>();
|
||||
|
||||
export type ChakraNextImageProps = ImageProps &
|
||||
Omit<BoxProps, "width" | "height"> & {
|
||||
alt: string;
|
||||
imgProps?: Omit<ChakraImageProps, "placeholder">;
|
||||
};
|
||||
|
||||
export const ChakraNextImage = (props: ChakraNextImageProps) => {
|
||||
const {
|
||||
src,
|
||||
alt,
|
||||
width,
|
||||
quality = 90,
|
||||
height,
|
||||
layout = "responsive",
|
||||
objectFit,
|
||||
objectPosition,
|
||||
placeholder = typeof src === "string" ? "empty" : "blur",
|
||||
imgProps,
|
||||
priority,
|
||||
sizes,
|
||||
...rest
|
||||
} = props;
|
||||
const { observe, width: _width } = useDimensions<HTMLDivElement | null>();
|
||||
const imageId = useMemo(() => {
|
||||
const _src: string =
|
||||
typeof src === "string"
|
||||
? src
|
||||
: (src as any)?.default?.src || (src as any)?.src || "";
|
||||
return `${_src}_w=${_width}`;
|
||||
}, [_width, src]);
|
||||
|
||||
const size =
|
||||
sizes ||
|
||||
(isBrowser() && _width !== undefined
|
||||
? `${(_width / window.innerWidth) * 100}vw`
|
||||
: "100vw");
|
||||
return (
|
||||
<Box maxW="100%" pos="relative" {...rest} ref={observe}>
|
||||
<ChakraNextUnwrappedImage
|
||||
onLoadingComplete={() => {
|
||||
previousLoadedImagesSet.add(imageId);
|
||||
}}
|
||||
objectFit={objectFit}
|
||||
objectPosition={objectPosition}
|
||||
w="auto"
|
||||
h="auto"
|
||||
layout={layout}
|
||||
sizes={size}
|
||||
width={width}
|
||||
quality={quality}
|
||||
height={height}
|
||||
placeholder={placeholder}
|
||||
src={src}
|
||||
alt={alt}
|
||||
priority={priority}
|
||||
transition={
|
||||
previousLoadedImagesSet.has(imageId) ? undefined : "all 0.2s"
|
||||
}
|
||||
{...imgProps}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
export type ChakraNextImageProps = React.ComponentProps<typeof ChakraNextImage>;
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
Icon,
|
||||
IconButton,
|
||||
Image,
|
||||
Link,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuItemOption,
|
||||
@@ -37,7 +36,6 @@ import {
|
||||
import { ChakraNextImage } from "components/Image";
|
||||
import { useReleasesFromDeploy } from "components/contract-components/hooks";
|
||||
import { CONTRACT_TYPE_NAME_MAP, FeatureIconMap } from "constants/mappings";
|
||||
import OriginalNextLink from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import * as React from "react";
|
||||
@@ -48,6 +46,7 @@ import {
|
||||
AddressCopyButton,
|
||||
Badge,
|
||||
Card,
|
||||
ChakraNextLink,
|
||||
Heading,
|
||||
LinkButton,
|
||||
Text,
|
||||
@@ -479,18 +478,16 @@ const AsyncContractNameCell: React.FC<AsyncContractNameCellProps> = ({
|
||||
|
||||
return (
|
||||
<Skeleton isLoaded={!metadataQuery.isLoading}>
|
||||
<OriginalNextLink href={href} passHref>
|
||||
<Link>
|
||||
<Text
|
||||
color="blue.700"
|
||||
_dark={{ color: "blue.300" }}
|
||||
size="label.md"
|
||||
_groupHover={{ textDecor: "underline" }}
|
||||
>
|
||||
{metadataQuery.data?.name || shortenIfAddress(cell.address)}
|
||||
</Text>
|
||||
</Link>
|
||||
</OriginalNextLink>
|
||||
<ChakraNextLink href={href} passHref>
|
||||
<Text
|
||||
color="blue.700"
|
||||
_dark={{ color: "blue.300" }}
|
||||
size="label.md"
|
||||
_groupHover={{ textDecor: "underline" }}
|
||||
>
|
||||
{metadataQuery.data?.name || shortenIfAddress(cell.address)}
|
||||
</Text>
|
||||
</ChakraNextLink>
|
||||
</Skeleton>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
import { ethers } from "ethers";
|
||||
import { useTrack } from "hooks/analytics/useTrack";
|
||||
import { FiExternalLink } from "react-icons/fi";
|
||||
import { Heading, NextLink, Text } from "tw-components";
|
||||
import { Heading, Link, Text } from "tw-components";
|
||||
import { ComponentWithChildren } from "types/component-with-children";
|
||||
|
||||
interface PriceLineProps {
|
||||
@@ -87,7 +87,7 @@ export const GasEstimatorBox: React.FC<GasEstimatorBoxProps> = ({
|
||||
|
||||
return (
|
||||
<Box p={6} border="1px solid" borderColor="borderColor" {...props}>
|
||||
<NextLink
|
||||
<Link
|
||||
href={`https://portal.thirdweb.com/pre-built-contracts/${contractType}`}
|
||||
onClick={() =>
|
||||
trackEvent({
|
||||
@@ -103,7 +103,7 @@ export const GasEstimatorBox: React.FC<GasEstimatorBoxProps> = ({
|
||||
{CONTRACT_TYPE_NAME_MAP[contractType]}
|
||||
<Icon as={FiExternalLink} ml={1} boxSize={4} />
|
||||
</Heading>
|
||||
</NextLink>
|
||||
</Link>
|
||||
<PriceLine
|
||||
title="Contract creation"
|
||||
label="The price to deploy this Smart Contract"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Flex, VStack } from "@chakra-ui/react";
|
||||
import Image from "next/image";
|
||||
import { ChakraNextImage } from "components/Image";
|
||||
import { Heading, Link } from "tw-components";
|
||||
|
||||
export const Resources: React.FC = () => {
|
||||
@@ -48,13 +48,7 @@ export const Resources: React.FC = () => {
|
||||
m={4}
|
||||
p={4}
|
||||
>
|
||||
<Image
|
||||
width="175px"
|
||||
objectFit="cover"
|
||||
height="135px"
|
||||
src={image}
|
||||
alt={label}
|
||||
/>
|
||||
<ChakraNextImage width={175} height={135} src={image} alt={label} />
|
||||
<Link href={link} fontSize="20px" mt={4}>
|
||||
{label}
|
||||
</Link>
|
||||
|
||||
@@ -294,7 +294,6 @@ export const WelcomeScreen: React.FC = () => {
|
||||
w={{ base: "45%", md: "90%" }}
|
||||
src={require("public/assets/product-pages/dashboard/hero.png")}
|
||||
alt=""
|
||||
layout="responsive"
|
||||
/>
|
||||
</Center>
|
||||
</motion.div>
|
||||
|
||||
@@ -122,13 +122,7 @@ export const Hero: ComponentWithChildren<IHero> = ({
|
||||
>
|
||||
<Flex justifyContent={{ base: "center", md: "flex-end" }} w="100%">
|
||||
<AspectRatio ratio={1} maxW={96} w="100%">
|
||||
<ChakraNextImage
|
||||
alt=""
|
||||
src={image}
|
||||
layout="fill"
|
||||
objectFit="contain"
|
||||
priority
|
||||
/>
|
||||
<ChakraNextImage alt="" src={image} priority />
|
||||
</AspectRatio>
|
||||
</Flex>
|
||||
</Center>
|
||||
|
||||
@@ -12,7 +12,6 @@ export const MultiChainSVG: React.FC = () => {
|
||||
<ChakraNextImage
|
||||
alt=""
|
||||
placeholder="empty"
|
||||
layout="fill"
|
||||
src={require(`./multi-chain/${src}.svg`)}
|
||||
/>
|
||||
</AspectRatio>
|
||||
|
||||
+5
-3
@@ -1,5 +1,3 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
|
||||
const ContentSecurityPolicy = `
|
||||
default-src 'self';
|
||||
img-src * data: blob:;
|
||||
@@ -36,8 +34,8 @@ const securityHeaders = [
|
||||
},
|
||||
];
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const moduleExports = {
|
||||
reactStrictMode: true,
|
||||
async headers() {
|
||||
return [
|
||||
{
|
||||
@@ -109,6 +107,10 @@ const moduleExports = {
|
||||
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
|
||||
domains: ["thirdweb.com", "portal.thirdweb.com", "blog.thirdweb.com"],
|
||||
},
|
||||
reactStrictMode: true,
|
||||
experimental: {
|
||||
scrollRestoration: true,
|
||||
},
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
|
||||
+11
-7
@@ -21,6 +21,7 @@
|
||||
"@emotion/styled": "^11",
|
||||
"@hookform/resolvers": "^2.8.0",
|
||||
"@n8tb1t/use-scroll-position": "^2.0.3",
|
||||
"@next/font": "^13.0.0",
|
||||
"@react-icons/all-files": "^4.1.0",
|
||||
"@sentry/nextjs": "^7.16.0",
|
||||
"@solana/wallet-adapter-base": "^0.9.16",
|
||||
@@ -33,17 +34,19 @@
|
||||
"@tanstack/react-query-persist-client": "^4.0.10",
|
||||
"@tanstack/react-table": "^8.5.13",
|
||||
"@thirdweb-dev/chain-icons": "^1.0.5",
|
||||
"@thirdweb-dev/react": "^3.5.1-nightly-4e7b293",
|
||||
"@thirdweb-dev/sdk": "^3.5.1-nightly-4e7b293",
|
||||
"@thirdweb-dev/react": "^3.5.1",
|
||||
"@thirdweb-dev/sdk": "^3.5.1",
|
||||
"@thirdweb-dev/storage": "^1.0.6",
|
||||
"bn.js": "^5.2.0",
|
||||
"ad": "^0.3.2",
|
||||
"bn.js": "^5.2.1",
|
||||
"classnames": "^2.3.2",
|
||||
"color": "^4.0.1",
|
||||
"date-fns": "^2.28.0",
|
||||
"emotion-theming": "^11.0.0",
|
||||
"ethers": "^5.4.6",
|
||||
"flat": "^5.0.2",
|
||||
"framer-motion": "^7.0.0",
|
||||
"next": "^12.0.9",
|
||||
"next": "^13.0.0",
|
||||
"next-seo": "^5.0.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"papaparse": "^5.3.1",
|
||||
@@ -64,12 +67,13 @@
|
||||
"remark-gfm": "^3.0.1",
|
||||
"spdx-correct": "^3.1.1",
|
||||
"tiny-invariant": "^1.2.0",
|
||||
"yarn": "^1.22.19",
|
||||
"zod": "^3.8.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.5",
|
||||
"@chakra-ui/cli": "^2.0.0",
|
||||
"@next/bundle-analyzer": "^12.1.5",
|
||||
"@next/bundle-analyzer": "^13.0.0",
|
||||
"@tanstack/react-location-devtools": "^3.4.4",
|
||||
"@trivago/prettier-plugin-sort-imports": "^3.2.0",
|
||||
"@types/color": "^3.0.2",
|
||||
@@ -86,7 +90,7 @@
|
||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
||||
"@typescript-eslint/parser": "^5.0.0",
|
||||
"eslint": "^8.0.0",
|
||||
"eslint-config-next": "^12.0.0",
|
||||
"eslint-config-next": "^13.0.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-import": "^2.25.2",
|
||||
"eslint-plugin-inclusive-language": "^2.1.1",
|
||||
@@ -100,7 +104,7 @@
|
||||
"resolutions": {
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"bn.js": "^5.2.0",
|
||||
"bn.js": "^5.2.1",
|
||||
"typescript": "^4.7.0"
|
||||
},
|
||||
"next-unused": {
|
||||
|
||||
@@ -93,6 +93,21 @@ function ConsoleApp({ Component, pageProps }: AppPropsWithLayout) {
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
// Taken from StackOverflow. Trying to detect both Safari desktop and mobile.
|
||||
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
||||
if (isSafari) {
|
||||
// This is kind of a lie.
|
||||
// We still rely on the manual Next.js scrollRestoration logic.
|
||||
// However, we *also* don't want Safari grey screen during the back swipe gesture.
|
||||
// Seems like it doesn't hurt to enable auto restore *and* Next.js logic at the same time.
|
||||
history.scrollRestoration = "auto";
|
||||
} else {
|
||||
// For other browsers, let Next.js set scrollRestoration to 'manual'.
|
||||
// It seems to work better for Chrome and Firefox which don't animate the back swipe.
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// setup route cancellation
|
||||
const handleStart = (url: string) => {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { withSentry } from "@sentry/nextjs";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
interface EmailSignupPayload {
|
||||
email: string;
|
||||
send_welcome_email?: boolean;
|
||||
}
|
||||
|
||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
if (req.method !== "POST") {
|
||||
return res.status(400).json({ error: "invalid method" });
|
||||
}
|
||||
|
||||
const { email, send_welcome_email = false } = JSON.parse(
|
||||
req.body,
|
||||
) as EmailSignupPayload;
|
||||
|
||||
invariant(process.env.BEEHIIV_API_KEY, "missing BEEHIIV_API_KEY");
|
||||
|
||||
const response = await fetch("https://api.beehiiv.com/v1/subscribers", {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-ApiKey": process.env.BEEHIIV_API_KEY,
|
||||
},
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
email,
|
||||
publication_id: "9f54090a-6d14-406b-adfd-dbb30574f664",
|
||||
send_welcome_email,
|
||||
utm_source: "thirdweb.com",
|
||||
}),
|
||||
});
|
||||
|
||||
return res.status(response.status).json({ status: response.statusText });
|
||||
};
|
||||
|
||||
export default withSentry(handler);
|
||||
+56
-10
@@ -6,8 +6,10 @@ import {
|
||||
DarkMode,
|
||||
Divider,
|
||||
Flex,
|
||||
FormControl,
|
||||
Icon,
|
||||
IconButton,
|
||||
Input,
|
||||
LightMode,
|
||||
List,
|
||||
ListIcon,
|
||||
@@ -40,10 +42,18 @@ import Hero from "public/assets/landingpage/hero.png";
|
||||
import MobileHero from "public/assets/landingpage/mobile-hero.png";
|
||||
import ThirdwebTeams from "public/assets/landingpage/thirdweb-teams.png";
|
||||
import WhiteLogo from "public/assets/landingpage/white-logo.png";
|
||||
import { useForm } from "react-hook-form";
|
||||
// end images
|
||||
import { BsLightningCharge, BsMenuButtonWide } from "react-icons/bs";
|
||||
import { MdMarkEmailRead, MdOutlineAnalytics } from "react-icons/md";
|
||||
import { Card, Heading, LinkButton, Text, TrackedLink } from "tw-components";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Heading,
|
||||
LinkButton,
|
||||
Text,
|
||||
TrackedLink,
|
||||
} from "tw-components";
|
||||
|
||||
const HomePage: ThirdwebNextPage = () => {
|
||||
const trackEvent = useTrack();
|
||||
@@ -753,6 +763,12 @@ const ContractsDescriptorItem: React.FC<ContractsDescriptorItemProps> = ({
|
||||
};
|
||||
|
||||
const NewsLetterSection: React.FC = () => {
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
email: "",
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Box bgColor="rgba(0,0,0,.6)" zIndex="100">
|
||||
<Container as="section" maxW="container.page" color="gray.500">
|
||||
@@ -776,15 +792,45 @@ const NewsLetterSection: React.FC = () => {
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<Box
|
||||
as="iframe"
|
||||
src="https://embeds.beehiiv.com/42f51ba6-da56-42f9-92d8-24a339b9acd0?slim=true"
|
||||
data-test-id="beehiiv-embed"
|
||||
frameBorder="0"
|
||||
scrolling="no"
|
||||
h="50px"
|
||||
borderRadius="md"
|
||||
/>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(async (data) => {
|
||||
try {
|
||||
await fetch("/api/email-signup", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ email: data.email }),
|
||||
});
|
||||
form.setValue("email", "");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
})}
|
||||
>
|
||||
<Flex gap={0} minW={{ base: "100%", md: "350px" }}>
|
||||
<FormControl isRequired>
|
||||
<Input
|
||||
borderRightRadius={0}
|
||||
type="email"
|
||||
borderColor="purple.500"
|
||||
borderRight={0}
|
||||
_hover={{ borderColor: "purple.500" }}
|
||||
_focus={{ borderColor: "purple.500" }}
|
||||
placeholder="Enter your email"
|
||||
{...form.register("email")}
|
||||
autoComplete="email"
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
borderLeftRadius={0}
|
||||
flexShrink={0}
|
||||
isLoading={form.formState.isSubmitting}
|
||||
type="submit"
|
||||
mr={2}
|
||||
colorScheme="purple"
|
||||
>
|
||||
Sign up
|
||||
</Button>
|
||||
</Flex>
|
||||
</form>
|
||||
</Stack>
|
||||
</Container>
|
||||
</Box>
|
||||
|
||||
@@ -142,7 +142,6 @@ const Solana: ThirdwebNextPage = () => {
|
||||
<ChakraNextImage
|
||||
alt=""
|
||||
src={require("public/assets/network-pages/solana/hero.png")}
|
||||
layout="fill"
|
||||
objectFit="contain"
|
||||
priority
|
||||
/>
|
||||
|
||||
+13
-2
@@ -19,8 +19,19 @@
|
||||
"paths": {
|
||||
"tw-components": ["tw-components"],
|
||||
"tw-components/*": ["tw-components/*"]
|
||||
}
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "additional.d.ts"],
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"additional.d.ts",
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"exclude": ["node_modules", ".next"]
|
||||
}
|
||||
|
||||
+10
-11
@@ -1,4 +1,5 @@
|
||||
import { Card } from "./card";
|
||||
import { ChakraNextLink } from "./link";
|
||||
import { Text } from "./text";
|
||||
import { convertFontSizeToCSSVar } from "./utils/typography";
|
||||
import {
|
||||
@@ -17,7 +18,6 @@ import {
|
||||
} from "@chakra-ui/react";
|
||||
import { Link as LocationLink, useMatch } from "@tanstack/react-location";
|
||||
import { useTrack } from "hooks/analytics/useTrack";
|
||||
import NextLink from "next/link";
|
||||
import React, { useEffect } from "react";
|
||||
import { FiCopy, FiExternalLink } from "react-icons/fi";
|
||||
import { fontWeights, letterSpacings, lineHeights } from "theme/typography";
|
||||
@@ -126,16 +126,15 @@ export const LinkButton = React.forwardRef<HTMLButtonElement, LinkButtonProps>(
|
||||
}
|
||||
|
||||
return (
|
||||
<NextLink href={href} passHref>
|
||||
<Button
|
||||
as={Link}
|
||||
ref={ref}
|
||||
{...restButtonProps}
|
||||
textDecoration="none!important"
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
</NextLink>
|
||||
<Button
|
||||
as={ChakraNextLink}
|
||||
href={href}
|
||||
ref={ref}
|
||||
{...restButtonProps}
|
||||
textDecoration="none!important"
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
+24
-12
@@ -1,12 +1,24 @@
|
||||
import {
|
||||
Link as ChakraLink,
|
||||
LinkProps as ChakraLinkProps,
|
||||
forwardRef,
|
||||
} from "@chakra-ui/react";
|
||||
import { Link as LocationLink, useMatch } from "@tanstack/react-location";
|
||||
import { useTrack } from "hooks/analytics/useTrack";
|
||||
import _NextLink, { LinkProps as _NextLinkProps } from "next/link";
|
||||
import React, { useCallback } from "react";
|
||||
|
||||
export type ChakraNextLinkProps = Omit<ChakraLinkProps, "as"> &
|
||||
Omit<_NextLinkProps, "as">;
|
||||
export const ChakraNextLink = forwardRef<ChakraNextLinkProps, "a">(
|
||||
(props, ref) => <ChakraLink as={_NextLink} {...props} ref={ref} />,
|
||||
);
|
||||
|
||||
export type ChakraLocationLinkProps = Omit<ChakraLinkProps, "as">;
|
||||
export const ChakraLocationLink = forwardRef<ChakraLocationLinkProps, "a">(
|
||||
(props, ref) => <ChakraLink as={LocationLink} {...props} ref={ref} />,
|
||||
);
|
||||
|
||||
interface LinkProps
|
||||
extends Omit<ChakraLinkProps, "href">,
|
||||
Pick<_NextLinkProps, "href"> {
|
||||
@@ -36,17 +48,22 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
|
||||
// we're in a react location context, so we can use that
|
||||
if (match && !noMatch) {
|
||||
return (
|
||||
<ChakraLink as={LocationLink} to={href} {...restLinkProps}>
|
||||
<ChakraLocationLink to={href} {...restLinkProps}>
|
||||
{children}
|
||||
</ChakraLink>
|
||||
</ChakraLocationLink>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<_NextLink href={href} passHref scroll={scroll || false}>
|
||||
<ChakraLink ref={ref} _focus={{ boxShadow: "none" }} {...restLinkProps}>
|
||||
{children}
|
||||
</ChakraLink>
|
||||
</_NextLink>
|
||||
<ChakraNextLink
|
||||
href={href}
|
||||
scroll={scroll}
|
||||
scrollBehavior="smooth"
|
||||
ref={ref}
|
||||
_focus={{ boxShadow: "none" }}
|
||||
{...restLinkProps}
|
||||
>
|
||||
{children}
|
||||
</ChakraNextLink>
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -75,8 +92,3 @@ export const TrackedLink = React.forwardRef<
|
||||
});
|
||||
|
||||
TrackedLink.displayName = "TrackedLink";
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link Link} instead.
|
||||
*/
|
||||
export const NextLink = Link;
|
||||
|
||||
Reference in New Issue
Block a user