@openzeppelin/contracts-ui-builder-react-core
Version:
Core React context providers and hooks for the OpenZeppelin Contracts UI Builder.
1 lines • 56.7 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts","../src/hooks/AdapterContext.tsx","../src/hooks/AdapterProvider.tsx","../src/hooks/WalletStateContext.tsx","../src/hooks/WalletStateProvider.tsx","../src/hooks/useAdapterContext.ts","../src/hooks/useDerivedAccountStatus.ts","../src/hooks/useDerivedSwitchChainStatus.ts","../src/hooks/useDerivedChainInfo.ts","../src/hooks/useDerivedConnectStatus.ts","../src/hooks/useDerivedDisconnect.ts","../src/components/WalletConnectionHeader.tsx","../src/components/WalletConnectionUI.tsx","../src/components/WalletConnectionWithSettings.tsx"],"sourcesContent":["// Contexts and Providers\nexport {\n AdapterContext,\n type AdapterContextValue,\n type AdapterRegistry,\n} from './hooks/AdapterContext';\nexport { AdapterProvider, type AdapterProviderProps } from './hooks/AdapterProvider';\nexport { WalletStateContext, type WalletStateContextValue } from './hooks/WalletStateContext';\nexport { WalletStateProvider, type WalletStateProviderProps } from './hooks/WalletStateProvider';\n\n// Consumer Hooks\nexport { useAdapterContext } from './hooks/useAdapterContext';\nexport { useWalletState } from './hooks/WalletStateContext';\nexport {\n useDerivedAccountStatus,\n type DerivedAccountStatus,\n} from './hooks/useDerivedAccountStatus';\nexport {\n useDerivedSwitchChainStatus,\n type DerivedSwitchChainStatus,\n} from './hooks/useDerivedSwitchChainStatus';\nexport { useDerivedChainInfo, type DerivedChainInfo } from './hooks/useDerivedChainInfo';\nexport {\n useDerivedConnectStatus,\n type DerivedConnectStatus,\n} from './hooks/useDerivedConnectStatus';\nexport { useDerivedDisconnect, type DerivedDisconnectStatus } from './hooks/useDerivedDisconnect';\n\n// UI Components\nexport { WalletConnectionHeader } from './components/WalletConnectionHeader';\nexport { WalletConnectionUI } from './components/WalletConnectionUI';\nexport { WalletConnectionWithSettings } from './components/WalletConnectionWithSettings';\n","/**\n * AdapterContext.tsx\n *\n * This file defines the React Context used for the adapter singleton pattern.\n * It provides types and the context definition, but the actual implementation\n * is in the AdapterProvider component.\n *\n * The adapter singleton pattern ensures that only one adapter instance exists\n * per network configuration, which is critical for consistent wallet connection\n * state across the application.\n */\nimport { createContext } from 'react';\n\nimport type { ContractAdapter, NetworkConfig } from '@openzeppelin/contracts-ui-builder-types';\n\n/**\n * Registry type that maps network IDs to their corresponding adapter instances\n * This is the core data structure for the singleton pattern\n */\nexport interface AdapterRegistry {\n [networkId: string]: ContractAdapter;\n}\n\n/**\n * Context value interface defining what's provided through the context\n * The main functionality is getAdapterForNetwork which either returns\n * an existing adapter or initiates loading of a new one\n */\nexport interface AdapterContextValue {\n getAdapterForNetwork: (networkConfig: NetworkConfig | null) => {\n adapter: ContractAdapter | null;\n isLoading: boolean;\n };\n}\n\n/**\n * The React Context that provides adapter registry access throughout the app\n * Components can access this through the useAdapterContext hook\n */\nexport const AdapterContext = createContext<AdapterContextValue | null>(null);\n","/**\n * AdapterProvider.tsx\n *\n * This file implements the Adapter Provider component which manages a registry of\n * adapter instances. It's a key part of the adapter singleton pattern which ensures\n * that only one adapter instance exists per network configuration.\n *\n * The adapter registry is shared across the application via React Context, allowing\n * components to access the same adapter instances and maintain consistent wallet\n * connection state.\n *\n * IMPORTANT: This implementation needs special care to avoid React state update errors\n * during component rendering. Direct state updates during render are not allowed, which\n * is why adapter loading is controlled carefully.\n */\nimport { ReactNode, useCallback, useEffect, useMemo, useState } from 'react';\n\nimport type { ContractAdapter, NetworkConfig } from '@openzeppelin/contracts-ui-builder-types';\nimport { logger } from '@openzeppelin/contracts-ui-builder-utils';\n\nimport { AdapterContext, AdapterContextValue, AdapterRegistry } from './AdapterContext';\n\nexport interface AdapterProviderProps {\n children: ReactNode;\n /** Function to resolve/create an adapter instance for a given NetworkConfig. */\n resolveAdapter: (networkConfig: NetworkConfig) => Promise<ContractAdapter>;\n}\n\n/**\n * Provider component that manages adapter instances centrally\n * to avoid creating multiple instances of the same adapter.\n *\n * This component:\n * 1. Maintains a registry of adapter instances by network ID\n * 2. Tracks loading states for adapters being initialized\n * 3. Provides a function to get or load adapters for specific networks\n * 4. Ensures adapter instances are reused when possible\n */\nexport function AdapterProvider({ children, resolveAdapter }: AdapterProviderProps) {\n // Registry to store adapter instances by network ID\n const [adapterRegistry, setAdapterRegistry] = useState<AdapterRegistry>({});\n\n // Track loading states by network ID\n const [loadingNetworks, setLoadingNetworks] = useState<Set<string>>(new Set());\n\n // Log registry status on changes\n useEffect(() => {\n const adapterCount = Object.keys(adapterRegistry).length;\n if (adapterCount > 0) {\n logger.info('AdapterProvider', `Registry contains ${adapterCount} adapters:`, {\n networkIds: Object.keys(adapterRegistry),\n loadingCount: loadingNetworks.size,\n loadingNetworkIds: Array.from(loadingNetworks),\n });\n }\n }, [adapterRegistry, loadingNetworks]);\n\n /**\n * Function to get or create an adapter for a network\n *\n * IMPORTANT: The actual adapter loading is handled in the useConfiguredAdapterSingleton hook\n * to avoid React state updates during render, which would cause errors.\n *\n * This function:\n * 1. Returns existing adapters immediately if available\n * 2. Reports loading state for adapters being initialized\n * 3. Initiates adapter loading when needed\n */\n const getAdapterForNetwork = useCallback(\n (networkConfig: NetworkConfig | null) => {\n if (!networkConfig) {\n return { adapter: null, isLoading: false };\n }\n\n const networkId = networkConfig.id;\n\n // Debug log to track adapter requests\n logger.debug('AdapterProvider', `Adapter requested for network ${networkId}`);\n\n // If we already have this adapter, return it\n if (adapterRegistry[networkId]) {\n logger.debug('AdapterProvider', `Using existing adapter for network ${networkId}`);\n return {\n adapter: adapterRegistry[networkId],\n isLoading: false,\n };\n }\n\n // If we're already loading this adapter, indicate loading\n if (loadingNetworks.has(networkId)) {\n logger.debug('AdapterProvider', `Adapter for network ${networkId} is currently loading`);\n return {\n adapter: null,\n isLoading: true,\n };\n }\n\n // Start loading the adapter\n // NOTE: This state update during render is handled safely in the useConfiguredAdapterSingleton hook\n setLoadingNetworks((prev) => {\n const newSet = new Set(prev);\n newSet.add(networkId);\n return newSet;\n });\n\n logger.info(\n 'AdapterProvider',\n `Starting adapter initialization for network ${networkId} (${networkConfig.name})`\n );\n\n // Use the passed-in resolveAdapter function\n void resolveAdapter(networkConfig)\n .then((adapter) => {\n logger.info('AdapterProvider', `Adapter for network ${networkId} loaded successfully`, {\n type: adapter.constructor.name,\n objectId: Object.prototype.toString.call(adapter),\n });\n\n // Update registry with new adapter\n setAdapterRegistry((prev) => ({\n ...prev,\n [networkId]: adapter,\n }));\n\n // Remove from loading networks\n setLoadingNetworks((prev) => {\n const newSet = new Set(prev);\n newSet.delete(networkId);\n return newSet;\n });\n })\n .catch((error) => {\n logger.error('AdapterProvider', `Error loading adapter for network ${networkId}:`, error);\n\n // Remove from loading networks on error\n setLoadingNetworks((prev) => {\n const newSet = new Set(prev);\n newSet.delete(networkId);\n return newSet;\n });\n });\n\n return {\n adapter: null,\n isLoading: true,\n };\n },\n [adapterRegistry, loadingNetworks, resolveAdapter]\n );\n\n // Memoize context value to prevent unnecessary re-renders\n const contextValue = useMemo<AdapterContextValue>(\n () => ({\n getAdapterForNetwork,\n }),\n [getAdapterForNetwork]\n );\n\n return <AdapterContext.Provider value={contextValue}>{children}</AdapterContext.Provider>;\n}\n","import React, { createContext } from 'react';\n\nimport type {\n ContractAdapter,\n EcosystemSpecificReactHooks,\n NetworkConfig,\n UiKitConfiguration,\n} from '@openzeppelin/contracts-ui-builder-types';\n\nexport interface WalletStateContextValue {\n // Globally selected network state\n activeNetworkId: string | null;\n setActiveNetworkId: (networkId: string | null) => void;\n activeNetworkConfig: NetworkConfig | null;\n\n // Active adapter state\n activeAdapter: ContractAdapter | null;\n isAdapterLoading: boolean;\n\n // Facade hooks object from the active adapter\n // Consumers will call these hooks (e.g., walletFacadeHooks.useAccount())\n walletFacadeHooks: EcosystemSpecificReactHooks | null;\n reconfigureActiveAdapterUiKit: (uiKitConfig?: Partial<UiKitConfiguration>) => void;\n}\n\nexport const WalletStateContext = createContext<WalletStateContextValue | undefined>(undefined);\n\n// Hook to easily consume the context\nexport function useWalletState(): WalletStateContextValue {\n const context = React.useContext(WalletStateContext);\n if (context === undefined) {\n throw new Error('useWalletState must be used within a WalletStateProvider');\n }\n return context;\n}\n","import React, { ReactNode, useCallback, useEffect, useMemo, useState } from 'react';\n\nimport type {\n ContractAdapter,\n EcosystemReactUiProviderProps,\n EcosystemSpecificReactHooks,\n NativeConfigLoader,\n NetworkConfig,\n UiKitConfiguration,\n} from '@openzeppelin/contracts-ui-builder-types';\nimport { logger } from '@openzeppelin/contracts-ui-builder-utils';\n\nimport { useAdapterContext } from './useAdapterContext';\nimport { WalletStateContext, type WalletStateContextValue } from './WalletStateContext';\n\n// Extended adapter interface that includes the callback-based configureUiKit method\ninterface ExtendedContractAdapter extends ContractAdapter {\n configureUiKit?(\n config: Partial<UiKitConfiguration>,\n options?: {\n loadUiKitNativeConfig?: (kitName: string) => Promise<Record<string, unknown> | null>;\n }\n ): void | Promise<void>;\n lastFullUiKitConfiguration?: UiKitConfiguration | null;\n getEcosystemReactUiContextProvider?():\n | React.ComponentType<EcosystemReactUiProviderProps>\n | undefined;\n}\n\nexport interface WalletStateProviderProps {\n children: ReactNode;\n /** Optional initial network ID to set as active when the provider mounts. */\n initialNetworkId?: string | null;\n /** Function to retrieve a NetworkConfig object by its ID. */\n getNetworkConfigById: (\n networkId: string\n ) => Promise<NetworkConfig | null | undefined> | NetworkConfig | null | undefined;\n /**\n * Optional generic function to load configuration modules by relative path.\n * The adapter is responsible for constructing the conventional path (e.g., './config/wallet/[kitName].config').\n * @param relativePath The conventional relative path to the configuration module.\n * @returns A Promise resolving to the configuration object (expected to have a default export) or null.\n */\n loadConfigModule?: NativeConfigLoader;\n}\n\n/**\n * Configures the adapter's UI kit and returns the UI provider component and hooks.\n */\nasync function configureAdapterUiKit(\n adapter: ExtendedContractAdapter,\n loadConfigModule?: (relativePath: string) => Promise<Record<string, unknown> | null>,\n programmaticOverrides: Partial<UiKitConfiguration> = {}\n): Promise<{\n providerComponent: React.ComponentType<EcosystemReactUiProviderProps> | null;\n hooks: EcosystemSpecificReactHooks | null;\n}> {\n try {\n // Ensure the adapter (and thus the EvmUiKitManager) is configured.\n if (typeof adapter.configureUiKit === 'function') {\n logger.info(\n '[WSP configureAdapterUiKit] Calling configureUiKit for adapter:',\n adapter?.networkConfig?.id\n );\n await adapter.configureUiKit(programmaticOverrides, {\n loadUiKitNativeConfig: loadConfigModule,\n });\n logger.info(\n '[WSP configureAdapterUiKit] configureUiKit completed for adapter:',\n adapter?.networkConfig?.id\n );\n }\n\n const providerComponent = adapter.getEcosystemReactUiContextProvider?.() || null;\n const hooks = adapter.getEcosystemReactHooks?.() || null;\n\n logger.info('[WSP configureAdapterUiKit]', 'UI provider and hooks retrieved successfully.');\n\n return { providerComponent, hooks };\n } catch (error) {\n logger.error('[WSP configureAdapterUiKit]', 'Error during adapter UI setup:', error);\n throw error; // Re-throw to be handled by caller\n }\n}\n\n/**\n * @name WalletStateProvider\n * @description This provider is a central piece of the application's state management for wallet and network interactions.\n * It is responsible for:\n * 1. Managing the globally selected active network ID (`activeNetworkId`).\n * 2. Deriving the full `NetworkConfig` object (`activeNetworkConfig`) for the active network.\n * 3. Fetching and providing the corresponding `ContractAdapter` instance (`activeAdapter`) for the active network,\n * leveraging the `AdapterProvider` to ensure adapter singletons.\n * 4. Storing and providing the `EcosystemSpecificReactHooks` (`walletFacadeHooks`) from the active adapter.\n * 5. Rendering the adapter-specific UI context provider (e.g., WagmiProvider for EVM) around its children,\n * which is essential for the facade hooks to function correctly.\n * 6. Providing a function (`setActiveNetworkId`) to change the globally active network.\n *\n * Consumers use the `useWalletState()` hook to access this global state.\n * It should be placed high in the component tree, inside an `<AdapterProvider>`.\n */\nexport function WalletStateProvider({\n children,\n initialNetworkId = null,\n getNetworkConfigById,\n loadConfigModule,\n}: WalletStateProviderProps) {\n // State for the ID of the globally selected network.\n const [currentGlobalNetworkId, setCurrentGlobalNetworkIdState] = useState<string | null>(\n initialNetworkId\n );\n // State for the full NetworkConfig object of the globally selected network.\n const [currentGlobalNetworkConfig, setCurrentGlobalNetworkConfig] =\n useState<NetworkConfig | null>(null);\n\n // State for the active ContractAdapter instance corresponding to the currentGlobalNetworkConfig.\n const [globalActiveAdapter, setGlobalActiveAdapter] = useState<ContractAdapter | null>(null);\n // Loading state for the globalActiveAdapter.\n const [isGlobalAdapterLoading, setIsGlobalAdapterLoading] = useState<boolean>(false);\n // State for the facade hooks provided by the globalActiveAdapter.\n const [walletFacadeHooks, setWalletFacadeHooks] = useState<EcosystemSpecificReactHooks | null>(\n null\n );\n // State to hold the Component Type\n const [AdapterUiContextProviderToRender, setAdapterUiContextProviderToRender] =\n useState<React.ComponentType<EcosystemReactUiProviderProps> | null>(null);\n\n // New state to act as a manual trigger for re-configuring the UI kit.\n const [uiKitConfigVersion, setUiKitConfigVersion] = useState(0);\n // State to hold programmatic overrides for the next reconfiguration.\n const [programmaticUiKitConfig, setProgrammaticUiKitConfig] = useState<\n Partial<UiKitConfiguration> | undefined\n >(undefined);\n\n // Consume AdapterContext to get the function for fetching adapter instances.\n const { getAdapterForNetwork } = useAdapterContext();\n\n // Effect to derive the full NetworkConfig object when currentGlobalNetworkId changes.\n useEffect(() => {\n const abortController = new AbortController();\n\n async function fetchNetworkConfig() {\n if (!currentGlobalNetworkId) {\n // If currentGlobalNetworkId is null, clear the config.\n if (!abortController.signal.aborted) {\n setCurrentGlobalNetworkConfig(null);\n }\n return;\n }\n\n try {\n const config = await Promise.resolve(getNetworkConfigById(currentGlobalNetworkId));\n if (!abortController.signal.aborted) {\n setCurrentGlobalNetworkConfig(config || null);\n }\n } catch (error) {\n if (!abortController.signal.aborted) {\n logger.error('[WSP fetchNetworkConfig]', 'Failed to fetch network config:', error);\n setCurrentGlobalNetworkConfig(null);\n }\n }\n }\n\n void fetchNetworkConfig();\n return () => abortController.abort();\n }, [currentGlobalNetworkId, getNetworkConfigById]);\n\n // Effect to load the active adapter and its UI capabilities when currentGlobalNetworkConfig changes.\n useEffect(() => {\n const abortController = new AbortController();\n\n async function loadAdapterAndConfigureUi() {\n if (!currentGlobalNetworkConfig) {\n // No network config - clear everything\n if (!abortController.signal.aborted) {\n setGlobalActiveAdapter(null);\n setIsGlobalAdapterLoading(false);\n setAdapterUiContextProviderToRender(null);\n setWalletFacadeHooks(null);\n }\n return;\n }\n\n const { adapter: newAdapter, isLoading: newIsLoading } = getAdapterForNetwork(\n currentGlobalNetworkConfig\n ) as { adapter: ExtendedContractAdapter | null; isLoading: boolean };\n\n if (abortController.signal.aborted) return;\n\n setGlobalActiveAdapter(newAdapter);\n setIsGlobalAdapterLoading(newIsLoading);\n\n if (newAdapter && !newIsLoading) {\n try {\n const { providerComponent, hooks } = await configureAdapterUiKit(\n newAdapter,\n loadConfigModule,\n programmaticUiKitConfig\n );\n\n if (!abortController.signal.aborted) {\n // We use the functional update form `() => providerComponent` here to ensure\n // that React sets the state to the component type itself, rather than trying\n // to execute the component function as if it were a state updater.\n setAdapterUiContextProviderToRender(() => providerComponent);\n setWalletFacadeHooks(hooks);\n }\n } catch (error) {\n if (!abortController.signal.aborted) {\n logger.error(\n '[WSP loadAdapterAndConfigureUi]',\n 'Error during adapter UI setup:',\n error\n );\n setAdapterUiContextProviderToRender(null);\n setWalletFacadeHooks(null);\n }\n }\n } else if (!newAdapter && !newIsLoading) {\n // Adapter is null and not loading, clear UI specific state\n if (!abortController.signal.aborted) {\n setAdapterUiContextProviderToRender(null);\n setWalletFacadeHooks(null);\n }\n }\n // If newIsLoading is true, retain previous AdapterUiContextProviderToRender and hooks\n // to prevent UI flicker, EvmWalletUiRoot will handle its loading state internally.\n }\n\n void loadAdapterAndConfigureUi();\n return () => abortController.abort();\n }, [\n currentGlobalNetworkConfig,\n getAdapterForNetwork,\n loadConfigModule,\n uiKitConfigVersion,\n programmaticUiKitConfig,\n ]);\n\n /**\n * Callback to set the globally active network ID.\n * Also clears dependent states (config, adapter, hooks) if the network ID is cleared.\n */\n const setActiveNetworkIdCallback = useCallback((networkId: string | null) => {\n logger.info('WalletStateProvider', `Setting global network ID to: ${networkId}`);\n setCurrentGlobalNetworkIdState(networkId); // This will trigger the fetchNetworkConfig effect.\n if (!networkId) {\n // If clearing the network, proactively clear downstream states.\n // The effects above will also clear them, but this is more immediate.\n setCurrentGlobalNetworkConfig(null);\n setGlobalActiveAdapter(null);\n setIsGlobalAdapterLoading(false);\n setWalletFacadeHooks(null);\n // Do not clear AdapterUiContextProviderToRender here, let the effect handle it\n // based on whether it's a loading transition or an actual clearing.\n // setAdapterUiContextProviderToRender(() => null);\n }\n }, []); // Empty dependency array as it only uses setters from useState.\n\n /**\n * Callback to explicitly trigger a re-configuration of the active adapter's UI kit.\n * This is useful when a UI kit setting changes (e.g., via a wizard) without a network change.\n */\n const reconfigureActiveAdapterUiKit = useCallback(\n (uiKitConfig?: Partial<UiKitConfiguration>) => {\n logger.info(\n 'WalletStateProvider',\n 'Explicitly triggering UI kit re-configuration by bumping version.',\n uiKitConfig\n );\n setProgrammaticUiKitConfig(uiKitConfig);\n setUiKitConfigVersion((v) => v + 1);\n },\n [setProgrammaticUiKitConfig, setUiKitConfigVersion]\n );\n\n // The context value now only provides the raw walletFacadeHooks object.\n // Consumers are responsible for calling specific hooks from it and handling their results.\n const contextValue = useMemo<WalletStateContextValue>(\n () => ({\n activeNetworkId: currentGlobalNetworkId,\n setActiveNetworkId: setActiveNetworkIdCallback,\n activeNetworkConfig: currentGlobalNetworkConfig,\n activeAdapter: globalActiveAdapter,\n isAdapterLoading: isGlobalAdapterLoading,\n walletFacadeHooks,\n reconfigureActiveAdapterUiKit,\n }),\n [\n currentGlobalNetworkId,\n setActiveNetworkIdCallback,\n currentGlobalNetworkConfig,\n globalActiveAdapter,\n isGlobalAdapterLoading,\n walletFacadeHooks,\n reconfigureActiveAdapterUiKit,\n ]\n );\n\n const ActualProviderToRender = AdapterUiContextProviderToRender;\n let childrenToRender: ReactNode;\n\n if (ActualProviderToRender) {\n const key = (globalActiveAdapter as ExtendedContractAdapter)?.lastFullUiKitConfiguration\n ?.kitName;\n // EvmWalletUiRoot (and similar for other adapters) no longer needs uiKitConfiguration prop\n // as it manages its own configuration internally via the EvmUiKitManager or equivalent.\n logger.info(\n '[WSP RENDER]',\n 'Rendering adapter-provided UI context provider:',\n ActualProviderToRender.displayName || ActualProviderToRender.name || 'UnknownComponent'\n );\n childrenToRender = <ActualProviderToRender key={key}>{children}</ActualProviderToRender>;\n } else {\n logger.info(\n '[WSP RENDER]',\n 'No adapter UI context provider to render. Rendering direct children.'\n );\n childrenToRender = children;\n }\n\n return (\n <WalletStateContext.Provider value={contextValue}>\n {childrenToRender}\n </WalletStateContext.Provider>\n );\n}\n","/**\n * useAdapterContext.ts\n *\n * This file provides a hook to access the AdapterContext throughout the application.\n * It's a critical part of the adapter singleton pattern, allowing components to\n * access the centralized adapter registry.\n *\n * The adapter singleton pattern ensures:\n * - Only one adapter instance exists per network\n * - Wallet connection state is consistent across the app\n * - Better performance by eliminating redundant adapter initialization\n */\nimport { useContext } from 'react';\n\nimport { AdapterContext, AdapterContextValue } from './AdapterContext';\n\n/**\n * Hook to access the adapter context\n *\n * This hook provides access to the getAdapterForNetwork function which\n * retrieves or creates adapter instances from the singleton registry.\n *\n * Components should typically use useConfiguredAdapterSingleton instead\n * of this hook directly, as it handles React state update timing properly.\n *\n * @throws Error if used outside of an AdapterProvider context\n * @returns The adapter context value\n */\nexport function useAdapterContext(): AdapterContextValue {\n const context = useContext(AdapterContext);\n\n if (!context) {\n throw new Error('useAdapterContext must be used within an AdapterProvider');\n }\n\n return context;\n}\n","// Assumes WalletStateContext exports useWalletState\nimport { isRecordWithProperties } from '@openzeppelin/contracts-ui-builder-utils';\n\nimport { useWalletState } from './WalletStateContext';\n\nexport interface DerivedAccountStatus {\n isConnected: boolean;\n address?: string;\n chainId?: number;\n // Potentially add other commonly used and safely extracted properties from useAccount's result\n}\n\nconst defaultAccountStatus: DerivedAccountStatus = {\n isConnected: false,\n address: undefined,\n chainId: undefined,\n};\n\n/**\n * A custom hook that consumes useWalletState to get the walletFacadeHooks,\n * then calls the useAccount facade hook (if available) and returns a structured,\n * safely-accessed account status (isConnected, address, chainId).\n * Provides default values if the hook or its properties are unavailable.\n */\nexport function useDerivedAccountStatus(): DerivedAccountStatus {\n const { walletFacadeHooks } = useWalletState();\n\n // Call the useAccount hook from the facade\n const accountHookOutput = walletFacadeHooks?.useAccount\n ? walletFacadeHooks.useAccount()\n : undefined;\n\n if (isRecordWithProperties(accountHookOutput)) {\n const isConnected =\n 'isConnected' in accountHookOutput && typeof accountHookOutput.isConnected === 'boolean'\n ? accountHookOutput.isConnected\n : defaultAccountStatus.isConnected;\n const address =\n 'address' in accountHookOutput && typeof accountHookOutput.address === 'string'\n ? accountHookOutput.address\n : defaultAccountStatus.address;\n const chainId =\n 'chainId' in accountHookOutput && typeof accountHookOutput.chainId === 'number'\n ? accountHookOutput.chainId\n : defaultAccountStatus.chainId;\n return { isConnected, address, chainId };\n }\n return defaultAccountStatus;\n}\n","import { isRecordWithProperties } from '@openzeppelin/contracts-ui-builder-utils';\n\nimport { useWalletState } from './WalletStateContext';\n\n// Define the expected return shape for the derived hook\nexport interface DerivedSwitchChainStatus {\n /** Function to initiate a network switch. Undefined if not available. */\n switchChain?: (args: { chainId: number }) => void;\n /** True if a network switch is currently in progress. */\n isSwitching: boolean;\n /** Error object if the last switch attempt failed, otherwise null. */\n error: Error | null;\n}\n\nconst defaultSwitchChainStatus: DerivedSwitchChainStatus = {\n switchChain: undefined,\n isSwitching: false,\n error: null,\n};\n\n/**\n * A custom hook that consumes `useWalletState` to get `walletFacadeHooks`,\n * then calls the `useSwitchChain` facade hook (if available) and returns a structured,\n * safely-accessed status and control function for network switching.\n * Provides default values if the hook or its properties are unavailable.\n */\nexport function useDerivedSwitchChainStatus(): DerivedSwitchChainStatus {\n const { walletFacadeHooks } = useWalletState();\n\n const switchChainHookOutput = walletFacadeHooks?.useSwitchChain\n ? walletFacadeHooks.useSwitchChain()\n : undefined;\n\n if (isRecordWithProperties(switchChainHookOutput)) {\n const execSwitchFn =\n 'switchChain' in switchChainHookOutput &&\n typeof switchChainHookOutput.switchChain === 'function'\n ? (switchChainHookOutput.switchChain as (args: { chainId: number }) => void)\n : defaultSwitchChainStatus.switchChain;\n\n const isPending =\n 'isPending' in switchChainHookOutput && typeof switchChainHookOutput.isPending === 'boolean'\n ? switchChainHookOutput.isPending\n : defaultSwitchChainStatus.isSwitching;\n\n const err =\n 'error' in switchChainHookOutput && switchChainHookOutput.error instanceof Error\n ? switchChainHookOutput.error\n : defaultSwitchChainStatus.error;\n\n return { switchChain: execSwitchFn, isSwitching: isPending, error: err };\n }\n\n return defaultSwitchChainStatus;\n}\n","import { logger } from '@openzeppelin/contracts-ui-builder-utils';\n\nimport { useWalletState } from './WalletStateContext';\n\nexport interface DerivedChainInfo {\n /** The current chain ID reported by the wallet's active connection, if available. */\n currentChainId?: number;\n /** Array of chains configured in the underlying wallet library (e.g., wagmi). Type is any[] for generic compatibility. */\n availableChains: unknown[];\n}\n\nconst defaultChainInfo: DerivedChainInfo = {\n currentChainId: undefined,\n availableChains: [],\n};\n\n/**\n * A custom hook that consumes `useWalletState` to get `walletFacadeHooks`,\n * then calls the `useChainId` and `useChains` facade hooks (if available)\n * and returns a structured object with this information.\n * Provides default values if the hooks or their properties are unavailable.\n */\nexport function useDerivedChainInfo(): DerivedChainInfo {\n const { walletFacadeHooks } = useWalletState();\n\n let chainIdToReturn: number | undefined = defaultChainInfo.currentChainId;\n const chainIdHookOutput = walletFacadeHooks?.useChainId\n ? walletFacadeHooks.useChainId()\n : undefined;\n // The useChainId hook from wagmi directly returns the number or undefined\n if (typeof chainIdHookOutput === 'number') {\n chainIdToReturn = chainIdHookOutput;\n } else if (chainIdHookOutput !== undefined) {\n // If it's not a number but not undefined, log a warning but use default. Could be an adapter returning unexpected type.\n logger.warn(\n 'useDerivedChainInfo',\n 'useChainId facade hook returned non-numeric value:',\n chainIdHookOutput\n );\n }\n\n let chainsToReturn: unknown[] = defaultChainInfo.availableChains;\n const chainsHookOutput = walletFacadeHooks?.useChains ? walletFacadeHooks.useChains() : undefined;\n // The useChains hook from wagmi directly returns an array of Chain objects\n if (Array.isArray(chainsHookOutput)) {\n chainsToReturn = chainsHookOutput;\n } else if (chainsHookOutput !== undefined) {\n logger.warn(\n 'useDerivedChainInfo',\n 'useChains facade hook returned non-array value:',\n chainsHookOutput\n );\n }\n\n return { currentChainId: chainIdToReturn, availableChains: chainsToReturn };\n}\n","import type { Connector } from '@openzeppelin/contracts-ui-builder-types';\nimport { isRecordWithProperties } from '@openzeppelin/contracts-ui-builder-utils';\n\nimport { useWalletState } from './WalletStateContext';\n\n// Assuming Connector type is available\n\nexport interface DerivedConnectStatus {\n /** Function to initiate a connection, usually takes a connector. Undefined if not available. */\n connect?: (args?: { connector?: Connector /* or string for id */ }) => void;\n /** Array of available connectors. Type is any[] for broad compatibility until Connector type is fully generic here. */\n connectors: Connector[]; // Or any[] if Connector type from types pkg is too specific for generic hook here\n /** True if a connection attempt is in progress. */\n isConnecting: boolean;\n /** Error object if the last connection attempt failed, otherwise null. */\n error: Error | null;\n /** The connector a connection is pending for, if any. */\n pendingConnector?: Connector; // Or any\n}\n\nconst defaultConnectStatus: DerivedConnectStatus = {\n connect: undefined,\n connectors: [],\n isConnecting: false,\n error: null,\n pendingConnector: undefined,\n};\n\n/**\n * A custom hook that consumes `useWalletState` to get `walletFacadeHooks`,\n * then calls the `useConnect` facade hook (if available) and returns a structured,\n * safely-accessed status and control functions for wallet connection.\n */\nexport function useDerivedConnectStatus(): DerivedConnectStatus {\n const { walletFacadeHooks } = useWalletState();\n\n const connectHookOutput = walletFacadeHooks?.useConnect\n ? walletFacadeHooks.useConnect()\n : undefined;\n\n if (isRecordWithProperties(connectHookOutput)) {\n const connectFn =\n 'connect' in connectHookOutput && typeof connectHookOutput.connect === 'function'\n ? (connectHookOutput.connect as (args?: { connector?: Connector }) => void)\n : defaultConnectStatus.connect;\n\n const conns =\n 'connectors' in connectHookOutput && Array.isArray(connectHookOutput.connectors)\n ? (connectHookOutput.connectors as Connector[])\n : defaultConnectStatus.connectors;\n\n const isPending =\n 'isPending' in connectHookOutput && typeof connectHookOutput.isPending === 'boolean'\n ? connectHookOutput.isPending\n : 'isLoading' in connectHookOutput && typeof connectHookOutput.isLoading === 'boolean'\n ? connectHookOutput.isLoading\n : defaultConnectStatus.isConnecting;\n\n const err =\n 'error' in connectHookOutput && connectHookOutput.error instanceof Error\n ? connectHookOutput.error\n : defaultConnectStatus.error;\n\n const pendingConn =\n 'pendingConnector' in connectHookOutput &&\n typeof connectHookOutput.pendingConnector === 'object' // Assuming Connector is an object\n ? (connectHookOutput.pendingConnector as Connector)\n : defaultConnectStatus.pendingConnector;\n\n return {\n connect: connectFn,\n connectors: conns,\n isConnecting: isPending,\n error: err,\n pendingConnector: pendingConn,\n };\n }\n\n return defaultConnectStatus;\n}\n","import { isRecordWithProperties } from '@openzeppelin/contracts-ui-builder-utils';\n\nimport { useWalletState } from './WalletStateContext';\n\nexport interface DerivedDisconnectStatus {\n /** Function to initiate disconnection. Undefined if not available. */\n disconnect?: () => void | Promise<void>; // Can be sync or async\n /** True if a disconnection attempt is in progress (if hook provides this). */\n isDisconnecting: boolean;\n /** Error object if the last disconnection attempt failed (if hook provides this). */\n error: Error | null;\n}\n\nconst defaultDisconnectStatus: DerivedDisconnectStatus = {\n disconnect: undefined,\n isDisconnecting: false,\n error: null,\n};\n\n/**\n * A custom hook that consumes `useWalletState` to get `walletFacadeHooks`,\n * then calls the `useDisconnect` facade hook (if available) and returns a structured,\n * safely-accessed status and control function for wallet disconnection.\n */\nexport function useDerivedDisconnect(): DerivedDisconnectStatus {\n const { walletFacadeHooks } = useWalletState();\n\n const disconnectHookOutput = walletFacadeHooks?.useDisconnect\n ? walletFacadeHooks.useDisconnect()\n : undefined;\n\n if (isRecordWithProperties(disconnectHookOutput)) {\n const disconnectFn =\n 'disconnect' in disconnectHookOutput && typeof disconnectHookOutput.disconnect === 'function'\n ? (disconnectHookOutput.disconnect as () => void | Promise<void>)\n : defaultDisconnectStatus.disconnect;\n\n // wagmi's useDisconnect doesn't have isPending/isLoading directly, but has error and variables (which is the connector it disconnected)\n // We will assume a simple isDisconnecting is not provided by current wagmi facade, but include for future flexibility\n const isPending =\n 'isPending' in disconnectHookOutput && typeof disconnectHookOutput.isPending === 'boolean'\n ? disconnectHookOutput.isPending\n : 'isLoading' in disconnectHookOutput && typeof disconnectHookOutput.isLoading === 'boolean'\n ? disconnectHookOutput.isLoading\n : defaultDisconnectStatus.isDisconnecting;\n\n const err =\n 'error' in disconnectHookOutput && disconnectHookOutput.error instanceof Error\n ? disconnectHookOutput.error\n : defaultDisconnectStatus.error;\n\n return { disconnect: disconnectFn, isDisconnecting: isPending, error: err };\n }\n\n return defaultDisconnectStatus;\n}\n","import React, { useEffect } from 'react';\n\nimport { logger } from '@openzeppelin/contracts-ui-builder-utils';\n\nimport { useWalletState } from '../hooks/WalletStateContext';\nimport { WalletConnectionUI } from './WalletConnectionUI';\n\n/**\n * Component that renders the wallet connection UI.\n * Uses useWalletState to get its data.\n */\nexport const WalletConnectionHeader: React.FC = () => {\n const { isAdapterLoading, activeAdapter } = useWalletState();\n\n useEffect(() => {\n logger.debug('WalletConnectionHeader', '[Debug] State from useWalletState:', {\n adapterPresent: !!activeAdapter,\n adapterNetwork: activeAdapter?.networkConfig.id,\n isLoading: isAdapterLoading,\n });\n }, [activeAdapter, isAdapterLoading]);\n\n if (isAdapterLoading) {\n logger.debug('WalletConnectionHeader', '[Debug] Adapter loading, showing skeleton.');\n return <div className=\"h-9 w-28 animate-pulse rounded bg-muted\"></div>;\n }\n\n return <WalletConnectionUI />;\n};\n","import React, { useEffect, useMemo, useState } from 'react';\n\nimport { Button } from '@openzeppelin/contracts-ui-builder-ui';\nimport { cn, logger } from '@openzeppelin/contracts-ui-builder-utils';\n\nimport { useWalletState } from '../hooks/WalletStateContext';\n\ninterface WalletConnectionUIProps {\n className?: string;\n}\n\n/**\n * Component that displays wallet connection UI components\n * provided by the active adapter.\n */\nexport const WalletConnectionUI: React.FC<WalletConnectionUIProps> = ({ className }) => {\n const [isError, setIsError] = useState(false);\n const { activeAdapter, walletFacadeHooks } = useWalletState();\n\n // Setup error handling with useEffect\n useEffect(() => {\n const handleError = () => {\n setIsError(true);\n };\n window.addEventListener('error', handleError);\n return () => {\n window.removeEventListener('error', handleError);\n };\n }, []);\n\n useEffect(() => {\n logger.debug('WalletConnectionUI', '[Debug] State from useWalletState:', {\n adapterId: activeAdapter?.networkConfig.id,\n hasFacadeHooks: !!walletFacadeHooks,\n });\n }, [activeAdapter, walletFacadeHooks]);\n\n // Memoize wallet components to avoid repeated calls on every render\n const walletComponents = useMemo(() => {\n // Get wallet components from adapter if available\n if (!activeAdapter || typeof activeAdapter.getEcosystemWalletComponents !== 'function') {\n logger.debug(\n 'WalletConnectionUI',\n '[Debug] No activeAdapter or getEcosystemWalletComponents method, returning null.'\n );\n return null;\n }\n\n try {\n const components = activeAdapter.getEcosystemWalletComponents();\n logger.debug('WalletConnectionUI', '[Debug] walletComponents from adapter:', components);\n return components;\n } catch (error) {\n logger.error('WalletConnectionUI', '[Debug] Error getting wallet components:', error);\n setIsError(true);\n return null;\n }\n }, [activeAdapter]); // Only re-compute when activeAdapter changes\n\n if (!walletComponents) {\n logger.debug(\n 'WalletConnectionUI',\n '[Debug] getEcosystemWalletComponents returned null/undefined, rendering null.'\n );\n return null;\n }\n\n // Log available components for debugging\n logger.debug('WalletConnectionUI', 'Rendering wallet components:', {\n hasConnectButton: !!walletComponents.ConnectButton,\n hasAccountDisplay: !!walletComponents.AccountDisplay,\n hasNetworkSwitcher: !!walletComponents.NetworkSwitcher,\n });\n\n const { ConnectButton, AccountDisplay, NetworkSwitcher } = walletComponents;\n\n // If there was an error, show an error button\n if (isError) {\n return (\n <div className={cn('flex items-center gap-4', className)}>\n <Button variant=\"destructive\" size=\"sm\" onClick={() => window.location.reload()}>\n Wallet Error - Retry\n </Button>\n </div>\n );\n }\n\n // Ensure walletComponents is not null before destructuring\n if (!walletComponents) {\n // This case should ideally be caught above, but as a safeguard:\n logger.debug(\n 'WalletConnectionUI',\n '[Debug] walletComponents is null before rendering, rendering null.'\n );\n return null;\n }\n\n return (\n <div className={cn('flex items-center gap-4', className)}>\n {/* Display network switcher if available - moved before account to match typical wallet UI flow */}\n {NetworkSwitcher && <NetworkSwitcher />}\n\n {/* Display account info if available */}\n {AccountDisplay && <AccountDisplay />}\n\n {/* Display connect button if available */}\n {ConnectButton && <ConnectButton />}\n </div>\n );\n};\n","import { Settings } from 'lucide-react';\nimport React, { useCallback, useEffect, useState } from 'react';\n\nimport {\n Button,\n NetworkSettingsDialog,\n useNetworkErrors,\n} from '@openzeppelin/contracts-ui-builder-ui';\n\nimport { useWalletState } from '../hooks/WalletStateContext';\nimport { WalletConnectionUI } from './WalletConnectionUI';\n\n/**\n * Enhanced wallet connection header with network settings menu.\n * Used in exported apps to provide access to RPC and Explorer configuration.\n */\nexport const WalletConnectionWithSettings: React.FC = () => {\n const { isAdapterLoading, activeAdapter, activeNetworkConfig } = useWalletState();\n const { setOpenNetworkSettingsHandler } = useNetworkErrors();\n\n // Network settings dialog state\n const [showNetworkSettings, setShowNetworkSettings] = useState(false);\n const [defaultTab, setDefaultTab] = useState<'rpc' | 'explorer'>('rpc');\n\n // Create a stable callback for opening network settings\n const openNetworkSettings = useCallback(\n (networkId: string, tab: 'rpc' | 'explorer' = 'rpc') => {\n // In exported apps, we only support the current network\n if (activeNetworkConfig && networkId === activeNetworkConfig.id) {\n setDefaultTab(tab);\n setShowNetworkSettings(true);\n }\n },\n [activeNetworkConfig]\n );\n\n // Register handler for opening network settings from error notifications\n useEffect(() => {\n setOpenNetworkSettingsHandler(openNetworkSettings);\n }, [openNetworkSettings, setOpenNetworkSettingsHandler]);\n\n if (isAdapterLoading) {\n return <div className=\"h-9 w-28 animate-pulse rounded bg-muted\"></div>;\n }\n\n return (\n <>\n <div className=\"flex items-center gap-2\">\n <WalletConnectionUI />\n\n {/* Settings Button */}\n {activeAdapter && activeNetworkConfig && (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-9 w-9\"\n title=\"Network Settings\"\n onClick={() => setShowNetworkSettings(true)}\n >\n <Settings className=\"h-4 w-4\" />\n </Button>\n )}\n </div>\n\n {/* Network Settings Dialog */}\n <NetworkSettingsDialog\n isOpen={showNetworkSettings}\n onOpenChange={setShowNetworkSettings}\n networkConfig={activeNetworkConfig}\n adapter={activeAdapter}\n defaultTab={defaultTab}\n />\n </>\n );\n};\n"],"mappings":"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