Skip to content
This repository was archived by the owner on Aug 30, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/thirdweb-react/docs/react.usecontract.md

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions packages/thirdweb-react/etc/react.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import type { EventQueryFilter } from '@thirdweb-dev/sdk';
import { FetchStatus } from '@tanstack/react-query';
import { InjectedConnector } from 'wagmi/connectors/injected';
import type { IStorage } from '@thirdweb-dev/storage';
import { IStorage as IStorage_2 } from '@thirdweb-dev/sdk';
import { Json } from '@thirdweb-dev/sdk';
import { ListingType } from '@thirdweb-dev/sdk';
import { LoginOptions } from '@thirdweb-dev/sdk/dist/src/schema';
Expand Down Expand Up @@ -288,7 +287,7 @@ export type RevealLazyMintInput = {
// Warning: (ae-internal-missing-underscore) The name "RolesForContract" should be prefixed with an underscore because the declaration is marked as @internal
//
// @internal (undocumented)
export type RolesForContract<TContract extends ContractWithRoles> = TContract extends SmartContract ? Role | (string & {}) : NonNullable<TContract["roles"]>["roles"][number];
export type RolesForContract<TContract extends ContractWithRoles> = TContract extends SmartContract ? Role | (string & {}) : NonNullable<Exclude<TContract, SmartContract>["roles"]>["roles"][number];

// @beta
export type SetClaimConditionsParams = {
Expand Down Expand Up @@ -1647,7 +1646,7 @@ export { useProvider }
// Warning: (ae-internal-missing-underscore) The name "useReadonlySDK" should be prefixed with an underscore because the declaration is marked as @internal
//
// @internal (undocumented)
export function useReadonlySDK(readonlyRpcUrl: string, sdkOptions: SDKOptions, storageInterface?: IStorage_2): ThirdwebSDK;
export function useReadonlySDK(readonlyRpcUrl: string, sdkOptions: SDKOptions, storageInterface?: IStorage): ThirdwebSDK;

// @beta
export function useResetClaimConditions<TContract extends NFTContract | Erc20>(...[contract, tokenId]: ClaimConditionsInputParams<TContract>): UseMutationResult<Omit<{
Expand Down
10 changes: 6 additions & 4 deletions packages/thirdweb-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"extract-api": "api-extractor run --local",
"generate:md-docs": "yarn api-documenter markdown -i ./temp -o ./docs",
"generate-snippets": "node ./scripts/generate-snippets.mjs",
"build": "yarn build:lib && yarn extract-api && yarn generate:md-docs && yarn generate-snippets",
"build": "tsc && yarn build:lib && yarn extract-api && yarn generate:md-docs && yarn generate-snippets",
"prepublishOnly": "yarn build"
},
"sideEffects:": false,
Expand All @@ -44,6 +44,7 @@
"@types/color": "^3.0.3",
"@types/mime": "^3.0.1",
"@types/react": "^18.0.5",
"@types/react-dom": "^18.0.6",
"@typescript-eslint/eslint-plugin": "^5.2.0",
"@typescript-eslint/parser": "^5.2.0",
"eslint": "^8.9.0",
Expand All @@ -54,7 +55,8 @@
"eslint-plugin-tsdoc": "^0.2.14",
"ethers": "^5.6.1",
"prettier": "^2.5.1",
"react": "^18.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^4.6.2"
},
"dependencies": {
Expand All @@ -63,7 +65,6 @@
"@gnosis.pm/safe-core-sdk": "2.1.0",
"@gnosis.pm/safe-ethers-adapters": "0.1.0-alpha.9",
"@gnosis.pm/safe-ethers-lib": "1.1.0",
"@reach/portal": "^0.17.0",
"@tanstack/react-query": "^4.0.10",
"@thirdweb-dev/storage": "^0.1.0",
"@zag-js/menu": "^0.1.11",
Expand All @@ -81,7 +82,8 @@
"peerDependencies": {
"@thirdweb-dev/sdk": "^2.3.23",
"ethers": ">=5.5.1",
"react": ">=18.0.0"
"react": ">=18.0.0",
"react-dom": ">=18.0.0"
},
"resolutions": {
"ansi-regex": "^6.0.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useChainId } from "../../hooks/useChainId";
import { useConnect } from "../../hooks/useConnect";
import { useDisconnect } from "../../hooks/useDisconnect";
import { useNetwork } from "../../hooks/useNetwork";
import { Portal } from "../../lib/portal";
import { shortenIfAddress } from "../../utils/addresses";
import { useClipboard } from "../hooks/useCopyClipboard";
import { useIsMounted } from "../hooks/useIsMounted";
Expand All @@ -19,7 +20,6 @@ import { Spinner } from "../shared/Spinner";
import { ThemeProvider, ThemeProviderProps } from "../shared/ThemeProvider";
import { fontFamily } from "../theme";
import { SupportedNetworkSelect } from "./NetworkSelect";
import { Portal } from "@reach/portal";
import { ChainId, LoginOptions, SUPPORTED_CHAIN_ID } from "@thirdweb-dev/sdk";
import * as menu from "@zag-js/menu";
import { normalizeProps, useMachine } from "@zag-js/react";
Expand Down
24 changes: 16 additions & 8 deletions packages/thirdweb-react/src/hooks/async/claim-conditions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export function useActiveClaimCondition<TContract extends NFTContract | Erc20>(
contract?.drop?.claim?.conditions?.getActive,
"Contract instance does not support contract?.drop?.claim?.conditions.getActive",
);
if (contract instanceof Erc1155) {
if (contract.featureName === "ERC1155") {
invariant(tokenId, "tokenId is required for ERC1155 claim conditions");
return contract?.drop?.claim?.conditions?.getActive(tokenId);
}
Expand All @@ -101,7 +101,10 @@ export function useActiveClaimCondition<TContract extends NFTContract | Erc20>(
// Checks that happen here:
// 1. if the contract is based on ERC1155 contract => tokenId cannot be `undefined`
// 2. if the contract is NOT based on ERC1155 => contract has to still be provided
enabled: contract instanceof Erc1155 ? tokenId !== undefined : !!contract,
enabled:
contract?.featureName === "ERC1155"
? tokenId !== undefined
: !!contract,
},
);
}
Expand Down Expand Up @@ -141,7 +144,7 @@ export function useClaimConditions<TContract extends NFTContract | Erc20>(
contract?.drop?.claim?.conditions?.getAll,
"Contract instance does not support drop.claim.conditions.getAll",
);
if (contract instanceof Erc1155) {
if (contract.featureName === "ERC1155") {
invariant(tokenId, "tokenId is required for ERC1155 claim conditions");
return contract?.drop?.claim?.conditions?.getAll(tokenId);
}
Expand All @@ -151,7 +154,10 @@ export function useClaimConditions<TContract extends NFTContract | Erc20>(
// Checks that happen here:
// 1. if the contract is based on ERC1155 contract => tokenId cannot be `undefined`
// 2. if the contract is NOT based on ERC1155 => contract has to still be provided
enabled: contract instanceof Erc1155 ? tokenId !== undefined : !!contract,
enabled:
contract?.featureName === "ERC1155"
? tokenId !== undefined
: !!contract,
},
);
}
Expand Down Expand Up @@ -195,7 +201,7 @@ export function useClaimIneligibilityReasons<
contract?.drop?.claim?.conditions.getClaimIneligibilityReasons,
"Contract instance does not support claimConditions.getClaimIneligibilityReasons",
);
if (contract instanceof Erc1155) {
if (contract.featureName === "ERC1155") {
invariant(
tokenId,
"tokenId is required for ERC1155 claim ineligibility reasons",
Expand All @@ -218,7 +224,9 @@ export function useClaimIneligibilityReasons<
// 3. has a params object been passed?
// 4. does params have an address in it?
enabled:
(contract instanceof Erc1155 ? tokenId !== undefined : !!contract) &&
(contract?.featureName === "ERC1155"
? tokenId !== undefined
: !!contract) &&
!!params &&
!!params.walletAddress,
},
Expand Down Expand Up @@ -297,7 +305,7 @@ export function useSetClaimConditions<TContract extends NFTContract | Erc20>(
invariant(contract, "No Contract instance provided");
const { phases, reset = false } = data;
invariant(phases, 'No "phases" provided');
if (contract instanceof Erc1155) {
if (contract.featureName === "ERC1155") {
invariant(tokenId, "tokenId is required for ERC1155 claim conditions");
return contract?.drop?.claim?.conditions.set(tokenId, phases, reset);
}
Expand Down Expand Up @@ -391,7 +399,7 @@ export function useResetClaimConditions<TContract extends NFTContract | Erc20>(
}));
};

if (contract instanceof Erc1155) {
if (contract.featureName === "ERC1155") {
invariant(tokenId, "tokenId is required for ERC1155 claim conditions");
const claimConditions = await contract?.drop?.claim?.conditions.getAll(
tokenId,
Expand Down
4 changes: 2 additions & 2 deletions packages/thirdweb-react/src/hooks/async/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import type {
ThirdwebSDK,
} from "@thirdweb-dev/sdk";
// eslint-disable-next-line no-duplicate-imports
import { CONTRACTS_MAP, SmartContract } from "@thirdweb-dev/sdk";
import { CONTRACTS_MAP } from "@thirdweb-dev/sdk";
import type {
CustomContractMetadata,
PublishedMetadata,
Expand Down Expand Up @@ -352,7 +352,7 @@ export function useContractFunctions(
typeAndCompilerMetadata,
sdk,
);
if (contract instanceof SmartContract) {
if (contract?.publishedMetadata.extractFunctions) {
return contract.publishedMetadata.extractFunctions();
}
return null;
Expand Down
5 changes: 2 additions & 3 deletions packages/thirdweb-react/src/hooks/async/drop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { useQueryWithNetwork } from "../query-utils/useQueryWithNetwork";
import { useNFTs } from "./nft";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import {
Erc1155,
NFTDrop,
NFTMetadataInput,
QueryAllParams,
Expand Down Expand Up @@ -117,7 +116,7 @@ export function useClaimedNFTSupply(contract: RequiredParam<DropContract>) {
cacheKeys.contract.nft.drop.totalClaimedSupply(contractAddress),
() => {
invariant(contract, "No Contract instance provided");
if (contract instanceof Erc1155) {
if (contract.featureName === "ERC1155") {
return contract.getTotalCount();
}
invariant(
Expand Down Expand Up @@ -198,7 +197,7 @@ export function useClaimNFT<TContract extends DropContract>(
async (data: ClaimNFTParams<TContract>) => {
invariant(data.to, 'No "to" address provided');
invariant(contract?.claimTo, "contract does not support claimTo");
if (contract instanceof Erc1155) {
if (contract.featureName === "ERC1155") {
invariant("tokenId" in data, "tokenId not provided");
const { to, tokenId, quantity } = data;
return (await contract.claimTo(
Expand Down
16 changes: 8 additions & 8 deletions packages/thirdweb-react/src/hooks/async/nft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function convertResponseToNFTType(
contract: NFTContract,
metadata: Awaited<ReturnType<typeof contract["get"]>>,
): NFT<typeof contract> {
if (contract instanceof Erc721) {
if (contract.featureName === "ERC721") {
return {
type: "ERC721",
supply: 1,
Expand Down Expand Up @@ -172,7 +172,7 @@ export function useTotalCirculatingSupply<TContract extends NFTContract>(
cacheKeys.contract.nft.query.totalCirculatingSupply(contractAddress),
() => {
invariant(contract, "No Contract instance provided");
if (contract instanceof Erc721) {
if (contract.featureName === "ERC721") {
invariant(
contract?.query?.totalCirculatingSupply,
"Contract instance does not support query.totalCirculatingSupply",
Expand Down Expand Up @@ -219,7 +219,7 @@ export function useTotalCount(contract: RequiredParam<NFTContract>) {
cacheKeys.contract.nft.query.totalCount(contractAddress),
() => {
invariant(contract, "No Contract instance provided");
if (contract instanceof Erc721) {
if (contract.featureName === "ERC721") {
invariant(
contract?.query?.totalCirculatingSupply,
"Contract instance does not support query.totalCirculatingSupply",
Expand Down Expand Up @@ -266,7 +266,7 @@ export function useOwnedNFTs<TContract extends NFTContract>(
cacheKeys.contract.nft.query.owned.all(contractAddress, ownerWalletAddress),
async () => {
invariant(contract, "No Contract instance provided");
if (contract instanceof Erc721) {
if (contract.featureName === "ERC721") {
invariant(
contract.query?.owned?.all,
"Contract instance does not support query.owned.all",
Expand Down Expand Up @@ -327,7 +327,7 @@ export function useNFTBalance<TContract extends NFTContract>(
"Contract instance does not support balanceOf",
);
invariant(ownerWalletAddress, "No owner wallet address provided");
if (contract instanceof Erc1155) {
if (contract.featureName === "ERC1155") {
invariant(tokenId, "No tokenId provided");
return contract.balanceOf(ownerWalletAddress, tokenId);
}
Expand Down Expand Up @@ -410,7 +410,7 @@ export function useMintNFT<TContract extends NFTContract>(
async (data: MintNFTParams<TContract>) => {
invariant(data.to, 'No "to" address provided');
invariant(contract?.mint?.to, "contract does not support mint.to");
if (contract instanceof Erc1155) {
if (contract.featureName === "ERC1155") {
invariant("supply" in data, "supply not provided");
const { to, metadata, supply } = data;
return (await contract.mint.to(to, {
Expand Down Expand Up @@ -589,7 +589,7 @@ export function useTransferNFT<TContract extends NFTContract>(
return useMutation(
(data: TransferNFTParams<TContract>) => {
invariant(contract?.transfer, "contract does not support transfer");
if (contract instanceof Erc1155) {
if (contract.featureName === "ERC1155") {
invariant("amount" in data, "amount not provided");
return contract.transfer(data.to, data.tokenId, data.amount);
}
Expand Down Expand Up @@ -761,7 +761,7 @@ export function useBurnNFT<TContract extends NFTContract>(
async (data: BurnNFTParams<TContract>) => {
invariant(data.tokenId, "No tokenId provided");
invariant(contract?.burn, "contract does not support burn");
if (contract instanceof Erc1155) {
if (contract.featureName === "ERC1155") {
invariant("amount" in data, "amount not provided");
const { tokenId, amount } = data;
return await contract.burn.tokens(tokenId, amount);
Expand Down
2 changes: 1 addition & 1 deletion packages/thirdweb-react/src/hooks/async/roles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export type ContractWithRoles =
export type RolesForContract<TContract extends ContractWithRoles> =
TContract extends SmartContract
? Role | (string & {})
: NonNullable<TContract["roles"]>["roles"][number];
: NonNullable<Exclude<TContract, SmartContract>["roles"]>["roles"][number];

/**
* @internal
Expand Down
3 changes: 2 additions & 1 deletion packages/thirdweb-react/src/hooks/useReadonlySDK.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { IStorage, SDKOptions, ThirdwebSDK } from "@thirdweb-dev/sdk";
import { SDKOptions, ThirdwebSDK } from "@thirdweb-dev/sdk";
import type { IStorage } from "@thirdweb-dev/storage";
import { useMemo } from "react";

/**
Expand Down
90 changes: 90 additions & 0 deletions packages/thirdweb-react/src/lib/portal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { useState, useCallback, useLayoutEffect, useEffect, useRef, PropsWithChildren } from "react";
import { createPortal } from "react-dom";


function canUseDOM() {
return !!(
typeof window !== "undefined" &&
window.document &&
window.document.createElement
);
}

/**
* Forces a re-render, similar to `forceUpdate` in class components.
*/
function useForceUpdate() {
const [, dispatch] = useState<{}>(Object.create(null));
return useCallback(() => {
dispatch(Object.create(null));
}, []);
}


export const useIsomorphicLayoutEffect = canUseDOM() ? useLayoutEffect : useEffect;


/**
* Portal from `@reach/portal`
*
* @see Docs https://reach.tech/portal#portal
*/
const PortalImpl: React.FC<PortalProps> = ({
children,
type = "reach-portal",
containerRef,
}) => {
const mountNode = useRef<HTMLDivElement | null>(null);
const portalNode = useRef<HTMLElement | null>(null);
const forceUpdate = useForceUpdate();


useLayoutEffect(() => {
// This ref may be null when a hot-loader replaces components on the page
if (!mountNode.current) {return;}
// It's possible that the content of the portal has, itself, been portaled.
// In that case, it's important to append to the correct document element.
const ownerDocument = mountNode.current.ownerDocument;
const body = containerRef?.current || ownerDocument.body;
portalNode.current = ownerDocument?.createElement(type);
body.appendChild(portalNode.current);
forceUpdate();
return () => {
if (portalNode.current && body) {
body.removeChild(portalNode.current);
}
};
}, [type, forceUpdate, containerRef]);

return portalNode.current ? (
createPortal(children, portalNode.current)
) : (
<span ref={mountNode} />
);
};

export const Portal: React.FC<PortalProps> = ({
unstable_skipInitialRender,
...props
}) => {
const [hydrated, setHydrated] = useState(false);
useEffect(() => {
if (unstable_skipInitialRender) {
setHydrated(true);
}
}, [unstable_skipInitialRender]);
if (unstable_skipInitialRender && !hydrated) {
return null;
}
return <PortalImpl {...props} />;
};


export type PortalProps = PropsWithChildren<{
type?: string;
containerRef?: React.RefObject<Node>;
unstable_skipInitialRender?: boolean;
}>;

Portal.displayName = "Portal";

2 changes: 1 addition & 1 deletion packages/thirdweb-react/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"skipLibCheck": true,
// error out if import and file system have a casing mismatch. Recommended by TS
"forceConsistentCasingInFileNames": true,
"emitDeclarationOnly": true,
"noEmit": true,
"target": "ES6",
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
Expand Down
Loading