Skip to content

Commit

Permalink
feat: support extending context from parent for web3-config-provider (#…
Browse files Browse the repository at this point in the history
…474)

* feat: support extending context from parent for web3-config-provider

* docs

* chore: changset

* feat: merge locale

* test: add test case

* chore: add lodash to  dep

---------

Co-authored-by: jrr997 <[email protected]>
  • Loading branch information
jrr997 and jrr997 authored Jan 10, 2024
1 parent 10d5962 commit 879548d
Show file tree
Hide file tree
Showing 8 changed files with 335 additions and 186 deletions.
6 changes: 6 additions & 0 deletions .changeset/slow-forks-dance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@ant-design/web3-common': minor
'@ant-design/web3': minor
---

feat: Add extendsContextFromParent props for web3-config-provider
3 changes: 2 additions & 1 deletion packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
"father": "^4.3.8",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.3.3"
"typescript": "^5.3.3",
"lodash": "^4.17.21"
},
"peerDependencies": {
"antd": ">=4.23.0 || >=5.0.0",
Expand Down
2 changes: 2 additions & 0 deletions packages/common/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ export interface UniversalWeb3ProviderInterface {
availableWallets?: Wallet[];
availableChains?: Chain[];

extendsContextFromParent?: boolean;

connect?: (wallet?: Wallet) => Promise<void>;
disconnect?: () => Promise<void>;
switchChain?: (chain: Chain) => Promise<void>;
Expand Down
50 changes: 42 additions & 8 deletions packages/common/src/web3-config-provider/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,52 @@
import React from 'react';
import React, { useMemo } from 'react';
import { merge } from 'lodash';

import defaultLocale from '../locale/default';
import { ConfigContext, type ConfigConsumerProps, type Web3ConfigProviderProps } from './context';

const ProviderChildren: React.FC<ConfigConsumerProps & { children?: React.ReactNode }> = (
props,
) => {
const { children, ...rest } = props;
return <ConfigContext.Provider value={rest}>{children}</ConfigContext.Provider>;
const ProviderChildren: React.FC<
ConfigConsumerProps & { children?: React.ReactNode; parentContext?: ConfigConsumerProps }
> = (props) => {
const { children, parentContext, ...rest } = props;

const config = { ...parentContext };

Object.keys(rest).forEach((key) => {
const typedKey = key as keyof typeof rest;
if (rest[typedKey] !== undefined) {
(config as any)[typedKey] = rest[typedKey];
}
});

const mergeLocale = useMemo(() => {
if (parentContext?.locale && rest.locale) {
return merge(parentContext.locale, rest.locale);
}
return undefined;
}, [parentContext?.locale, rest.locale]);

config.locale = mergeLocale ?? config.locale;

return (
<ConfigContext.Provider value={config as ConfigConsumerProps}>
{children}
</ConfigContext.Provider>
);
};

const Web3ConfigProvider: React.FC<Web3ConfigProviderProps> = (props) => {
const { locale, ...restProps } = props;
return <ProviderChildren {...restProps} defaultLocale={defaultLocale} locale={locale} />;
const { extendsContextFromParent = true, ...restProps } = props;
const parentContext = React.useContext(ConfigContext);
const context = extendsContextFromParent ? parentContext : undefined;

return (
<ProviderChildren
{...restProps}
defaultLocale={defaultLocale}
parentContext={context}
extendsContextFromParent={extendsContextFromParent}
/>
);
};

export { Web3ConfigProvider };
Expand Down
107 changes: 104 additions & 3 deletions packages/web3/src/web3-config-provider/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import React from 'react';
import React, { useContext } from 'react';
import {
ConfigContext,
ConnectButton,
useAccount,
useNFT,
Web3ConfigProvider,
type Account,
} from '@ant-design/web3';
import type { Web3ConfigProviderProps } from '@ant-design/web3-common';
import { render } from '@testing-library/react';
import { fireEvent, render } from '@testing-library/react';
import { Spin } from 'antd';
import { describe, expect, it } from 'vitest';
import { describe, expect, it, vi } from 'vitest';

const baseProps: Web3ConfigProviderProps = {
availableWallets: [
Expand Down Expand Up @@ -152,4 +153,104 @@ describe('web3-config-provider', () => {
const { baseElement } = render(<App />);
expect(baseElement).toMatchSnapshot();
});
it('extendable', () => {
const Child: React.FC = () => {
const { account, balance } = useContext(ConfigContext);
return (
<>
<div id="account-name">{account?.name}</div>
<div id="balance">{balance?.value?.toString()}</div>
</>
);
};

const App: React.FC = () => {
return (
<Web3ConfigProvider
account={{
name: 'testAccount',
address: '0x123456789',
}}
balance={{ value: 200n }}
>
<Web3ConfigProvider balance={{ value: 100n }}>
<Child />
</Web3ConfigProvider>
</Web3ConfigProvider>
);
};

const { baseElement } = render(<App />);
expect(baseElement.querySelector('#account-name')?.textContent).toBe('testAccount');
expect(baseElement.querySelector('#balance')?.textContent).toBe('100');
});
it('should not extend from parent', () => {
const Child: React.FC = () => {
const { account, balance } = useContext(ConfigContext);
return (
<>
<div id="account-name">{account?.name}</div>
<div id="balance">{balance?.value?.toString()}</div>
</>
);
};

const App: React.FC = () => {
return (
<Web3ConfigProvider
account={{
name: 'testAccount',
address: '0x123456789',
}}
balance={{ value: 200n }}
>
<Web3ConfigProvider extendsContextFromParent={false} balance={{ value: 100n }}>
<Child />
</Web3ConfigProvider>
</Web3ConfigProvider>
);
};

const { baseElement } = render(<App />);
expect(baseElement.querySelector('#account-name')?.textContent).toBeFalsy();
expect(baseElement.querySelector('#balance')?.textContent).toBe('100');
});
it('merge locale', async () => {
const { baseElement } = render(
<Web3ConfigProvider
locale={{
ConnectButton: {
disconnect: 'Parent Disconnect',
copyAddress: 'Parent Copy Address',
},
}}
>
<Web3ConfigProvider
locale={{
ConnectButton: {
copyAddress: 'Child Copy Address',
},
}}
>
<ConnectButton
account={{
address: '0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B',
}}
/>
</Web3ConfigProvider>
</Web3ConfigProvider>,
);

fireEvent.click(baseElement.querySelector('.ant-web3-connect-button') as Element);
await vi.waitFor(() => {
expect(
baseElement.querySelector('.ant-modal-footer')!.querySelectorAll('.ant-btn')[0]
.childNodes[0].textContent,
).toBe('Child Copy Address');
expect(
baseElement.querySelector('.ant-modal-footer')!.querySelectorAll('.ant-btn')[1]
.childNodes[0].textContent,
).toBe('Parent Disconnect');
});
});
});
1 change: 1 addition & 0 deletions packages/web3/src/web3-config-provider/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Provide global configuration and states for components.
| balance | Balance | [Balance](/components/connect-button#balance-1) | - | |
| availableWallets | List of available wallets | [Wallet](/components/types#wallet)\[] | - | |
| availableChains | List of available chains | [Chain](/components/types#chain)\[] | - | |
| extendsContextFromParent | extends context from parent `Provider` | `boolean` | `true` | |
| connect | Connect to the chain | `(wallet?: Wallet) => Promise<void>` | - | |
| disconnect | Disconnect from the chain | `() => Promise<void>` | - | |
| switchChain | Switch to another chain | `(chain: Chain) => Promise<void>` | - | |
Expand Down
1 change: 1 addition & 0 deletions packages/web3/src/web3-config-provider/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ group:
| balance | 当前连接的账户余额 | [Balance](/components/connect-button#balance-1) | - | |
| availableWallets | 可用钱包列表 | [Wallet](/components/types#wallet)\[] | - | |
| availableChains | 可用链列表 | [Chain](/components/types#chain)\[] | - | |
| extendsContextFromParent | 继承父级 `Provider` 的值 | `boolean` | `true` | |
| connect | 连接链 | `(wallet?: Wallet) => Promise<void>` | - | |
| disconnect | 断开连接 | `() => Promise<void>` | - | |
| switchChain | 切换链 | `(chain: Chain) => Promise<void>` | - | |
Expand Down
Loading

0 comments on commit 879548d

Please sign in to comment.