Skip to content

Commit 99b1117

Browse files
authored
Merge pull request #12 from OpenZeppelin/feature/plat-6727-evm-adapter-enhance-ui-customizations-using-rainbowkits
feat(adapter): add native prop-based ConnectButton customizations
2 parents cac60b9 + ca35f99 commit 99b1117

File tree

7 files changed

+152
-2
lines changed

7 files changed

+152
-2
lines changed

packages/adapter-evm/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import EvmAdapter from './adapter';
33
// Re-export the main adapter class
44
export { EvmAdapter };
55

6+
// Export RainbowKit customization types
7+
export * from './wallet/rainbowkit/types';
8+
69
// Optionally re-export types if they need to be accessible directly
710
// export * from './types';
811

packages/adapter-evm/src/wallet/README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,53 @@ const rainbowKitAppConfig = {
109109
// modalSize: 'compact',
110110
// appInfo: { appName: 'My dApp', learnMoreUrl: 'https://learnmore.example' }
111111
}, // as RainbowKitProviderProps (or a subset for type safety)
112+
113+
// Enhanced UI customizations using RainbowKit's native prop types
114+
customizations: {
115+
connectButton: {
116+
// Uses RainbowKit's native ConnectButton props - no custom types needed!
117+
// Refer to RainbowKit docs: https://www.rainbowkit.com/docs/connect-button
118+
119+
chainStatus: 'none', // Hide network switcher dropdown
120+
accountStatus: 'full', // Show full account info when connected
121+
label: 'Connect Wallet', // Custom connect button text
122+
showBalance: true, // Show/hide balance display
123+
124+
// Responsive configurations are also supported:
125+
// showBalance: {
126+
// smallScreen: false,
127+
// largeScreen: true,
128+
// },
129+
// accountStatus: {
130+
// smallScreen: 'avatar',
131+
// largeScreen: 'full',
132+
// },
133+
},
134+
},
112135
};
113136

