npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@liberfi.io/ui-chain-select

v0.1.83

Published

Chain Management for Liberfi React SDK

Readme

@liberfi.io/ui-chain-select

Chain selection UI and state management for the Liberfi React SDK. Provides a responsive chain selector widget (desktop popover / mobile icon buttons), Jotai-based state atoms, and hooks for reading and switching the current chain. Consumed by app-level packages and widgets that need chain-aware behaviour.

Design Philosophy

  • State / Hooks / UI layering — Jotai atoms own the chain state; hooks read/write atoms and invoke callbacks; the widget wires them together; UI components are purely presentational and can be used independently.
  • Inversion of control — All side effects (wallet switching, toast, analytics) are delegated to the caller via onSwitchChain, onSuccess, and onError callbacks. The package never hardcodes feedback.
  • Optional Provider — Works out of the box with default atoms (zero-config). Wrap with ChainSelectProvider only when multiple independent chain selectors need to coexist (different storageKeyPrefix).
  • Single source of truthChain and ChainNamespace types come from @liberfi.io/types; display names, colors, icons, and chainToNamespace come from @liberfi.io/utils and @liberfi.io/ui.

Installation

pnpm add @liberfi.io/ui-chain-select

Peer dependencies

The consumer must provide:

| Package | Version | | ---------------- | --------- | | react | >= 18 | | react-dom | >= 18 | | jotai | >= 2.15.1 | | @liberfi.io/ui | workspace |

API Reference

Components

ChainSelectWidget

Full-featured chain selector that wires state and callbacks. Drop-in usage — no Provider required.

function ChainSelectWidget(props: ChainSelectWidgetProps): JSX.Element;

| Prop | Type | Default | Description | | --------------- | --------------------------------- | ----------------------------- | ----------------------------------- | | size | "sm" \| "md" \| "lg" | undefined | Button / item size | | className | string | undefined | Class on the root element | | candidates | Chain[] | [SOLANA, ETHEREUM, BINANCE] | Chains to offer | | onSwitchChain | (chain: Chain) => Promise<void> | undefined | Async handler (e.g. wallet switch) | | onSuccess | (chain: Chain) => void | undefined | Called after successful switch | | onError | (error: unknown) => void | undefined | Called when onSwitchChain rejects |

ChainSelectUI

Presentational responsive shell. Renders ChainSelectDesktopUI or ChainSelectMobileUI based on viewport.

function ChainSelectUI(props: ChainSelectUIProps): JSX.Element;

| Prop | Type | Default | Description | | --------------- | ----------------------------------------- | -------------------- | ------------------------- | | size | "sm" \| "md" \| "lg" | undefined | Button / item size | | chain | Chain | candidates[0] | Currently selected chain | | candidates | Chain[] | DEFAULT_CANDIDATES | Chains to show | | onSelectChain | (chain: Chain) => void \| Promise<void> | undefined | Selection handler | | isSwitching | boolean | undefined | Shows loading state | | className | string | undefined | Class on the root element |

ChainAvatar

Renders a chain icon. Uses dedicated SVG icons for known chains, falls back to an Avatar with the chain's icon URL.

function ChainAvatar(props: ChainAvatarProps): JSX.Element;

| Prop | Type | Description | | ----------- | -------- | -------------------------- | | chain | Chain | The chain to display | | className | string | Class on the icon / avatar |

ChainSelectProvider

Optional context provider for multi-instance scenarios.

function ChainSelectProvider(props: ChainSelectProviderProps): JSX.Element;

| Prop | Type | Default | Description | | ------------------ | ----------- | ------- | ---------------------------- | | storageKeyPrefix | string | "" | Prefix for localStorage keys | | children | ReactNode | — | Children |

Hooks

useSelectChain

Returns a selectChain function and isSwitching state.

function useSelectChain(options?: UseSelectChainOptions): {
  selectChain: (chain: Chain) => Promise<void>;
  isSwitching: boolean;
};

| Option | Type | Description | | --------------- | --------------------------------- | ----------------------------------- | | onSwitchChain | (chain: Chain) => Promise<void> | Async handler before state update | | onSuccess | (chain: Chain) => void | Called after successful switch | | onError | (error: unknown) => void | Called when onSwitchChain rejects |

useCurrentChain

Reads the current chain and namespace from state.

function useCurrentChain(): {
  chain: Chain;
  chainNamespace: ChainNamespace;
};

State (Jotai atoms)

| Export | Type | Description | | -------------------- | --------------------------------- | ----------------------------------------------- | | chainAtom | WritableAtom<Chain> | Default chain atom (key "chain") | | chainNamespaceAtom | WritableAtom<ChainNamespace> | Default namespace atom (key "chainNamespace") | | defaultChainAtoms | ChainAtoms | Bundle of both default atoms | | createChainAtoms | (prefix?: string) => ChainAtoms | Factory for custom-prefixed atoms |

Types

| Export | Description | | ------------------------------ | ----------------------------------- | | ChainAtoms | { chainAtom, chainNamespaceAtom } | | ChainSelectStateContextValue | Context value type | | ChainSelectProviderProps | Props for ChainSelectProvider | | ChainSelectWidgetProps | Props for ChainSelectWidget | | ChainSelectUIProps | Props for ChainSelectUI | | ChainAvatarProps | Props for ChainAvatar | | UseSelectChainOptions | Options for useSelectChain |

Usage Examples

Basic usage

import { ChainSelectWidget } from "@liberfi.io/ui-chain-select";

function App() {
  return (
    <ChainSelectWidget
      onSwitchChain={async (chain) => {
        await wallet.switchChain(chain);
      }}
      onSuccess={(chain) => toast.success(`Switched to ${chain}`)}
      onError={(err) => toast.error("Switch failed")}
    />
  );
}

Presentational-only (no state management)

import { Chain } from "@liberfi.io/types";
import { ChainSelectUI } from "@liberfi.io/ui-chain-select";

function ReadOnlyChainDisplay() {
  return (
    <ChainSelectUI
      chain={Chain.ETHEREUM}
      candidates={[Chain.ETHEREUM, Chain.BINANCE]}
      onSelectChain={(chain) => console.log(chain)}
    />
  );
}

Multiple independent instances

import {
  ChainSelectProvider,
  ChainSelectWidget,
} from "@liberfi.io/ui-chain-select";

function MultiChainApp() {
  return (
    <>
      <ChainSelectProvider storageKeyPrefix="source_">
        <ChainSelectWidget onSwitchChain={handleSourceSwitch} />
      </ChainSelectProvider>
      <ChainSelectProvider storageKeyPrefix="target_">
        <ChainSelectWidget onSwitchChain={handleTargetSwitch} />
      </ChainSelectProvider>
    </>
  );
}

Reading current chain from hooks

import { useCurrentChain } from "@liberfi.io/ui-chain-select";

function ChainInfo() {
  const { chain, chainNamespace } = useCurrentChain();
  return (
    <p>
      Current: {chain} ({chainNamespace})
    </p>
  );
}

Future Improvements

  • Refactor version.ts module-level side effect to a lazy registration pattern (monorepo-wide change).