thirdweb 5.71.0 → 5.72.0-nightly-a98550d229e7fd124e1977fcc64dbd1b602ce656-20241126000403
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/exports/react.js +8 -1
- package/dist/cjs/exports/react.js.map +1 -1
- package/dist/cjs/react/web/ui/prebuilt/Chain/icon.js +96 -0
- package/dist/cjs/react/web/ui/prebuilt/Chain/icon.js.map +1 -0
- package/dist/cjs/react/web/ui/prebuilt/Chain/name.js +124 -0
- package/dist/cjs/react/web/ui/prebuilt/Chain/name.js.map +1 -0
- package/dist/cjs/react/web/ui/prebuilt/Chain/provider.js +54 -0
- package/dist/cjs/react/web/ui/prebuilt/Chain/provider.js.map +1 -0
- package/dist/cjs/react/web/ui/prebuilt/Token/icon.js.map +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/version.js.map +1 -1
- package/dist/esm/exports/react.js +4 -0
- package/dist/esm/exports/react.js.map +1 -1
- package/dist/esm/react/web/ui/prebuilt/Chain/icon.js +93 -0
- package/dist/esm/react/web/ui/prebuilt/Chain/icon.js.map +1 -0
- package/dist/esm/react/web/ui/prebuilt/Chain/name.js +121 -0
- package/dist/esm/react/web/ui/prebuilt/Chain/name.js.map +1 -0
- package/dist/esm/react/web/ui/prebuilt/Chain/provider.js +50 -0
- package/dist/esm/react/web/ui/prebuilt/Chain/provider.js.map +1 -0
- package/dist/esm/react/web/ui/prebuilt/Token/icon.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/types/exports/react.d.ts +3 -0
- package/dist/types/exports/react.d.ts.map +1 -1
- package/dist/types/react/web/ui/prebuilt/Chain/icon.d.ts +106 -0
- package/dist/types/react/web/ui/prebuilt/Chain/icon.d.ts.map +1 -0
- package/dist/types/react/web/ui/prebuilt/Chain/name.d.ts +142 -0
- package/dist/types/react/web/ui/prebuilt/Chain/name.d.ts.map +1 -0
- package/dist/types/react/web/ui/prebuilt/Chain/provider.d.ts +48 -0
- package/dist/types/react/web/ui/prebuilt/Chain/provider.d.ts.map +1 -0
- package/dist/types/react/web/ui/prebuilt/Token/icon.d.ts +5 -0
- package/dist/types/react/web/ui/prebuilt/Token/icon.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/version.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/exports/react.ts +14 -0
- package/src/react/web/ui/prebuilt/Chain/icon.tsx +154 -0
- package/src/react/web/ui/prebuilt/Chain/name.test.tsx +73 -0
- package/src/react/web/ui/prebuilt/Chain/name.tsx +185 -0
- package/src/react/web/ui/prebuilt/Chain/provider.test.tsx +34 -0
- package/src/react/web/ui/prebuilt/Chain/provider.tsx +73 -0
- package/src/react/web/ui/prebuilt/Token/icon.tsx +5 -0
- package/src/react/web/ui/prebuilt/Token/provider.test.tsx +44 -0
- package/src/react/web/ui/prebuilt/Token/symbol.test.tsx +30 -0
- package/src/version.ts +1 -1
@@ -0,0 +1,73 @@
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
2
|
+
import { render, screen, waitFor } from "~test/react-render.js";
|
3
|
+
import { ethereum } from "../../../../../chains/chain-definitions/ethereum.js";
|
4
|
+
import { defineChain } from "../../../../../chains/utils.js";
|
5
|
+
import { ChainName } from "./name.js";
|
6
|
+
import { ChainProvider } from "./provider.js";
|
7
|
+
|
8
|
+
describe.runIf(process.env.TW_SECRET_KEY)("ChainName component", () => {
|
9
|
+
it("should return the correct chain name, if the name exists in the chain object", () => {
|
10
|
+
render(
|
11
|
+
<ChainProvider chain={ethereum}>
|
12
|
+
<ChainName />
|
13
|
+
</ChainProvider>,
|
14
|
+
);
|
15
|
+
waitFor(() =>
|
16
|
+
expect(
|
17
|
+
screen.getByText("Ethereum", {
|
18
|
+
exact: true,
|
19
|
+
selector: "span",
|
20
|
+
}),
|
21
|
+
).toBeInTheDocument(),
|
22
|
+
);
|
23
|
+
});
|
24
|
+
|
25
|
+
it("should return the correct chain name, if the name is loaded from the server", () => {
|
26
|
+
render(
|
27
|
+
<ChainProvider chain={defineChain(1)}>
|
28
|
+
<ChainName />
|
29
|
+
</ChainProvider>,
|
30
|
+
);
|
31
|
+
waitFor(() =>
|
32
|
+
expect(
|
33
|
+
screen.getByText("Ethereum Mainnet", {
|
34
|
+
exact: true,
|
35
|
+
selector: "span",
|
36
|
+
}),
|
37
|
+
).toBeInTheDocument(),
|
38
|
+
);
|
39
|
+
});
|
40
|
+
|
41
|
+
it("should return the correct FORMATTED chain name", () => {
|
42
|
+
render(
|
43
|
+
<ChainProvider chain={ethereum}>
|
44
|
+
<ChainName formatFn={(str: string) => `${str}-formatted`} />
|
45
|
+
</ChainProvider>,
|
46
|
+
);
|
47
|
+
waitFor(() =>
|
48
|
+
expect(
|
49
|
+
screen.getByText("Ethereum-formatted", {
|
50
|
+
exact: true,
|
51
|
+
selector: "span",
|
52
|
+
}),
|
53
|
+
).toBeInTheDocument(),
|
54
|
+
);
|
55
|
+
});
|
56
|
+
|
57
|
+
it("should fallback properly when fail to resolve chain name", () => {
|
58
|
+
render(
|
59
|
+
<ChainProvider chain={defineChain(-1)}>
|
60
|
+
<ChainName fallbackComponent={<span>oops</span>} />
|
61
|
+
</ChainProvider>,
|
62
|
+
);
|
63
|
+
|
64
|
+
waitFor(() =>
|
65
|
+
expect(
|
66
|
+
screen.getByText("oops", {
|
67
|
+
exact: true,
|
68
|
+
selector: "span",
|
69
|
+
}),
|
70
|
+
).toBeInTheDocument(),
|
71
|
+
);
|
72
|
+
});
|
73
|
+
});
|
@@ -0,0 +1,185 @@
|
|
1
|
+
"use client";
|
2
|
+
|
3
|
+
import { type UseQueryOptions, useQuery } from "@tanstack/react-query";
|
4
|
+
import type React from "react";
|
5
|
+
import type { JSX } from "react";
|
6
|
+
import { getChainMetadata } from "../../../../../chains/utils.js";
|
7
|
+
import { useChainContext } from "./provider.js";
|
8
|
+
|
9
|
+
/**
|
10
|
+
* Props for the ChainName component
|
11
|
+
* @component
|
12
|
+
* @chain
|
13
|
+
*/
|
14
|
+
export interface ChainNameProps
|
15
|
+
extends Omit<React.HTMLAttributes<HTMLSpanElement>, "children"> {
|
16
|
+
/**
|
17
|
+
* This prop can be a string or a (async) function that resolves to a string, representing the name of the chain
|
18
|
+
* This is particularly useful if you already have a way to fetch the chain name.
|
19
|
+
*/
|
20
|
+
nameResolver?: string | (() => string) | (() => Promise<string>);
|
21
|
+
/**
|
22
|
+
* A function to format the name's display value
|
23
|
+
* Particularly useful to avoid overflowing-UI issues
|
24
|
+
*
|
25
|
+
* ```tsx
|
26
|
+
* <ChainName formatFn={(str: string) => doSomething()} />
|
27
|
+
* ```
|
28
|
+
*/
|
29
|
+
formatFn?: (str: string) => string;
|
30
|
+
/**
|
31
|
+
* This component will be shown while the name of the chain is being fetched
|
32
|
+
* If not passed, the component will return `null`.
|
33
|
+
*
|
34
|
+
* You can/should pass a loading sign or spinner to this prop.
|
35
|
+
* @example
|
36
|
+
* ```tsx
|
37
|
+
* <ChainName loadingComponent={<Spinner />} />
|
38
|
+
* ```
|
39
|
+
*/
|
40
|
+
loadingComponent?: JSX.Element;
|
41
|
+
/**
|
42
|
+
* This component will be shown if the name fails to be retreived
|
43
|
+
* If not passed, the component will return `null`.
|
44
|
+
*
|
45
|
+
* You can/should pass a descriptive text/component to this prop, indicating that the
|
46
|
+
* name was not fetched succesfully
|
47
|
+
* @example
|
48
|
+
* ```tsx
|
49
|
+
* <ChainName fallbackComponent={"Failed to load"}
|
50
|
+
* />
|
51
|
+
* ```
|
52
|
+
*/
|
53
|
+
fallbackComponent?: JSX.Element;
|
54
|
+
/**
|
55
|
+
* Optional `useQuery` params
|
56
|
+
*/
|
57
|
+
queryOptions?: Omit<UseQueryOptions<string>, "queryFn" | "queryKey">;
|
58
|
+
}
|
59
|
+
|
60
|
+
/**
|
61
|
+
* This component fetches then shows the name of a chain.
|
62
|
+
* It inherits all the attributes of a HTML <span> component, hence you can style it just like how you would style a normal <span>
|
63
|
+
*
|
64
|
+
*
|
65
|
+
* @example
|
66
|
+
* ### Basic usage
|
67
|
+
* ```tsx
|
68
|
+
* import { ChainProvider, ChainName } from "thirdweb/react";
|
69
|
+
* import { ethereum } from "thirdweb/chains";
|
70
|
+
*
|
71
|
+
* <ChainProvider {...props}>
|
72
|
+
* <ChainName />
|
73
|
+
* </ChainProvider>
|
74
|
+
* ```
|
75
|
+
* Result:
|
76
|
+
* ```html
|
77
|
+
* <span>Ethereum Mainnet</span>
|
78
|
+
* ```
|
79
|
+
*
|
80
|
+
* ### Custom name resolver
|
81
|
+
* By default ChainName will call the thirdweb API to retrieve the chain name.
|
82
|
+
* However if you have a different way to fetch the name, you can pass the function to the `nameResolver` prop.
|
83
|
+
* Note: nameResolver should either be a string or a function (async) that returns a string.
|
84
|
+
* ```tsx
|
85
|
+
* async function fetchNameMethod() {
|
86
|
+
* // your own fetching logic
|
87
|
+
* return "the chain name";
|
88
|
+
* }
|
89
|
+
*
|
90
|
+
* <ChainName nameResolver={fetchNameMethod} />
|
91
|
+
* ```
|
92
|
+
*
|
93
|
+
* Alternatively you can also pass in a string directly:
|
94
|
+
* ```tsx
|
95
|
+
* <ChainName nameResolver="ETH Mainnet" />
|
96
|
+
* ```
|
97
|
+
*
|
98
|
+
*
|
99
|
+
* ### Format the name (capitalize, truncate, etc.)
|
100
|
+
* The ChainName component accepts a `formatFn` which takes in a string and outputs a string
|
101
|
+
* The function is used to modify the name of the chain
|
102
|
+
*
|
103
|
+
* ```tsx
|
104
|
+
* const concatStr = (str: string):string => str + "Network"
|
105
|
+
*
|
106
|
+
* <ChainProvider {...props}>
|
107
|
+
* <ChainName formatFn={concatStr} />
|
108
|
+
* </ChainProvider>
|
109
|
+
* ```
|
110
|
+
*
|
111
|
+
* Result:
|
112
|
+
* ```html
|
113
|
+
* <span>Ethereum Mainnet Network</span>
|
114
|
+
* ```
|
115
|
+
*
|
116
|
+
* ### Show a loading sign when the name is being fetched
|
117
|
+
* ```tsx
|
118
|
+
* import { ChainProvider, ChainName } from "thirdweb/react";
|
119
|
+
*
|
120
|
+
* <ChainProvider {...props}>
|
121
|
+
* <ChainName loadingComponent={<Spinner />} />
|
122
|
+
* </ChainProvider>
|
123
|
+
* ```
|
124
|
+
*
|
125
|
+
* ### Fallback to something when the name fails to resolve
|
126
|
+
* ```tsx
|
127
|
+
* <ChainProvider {...props}>
|
128
|
+
* <ChainName fallbackComponent={"Failed to load"} />
|
129
|
+
* </ChainProvider>
|
130
|
+
* ```
|
131
|
+
*
|
132
|
+
* ### Custom query options for useQuery
|
133
|
+
* This component uses `@tanstack-query`'s useQuery internally.
|
134
|
+
* You can use the `queryOptions` prop for more fine-grained control
|
135
|
+
* ```tsx
|
136
|
+
* <ChainName
|
137
|
+
* queryOptions={{
|
138
|
+
* enabled: isEnabled,
|
139
|
+
* retry: 4,
|
140
|
+
* }}
|
141
|
+
* />
|
142
|
+
* ```
|
143
|
+
*
|
144
|
+
* @component
|
145
|
+
* @chain
|
146
|
+
* @beta
|
147
|
+
*/
|
148
|
+
export function ChainName({
|
149
|
+
nameResolver,
|
150
|
+
formatFn,
|
151
|
+
loadingComponent,
|
152
|
+
fallbackComponent,
|
153
|
+
queryOptions,
|
154
|
+
...restProps
|
155
|
+
}: ChainNameProps) {
|
156
|
+
const { chain } = useChainContext();
|
157
|
+
const nameQuery = useQuery({
|
158
|
+
queryKey: ["_internal_chain_name_", chain.id] as const,
|
159
|
+
queryFn: async () => {
|
160
|
+
if (typeof nameResolver === "string") {
|
161
|
+
return nameResolver;
|
162
|
+
}
|
163
|
+
if (typeof nameResolver === "function") {
|
164
|
+
return nameResolver();
|
165
|
+
}
|
166
|
+
if (chain.name) {
|
167
|
+
return chain.name;
|
168
|
+
}
|
169
|
+
return getChainMetadata(chain).then((data) => data.name);
|
170
|
+
},
|
171
|
+
...queryOptions,
|
172
|
+
});
|
173
|
+
|
174
|
+
if (nameQuery.isLoading) {
|
175
|
+
return loadingComponent || null;
|
176
|
+
}
|
177
|
+
|
178
|
+
if (!nameQuery.data) {
|
179
|
+
return fallbackComponent || null;
|
180
|
+
}
|
181
|
+
|
182
|
+
const displayValue = formatFn ? formatFn(nameQuery.data) : nameQuery.data;
|
183
|
+
|
184
|
+
return <span {...restProps}>{displayValue}</span>;
|
185
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
2
|
+
import { render, screen, waitFor } from "~test/react-render.js";
|
3
|
+
import { ethereum } from "../../../../../chains/chain-definitions/ethereum.js";
|
4
|
+
import { ChainName } from "./name.js";
|
5
|
+
import { ChainProvider } from "./provider.js";
|
6
|
+
|
7
|
+
describe.runIf(process.env.TW_SECRET_KEY)("ChainProvider component", () => {
|
8
|
+
it("should render children correctly", () => {
|
9
|
+
render(
|
10
|
+
<ChainProvider chain={ethereum}>
|
11
|
+
<div>Child Component</div>
|
12
|
+
</ChainProvider>,
|
13
|
+
);
|
14
|
+
|
15
|
+
expect(screen.getByText("Child Component")).toBeInTheDocument();
|
16
|
+
});
|
17
|
+
|
18
|
+
it("should pass the chain correctly to the children props", () => {
|
19
|
+
render(
|
20
|
+
<ChainProvider chain={ethereum}>
|
21
|
+
<ChainName />
|
22
|
+
</ChainProvider>,
|
23
|
+
);
|
24
|
+
|
25
|
+
waitFor(() =>
|
26
|
+
expect(
|
27
|
+
screen.getByText("Ethereum", {
|
28
|
+
exact: true,
|
29
|
+
selector: "span",
|
30
|
+
}),
|
31
|
+
).toBeInTheDocument(),
|
32
|
+
);
|
33
|
+
});
|
34
|
+
});
|
@@ -0,0 +1,73 @@
|
|
1
|
+
"use client";
|
2
|
+
|
3
|
+
import type React from "react";
|
4
|
+
import { createContext, useContext } from "react";
|
5
|
+
import type { Chain } from "../../../../../chains/types.js";
|
6
|
+
|
7
|
+
/**
|
8
|
+
* Props for the <ChainProvider /> component
|
9
|
+
* @component
|
10
|
+
* @chain
|
11
|
+
*/
|
12
|
+
export type ChainProviderProps = {
|
13
|
+
chain: Chain;
|
14
|
+
};
|
15
|
+
|
16
|
+
const ChainProviderContext = /* @__PURE__ */ createContext<
|
17
|
+
ChainProviderProps | undefined
|
18
|
+
>(undefined);
|
19
|
+
|
20
|
+
/**
|
21
|
+
* A React context provider component that supplies Chain-related data to its child components.
|
22
|
+
*
|
23
|
+
* This component serves as a wrapper around the `ChainProviderContext.Provider` and passes
|
24
|
+
* the provided chain data down to all of its child components through the context API.
|
25
|
+
*
|
26
|
+
* @example
|
27
|
+
* ### Basic usage
|
28
|
+
* ```tsx
|
29
|
+
* import { ChainProvider, ChainIcon, ChainName } from "thirdweb/react";
|
30
|
+
* import { ethereum } from "thirdweb/chains";
|
31
|
+
*
|
32
|
+
* <ChainProvider chain={ethereum}>
|
33
|
+
* <ChainIcon />
|
34
|
+
* <ChainName />
|
35
|
+
* </ChainProvider>
|
36
|
+
* ```
|
37
|
+
*
|
38
|
+
* ### Usage with defineChain
|
39
|
+
* ```tsx
|
40
|
+
* import { defineChain } from "thirdweb/chains"l
|
41
|
+
* import { ChainProvider, ChainName } from "thirdweb/react";
|
42
|
+
*
|
43
|
+
* const chainId = someNumber;
|
44
|
+
*
|
45
|
+
* <ChainProvider chain={defineChain(chainId)}>
|
46
|
+
* <ChainName />
|
47
|
+
* </ChainProvider>
|
48
|
+
* ```
|
49
|
+
* @component
|
50
|
+
* @chain
|
51
|
+
*/
|
52
|
+
export function ChainProvider(
|
53
|
+
props: React.PropsWithChildren<ChainProviderProps>,
|
54
|
+
) {
|
55
|
+
return (
|
56
|
+
<ChainProviderContext.Provider value={props}>
|
57
|
+
{props.children}
|
58
|
+
</ChainProviderContext.Provider>
|
59
|
+
);
|
60
|
+
}
|
61
|
+
|
62
|
+
/**
|
63
|
+
* @internal
|
64
|
+
*/
|
65
|
+
export function useChainContext() {
|
66
|
+
const ctx = useContext(ChainProviderContext);
|
67
|
+
if (!ctx) {
|
68
|
+
throw new Error(
|
69
|
+
"ChainProviderContext not found. Make sure you are using ChainName, ChainIcon, etc. inside a <ChainProvider /> component",
|
70
|
+
);
|
71
|
+
}
|
72
|
+
return ctx;
|
73
|
+
}
|
@@ -7,6 +7,11 @@ import { getContractMetadata } from "../../../../../extensions/common/read/getCo
|
|
7
7
|
import { resolveScheme } from "../../../../../utils/ipfs.js";
|
8
8
|
import { useTokenContext } from "./provider.js";
|
9
9
|
|
10
|
+
/**
|
11
|
+
* Props for the TokenIcon component
|
12
|
+
* @component
|
13
|
+
* @token
|
14
|
+
*/
|
10
15
|
export interface TokenIconProps
|
11
16
|
extends Omit<React.ImgHTMLAttributes<HTMLImageElement>, "src"> {
|
12
17
|
/**
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
2
|
+
import { render, screen, waitFor } from "~test/react-render.js";
|
3
|
+
import { TEST_CLIENT } from "~test/test-clients.js";
|
4
|
+
import { ethereum } from "../../../../../chains/chain-definitions/ethereum.js";
|
5
|
+
import { NATIVE_TOKEN_ADDRESS } from "../../../../../constants/addresses.js";
|
6
|
+
import { TokenName } from "./name.js";
|
7
|
+
import { TokenProvider } from "./provider.js";
|
8
|
+
|
9
|
+
describe.runIf(process.env.TW_SECRET_KEY)("TokenProvider component", () => {
|
10
|
+
it("should render children correctly", () => {
|
11
|
+
render(
|
12
|
+
<TokenProvider
|
13
|
+
address={NATIVE_TOKEN_ADDRESS}
|
14
|
+
client={TEST_CLIENT}
|
15
|
+
chain={ethereum}
|
16
|
+
>
|
17
|
+
<div>Child Component</div>
|
18
|
+
</TokenProvider>,
|
19
|
+
);
|
20
|
+
|
21
|
+
expect(screen.getByText("Child Component")).toBeInTheDocument();
|
22
|
+
});
|
23
|
+
|
24
|
+
it("should pass the token data correctly to the children props", () => {
|
25
|
+
render(
|
26
|
+
<TokenProvider
|
27
|
+
address={NATIVE_TOKEN_ADDRESS}
|
28
|
+
client={TEST_CLIENT}
|
29
|
+
chain={ethereum}
|
30
|
+
>
|
31
|
+
<TokenName />
|
32
|
+
</TokenProvider>,
|
33
|
+
);
|
34
|
+
|
35
|
+
waitFor(() =>
|
36
|
+
expect(
|
37
|
+
screen.getByText("Ether", {
|
38
|
+
exact: true,
|
39
|
+
selector: "span",
|
40
|
+
}),
|
41
|
+
).toBeInTheDocument(),
|
42
|
+
);
|
43
|
+
});
|
44
|
+
});
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
2
|
+
import { render, screen, waitFor } from "~test/react-render.js";
|
3
|
+
import { TEST_CLIENT } from "~test/test-clients.js";
|
4
|
+
import { ethereum } from "../../../../../chains/chain-definitions/ethereum.js";
|
5
|
+
import { NATIVE_TOKEN_ADDRESS } from "../../../../../constants/addresses.js";
|
6
|
+
import { TokenProvider } from "./provider.js";
|
7
|
+
import { TokenSymbol } from "./symbol.js";
|
8
|
+
|
9
|
+
describe.runIf(process.env.TW_SECRET_KEY)("TokenSymbol component", () => {
|
10
|
+
it("should pass the address correctly to the children props", () => {
|
11
|
+
render(
|
12
|
+
<TokenProvider
|
13
|
+
address={NATIVE_TOKEN_ADDRESS}
|
14
|
+
client={TEST_CLIENT}
|
15
|
+
chain={ethereum}
|
16
|
+
>
|
17
|
+
<TokenSymbol />
|
18
|
+
</TokenProvider>,
|
19
|
+
);
|
20
|
+
|
21
|
+
waitFor(() =>
|
22
|
+
expect(
|
23
|
+
screen.getByText("ETH", {
|
24
|
+
exact: true,
|
25
|
+
selector: "span",
|
26
|
+
}),
|
27
|
+
).toBeInTheDocument(),
|
28
|
+
);
|
29
|
+
});
|
30
|
+
});
|
package/src/version.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export const version = "5.
|
1
|
+
export const version = "5.72.0-nightly-a98550d229e7fd124e1977fcc64dbd1b602ce656-20241126000403";
|