114137
export default rainbowKitAppConfig;
115138
```
116139

117140
- **`wagmiParams`**: Contains parameters for RainbowKit's `getDefaultConfig()` (e.g., `appName`, `projectId`). The adapter will use these but will override `chains` and `transports` based on its own `networkConfig` and `AppConfigService` RPC overrides.
118141
- **`providerProps`**: Contains props to be spread onto the `<RainbowKitProvider />` component (e.g., `theme`, `modalSize`).
142+
- **`customizations`**: Enhanced UI customizations that leverage RainbowKit's native prop types directly. This section allows you to configure the ConnectButton component using RainbowKit's official props.
143+
144+
#### RainbowKit ConnectButton Customizations
145+
146+
The `customizations.connectButton` section supports all native RainbowKit ConnectButton props:
147+
148+
- **`chainStatus`**: Controls network switcher visibility
149+
- `'full'`: Show full chain name and icon (default)
150+
- `'icon'`: Show only chain icon
151+
- `'name'`: Show only chain name
152+
- `'none'`: Hide network switcher completely
153+
- **`accountStatus`**: Controls account info display when connected
154+
- `'full'`: Show full account info (default)
155+
- `'avatar'`: Show only avatar
156+
- `'address'`: Show only address
157+
- **`label`**: Custom text for the connect button when disconnected
158+
- **`showBalance`**: Show/hide balance in the button (boolean or responsive object)
119159

120160
### 3. `loadConfigModule` (Application-Provided Importer)
121161

packages/adapter-evm/src/wallet/rainbowkit/components.tsx

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import { cn, logger } from '@openzeppelin/transaction-form-utils';
88

99
import { CustomConnectButton } from '../components';
1010
import { WagmiProviderInitializedContext } from '../context/wagmi-context';
11+
import { evmUiKitManager } from '../evmUiKitManager';
12+
13+
import { extractRainbowKitCustomizations } from './types';
1114

1215
const MIN_COMPONENT_LOADING_DISPLAY_MS = 1000; // 1 second artificial delay
1316

@@ -23,9 +26,18 @@ export const RainbowKitConnectButton: React.FC<BaseComponentProps> = (props) =>
2326
const [isLoadingComponent, setIsLoadingComponent] = useState(true);
2427
const [showComponentLoadingOverride, setShowComponentLoadingOverride] = useState(false);
2528
const componentLoadingTimerRef = useRef<NodeJS.Timeout | null>(null);
29+
const [managerState, setManagerState] = useState(evmUiKitManager.getState());
2630

2731
const isWagmiProviderReady = useContext(WagmiProviderInitializedContext);
2832

33+
// Subscribe to UI kit manager state changes
34+
useEffect(() => {
35+
const unsubscribe = evmUiKitManager.subscribe(() => {
36+
setManagerState(evmUiKitManager.getState());
37+
});
38+
return unsubscribe;
39+
}, []);
40+
2941
useEffect(() => {
3042
let isMounted = true;
3143
setIsLoadingComponent(true);
@@ -109,5 +121,22 @@ export const RainbowKitConnectButton: React.FC<BaseComponentProps> = (props) =>
109121
return <CustomConnectButton {...props} />;
110122
}
111123

112-
return <Component {...props} />;
124+
// Extract custom configuration from the manager state
125+
const kitConfig = managerState.currentFullUiKitConfig?.kitConfig;
126+
const customizations = extractRainbowKitCustomizations(kitConfig);
127+
const connectButtonConfig = customizations?.connectButton;
128+
129+
// Merge props: base props + custom configuration + any overrides from props
130+
// This allows the config to set defaults while still allowing prop overrides
131+
const finalProps = {
132+
...connectButtonConfig, // Apply custom configuration from config
133+
...props, // Allow props to override configuration
134+
};
135+
136+
logger.debug('RainbowKitConnectButton', 'Rendering with configuration:', {
137+
configFromFile: connectButtonConfig,
138+
finalProps: finalProps,
139+
});
140+
141+
return <Component {...finalProps} />;
113142
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './components';
22
export * from './utils';
33
export * from './componentFactory';
4+
export * from './types';
45
export { createRainbowKitWagmiConfig, getWagmiConfigForRainbowKit } from './config-service';
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Custom RainbowKit configuration types for enhanced UI control
3+
*/
4+
/**
5+
* Re-export RainbowKit's native types for ConnectButton props
6+
* This ensures we use the exact same types that RainbowKit expects,
7+
* reducing maintenance burden and letting RainbowKit handle type validation
8+
*/
9+
// Import RainbowKit's native ConnectButton types
10+
import type { ConnectButton } from '@rainbow-me/rainbowkit';
11+
12+
/**
13+
* Extract the props type from RainbowKit's ConnectButton component
14+
* This gives us the exact same types that RainbowKit uses internally
15+
*/
16+
export type RainbowKitConnectButtonProps = React.ComponentProps<typeof ConnectButton>;
17+
18+
/**
19+
* Custom UI configuration that uses RainbowKit's native types
20+
* This extends our configuration system while leveraging RainbowKit's own type definitions
21+
*/
22+
export interface RainbowKitCustomizations {
23+
/**
24+
* Configuration for the RainbowKit ConnectButton component
25+
* Uses RainbowKit's native prop types for type safety and compatibility
26+
*/
27+
connectButton?: Partial<RainbowKitConnectButtonProps>;
28+
}
29+
30+
/**
31+
* Type guard to check if an object contains RainbowKit customizations
32+
*/
33+
export function isRainbowKitCustomizations(obj: unknown): obj is RainbowKitCustomizations {
34+
return typeof obj === 'object' && obj !== null && 'connectButton' in obj;
35+
}
36+
37+
/**
38+
* Utility to extract RainbowKit customizations from a kit config
39+
*/
40+
export function extractRainbowKitCustomizations(
41+
kitConfig: Record<string, unknown> | undefined
42+
): RainbowKitCustomizations | undefined {
43+
if (!kitConfig || !kitConfig.customizations) {
44+
return undefined;
45+
}
46+
47+
const customizations = kitConfig.customizations;
48+
return isRainbowKitCustomizations(customizations) ? customizations : undefined;
49+
}

packages/core/public/app.config.local.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"kitConfig": {
77
"showInjectedConnector": false,
88
"components": {
9-
"exclude": []
9+
"exclude": ["NetworkSwitcher"]
1010
}
1111
}
1212
}

packages/core/src/config/wallet/rainbowkit.config.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// packages/core/src/config/wallet/rainbowkit.config.ts
22
import { type RainbowKitProvider, darkTheme } from '@rainbow-me/rainbowkit';
33

4+
// Import the custom configuration types from the EVM adapter
5+
import type { RainbowKitCustomizations } from '@openzeppelin/transaction-form-adapter-evm';
6+
47
// For WalletConnect project ID, appName, wallets, ssr options for getDefaultConfig
58
// RainbowKit doesn't export a single neat type for all getDefaultConfig options other than `chains` and `transports`.
69
// Users can refer to RainbowKit docs for available options for getDefaultConfig.
@@ -19,6 +22,7 @@ import { type RainbowKitProvider, darkTheme } from '@rainbow-me/rainbowkit';
1922
* The adapter will override `chains` and `transports`.
2023
* - `providerProps`: An object with props for the `<RainbowKitProvider />` component
2124
* (e.g., `theme`, `locale`, `modalSize`, `initialChain`, `appInfo`).
25+
* - `customizations`: Additional UI customizations that use RainbowKit's native prop types
2226
*/
2327

2428
// Infer props type from RainbowKitProvider for stronger typing on the user's side for providerProps.
@@ -48,6 +52,30 @@ const rainbowKitAppConfig = {
4852
learnMoreUrl: 'https://openzeppelin.com',
4953
},
5054
} as Partial<InferredRainbowKitProviderProps>, // User can cast or ensure their object matches
55+
56+
/**
57+
* Custom UI enhancements using RainbowKit's native prop types
58+
* These options extend RainbowKit's functionality using their own type system
59+
* Refer to RainbowKit docs for available props: https://www.rainbowkit.com/docs/connect-button
60+
*/
61+
customizations: {
62+
connectButton: {
63+
// Use RainbowKit's native props directly - no custom types needed!
64+
chainStatus: 'none', // Hide the network switcher dropdown
65+
// accountStatus: 'full', // Default behavior - can be 'full', 'avatar', 'address'
66+
// label: 'Connect Wallet', // Custom connect button text
67+
// showBalance: true, // Show/hide balance - can be boolean or responsive object
68+
// Example responsive configuration:
69+
// showBalance: {
70+
// smallScreen: false,
71+
// largeScreen: true,
72+
// },
73+
// accountStatus: {
74+
// smallScreen: 'avatar',
75+
// largeScreen: 'full',
76+
// },
77+
},
78+
} as RainbowKitCustomizations,
5179
};
5280

5381
export default rainbowKitAppConfig;

0 commit comments

Comments
 (0)