@liberfi.io/ui-tokens
v3.0.70
Published
Token Components for Liberfi React SDK
Readme
@liberfi.io/ui-tokens
Token-related UI components for the Liberfi React SDK. Provides token lists, search, avatars, and pulse (real-time new/migrated token) widgets consumed by downstream applications.
Design Philosophy
- Script / UI / Widget layering —
.script.tsfiles encapsulate data-fetching and business logic as hooks;.ui.tsxfiles are pure presentational components driven by props;.widget.tsxfiles compose scripts and UI together. - No built-in global state — Data flows through props and lightweight React contexts scoped to individual features (e.g.
SearchProvider). Persistent state usesatomWithStorage(jotai) so the storage backend can be swapped. - Callbacks over side effects — Selection, navigation, and feedback (toast, analytics) are surfaced via
onSelectToken,onResult, etc. rather than hard-coded inside the library. - Mobile-first search — The search module targets constrained-width containers (modals, sidebars) and uses a compact mobile layout exclusively.
Installation
pnpm add @liberfi.io/ui-tokensPeer dependencies
The consumer must provide:
react>= 18react-dom>= 18jotai>= 2.15.1
API Reference
Components — Search
| Export | Kind | Description |
| ------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------- |
| SearchTokensButton | Widget | Button that opens the search modal (supports / keyboard shortcut). |
| SearchModal | Widget | AsyncModal wrapper; renders SearchWidget inside a StyledModal. |
| SearchWidget | Widget | Standalone search experience (input + history + result list). Accepts chains?: Chain[] and onSelectToken. |
| SearchInputUI | UI | Search input with 500ms debounce, paste, and clear buttons. |
| SearchContentUI | UI | Conditional renderer — shows history + hint when idle, search results when a keyword is set. |
| SearchHistoryUI | UI | Chips displaying persisted search history with a clear button. |
| SearchResultListWidget | Widget | Virtualized infinite-scroll result list (react-window + react-window-infinite-loader). |
| SearchResultListHeader | UI | Static column headers (Token/Age/MCap/Liq | Price/24h%). |
| SearchResultItemUI | UI | Compact token row — avatar, symbol, age, market cap, TVL, price, and price change. |
| SearchResultListSkeleton | UI | Skeleton placeholder for initial loading state. |
| SearchProvider / useSearchContext | Context | Manages the current search keyword. |
| useSearchHistory | Hook | Read/write persisted search history (backed by atomWithStorage). |
| useSearchResultListScript | Hook | Connects useSearchTokensInfiniteQuery to the search context. |
SearchModal
Wraps AsyncModal with id="search_tokens". Open it from anywhere via:
import { useAsyncModal } from "@liberfi.io/ui-scaffold";
const { onOpen } = useAsyncModal<SearchModalParams, SearchModalResult>(
"search_tokens",
);
await onOpen({ params: { chains: [Chain.SOLANA] } });
// resolves with Token on selection, undefined on dismissSearchWidget (standalone)
import { SearchWidget } from "@liberfi.io/ui-tokens";
<SearchWidget
chains={[Chain.SOLANA]}
onSelectToken={(token) => navigate(`/token/${token.chain}/${token.address}`)}
/>;Components — Token Avatar
| Export | Kind | Description |
| ------------- | ---- | ------------------------------------------------------------------------------------------- |
| TokenAvatar | UI | Token avatar with optional protocol family icon, bonding-curve progress, and image preview. |
Components — Token List
| Export | Kind | Description |
| ------------------------- | ------ | -------------------------------------------- |
| NewTokenListWidget | Widget | New tokens list with real-time subscription. |
| TrendingTokenListWidget | Widget | Trending tokens list. |
| StockTokenListWidget | Widget | Stock tokens list. |
| TokenListFilterModal | UI | Filter modal for token list columns. |
Components — Pulse
| Export | Kind | Description |
| ----------------------------- | ------ | -------------------------------- |
| PulseNewListWidget | Widget | Real-time new token pulse feed. |
| PulseMigratedListWidget | Widget | Migrated tokens pulse feed. |
| PulseFinalStretchListWidget | Widget | Final-stretch tokens pulse feed. |
Components — Shared primitives
| Export | Kind | Description |
| -------------------- | ---- | -------------------------------------------------------------------------- |
| TraderTagBadge | UI | Classification chip for a single trader tag (kol, smart, sniper, …). |
| TraderTagBadgeList | UI | Row of trader tags with max-visible + overflow counter. |
| HolderTagBadge | UI | Classification chip for a single holder tag (same palette as trader tags). |
| HolderTagBadgeList | UI | Row of holder tags with max-visible + overflow counter. |
Components — Token Detail
Token-detail widgets follow the *.ui.tsx / *.script.ts / *.widget.tsx triad. Every script layer calls @liberfi.io/react hooks only; UI layers are pure presentational and driven by props. The header composes the basic-info strip by default — pass dataStrip={null} to hide it.
| Export | Kind | Description |
| --------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| TokenDetailHeaderWidget | Widget | Live-updating header: avatar, symbol / name, copy-address, slot for favorite / share actions, and an injectable data strip. |
| TokenBasicInfoWidget | Widget | Compact strip: price, market cap, volume, holders, social media. Consumes useTokenQuery + useTokenSubscription. |
| TokenPriceWidget | Widget | Live price + 24h change badge. |
| TokenMarketCapWidget | Widget | Market cap / liquidity / age summary. |
| TokenVolumeWidget | Widget | 24h volume / trades / traders summary. |
| TokenHoldersCountWidget | Widget | Holder count + top-10 / top-100 ratio summary. |
| TokenSocialMediaWidget | Widget | Row of social-media icon links (website, twitter, telegram, discord, …). |
| TokenHoldersListWidget | Widget | Paginated token-holders table (Phase 3): sortBy selector (holdingUsd / lastActiveAt), holder tags, first-held-at, last-active-at. |
| TokenActivitiesListWidget | Widget | Paginated token-activities table (Phase 3): sortBy selector, type filter, trader tags, gas fee. |
| TokenTradersOverviewWidget | Widget | Unique-traders card with buy / sell split and progress bar. |
| TokenTransactionsOverviewWidget | Widget | Tx-count card with buy / sell split and progress bar. |
| TokenVolumesOverviewWidget | Widget | USD-volume card with buy / sell split and progress bar. |
| TokenSecurityWidget | Widget | Security flags from useTokenSecurityQuery (transfer fee / freezable / closable / …) + optional external auditor link. |
| TokenAboutWidget | Widget | Name / symbol / human-readable description section. |
| TokenLiquiditiesWidget | Widget | DEX liquidity breakdown with per-pool TVL and collapse-at-N support. |
| TokenCexListingWidget | Widget | CEX listings chips. Data is caller-supplied (the Token domain type does not model CEX listings). |
| TokenCategoriesWidget | Widget | Category chips sourced from token.tags. |
Hooks
| Export | Description |
| ------------------- | ------------------------------------------------------------------------------------------------- |
| useTokens(params) | Fetches and subscribes to a set of tokens by chain + addresses, with polling and WebSocket merge. |
Usage Examples
Full search modal setup
import { SearchModal, SearchTokensButton } from "@liberfi.io/ui-tokens";
function App() {
return (
<>
{/* Trigger button */}
<SearchTokensButton />
{/* Modal definition — render once at app root */}
<SearchModal />
</>
);
}Standalone search widget inside a sidebar
import { Chain } from "@liberfi.io/types";
import { SearchWidget } from "@liberfi.io/ui-tokens";
function Sidebar() {
return (
<div className="w-80 h-screen">
<SearchWidget
chains={[Chain.SOLANA, Chain.ETHEREUM]}
onSelectToken={(token) => {
console.log("Selected:", token.chain, token.address);
}}
/>
</div>
);
}Composing the token-detail page
import {
TokenDetailHeaderWidget,
TokenHoldersListWidget,
TokenActivitiesListWidget,
TokenSecurityWidget,
TokenAboutWidget,
TokenLiquiditiesWidget,
TokenCategoriesWidget,
TokenTradersOverviewWidget,
TokenTransactionsOverviewWidget,
TokenVolumesOverviewWidget,
} from "@liberfi.io/ui-tokens";
function TokenDetailPage({
chain,
address,
}: {
chain: Chain;
address: string;
}) {
return (
<div className="flex flex-col gap-4">
<TokenDetailHeaderWidget chain={chain} address={address} />
<div className="grid grid-cols-1 gap-4 lg:grid-cols-3">
<TokenTradersOverviewWidget chain={chain} address={address} />
<TokenTransactionsOverviewWidget chain={chain} address={address} />
<TokenVolumesOverviewWidget chain={chain} address={address} />
</div>
<TokenActivitiesListWidget chain={chain} address={address} />
<TokenHoldersListWidget chain={chain} address={address} />
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
<TokenAboutWidget chain={chain} address={address} />
<TokenSecurityWidget chain={chain} address={address} />
<TokenCategoriesWidget chain={chain} address={address} />
<TokenLiquiditiesWidget chain={chain} address={address} />
</div>
</div>
);
}Future Improvements
- Add tab system (Discover / Favorite / View) for the empty-state content when no keyword is entered.
- Support sort and filter controls in search result headers.
- Add chain selector to scope search to a specific chain.
- Support custom
atomWithStoragestorage adapter for search history (e.g. server-side persistence). - Token-detail widgets: add skeleton loading states that match the final layout.
- Token-holders list: wire a real-time WebSocket channel once the server exposes one (currently refreshes via pagination).
