@fliidotdev/blinks-react
v0.1.3
Published
React components for Blinks SDK
Readme
@fliidotdev/blinks-react
React components and hooks for building Solana Blinks interfaces. Create beautiful, interactive blockchain experiences with pre-built components and custom hooks.
Installation
npm install @fliidotdev/blinks-react @fliidotdev/blinks-core
# or
yarn add @fliidotdev/blinks-react @fliidotdev/blinks-core
# or
pnpm add @fliidotdev/blinks-react @fliidotdev/blinks-coreFeatures
- Pre-built Components: Ready-to-use Blink components
- Custom Hooks: React hooks for blockchain interactions
- Wallet Integration: Seamless wallet connection UI
- Responsive Design: Mobile-first, accessible components
- Theme Support: Customizable themes and styles
- TypeScript: Full type safety and IntelliSense
- SSR Compatible: Works with Next.js and other SSR frameworks
Quick Start
import { BlinkProvider, BlinkButton, useWallet } from '@fliidotdev/blinks-react';
import { WalletAdapterNetwork } from '@solana/wallet-adapter-base';
function App() {
return (
<BlinkProvider network={WalletAdapterNetwork.Mainnet}>
<PaymentButton />
</BlinkProvider>
);
}
function PaymentButton() {
const { connected, publicKey } = useWallet();
return (
<BlinkButton
action={{
type: 'transfer',
recipient: 'ABC...XYZ',
amount: 0.1
}}
onSuccess={(signature) => console.log('Success!', signature)}
onError={(error) => console.error('Failed:', error)}
>
Pay 0.1 SOL
</BlinkButton>
);
}Components
<BlinkProvider>
Root provider component that manages wallet connection and blockchain state.
import { BlinkProvider } from '@fliidotdev/blinks-react';
<BlinkProvider
network={WalletAdapterNetwork.Mainnet}
endpoint="https://api.mainnet-beta.solana.com"
wallets={[phantom, solflare]}
>
{children}
</BlinkProvider>Props:
network- Solana network to connect toendpoint- RPC endpoint URLwallets- Array of wallet adaptersautoConnect- Auto-connect to wallet (default: false)theme- UI theme configuration
<BlinkButton>
Interactive button component for executing Blink actions.
<BlinkButton
action={{
type: 'transfer',
recipient: walletAddress,
amount: 1.5
}}
variant="primary"
size="large"
loading={isProcessing}
disabled={!connected}
onSuccess={handleSuccess}
onError={handleError}
>
Send 1.5 SOL
</BlinkButton>Props:
action- Blink action configurationvariant- Button style variantsize- Button sizeloading- Loading statedisabled- Disabled stateonSuccess- Success callbackonError- Error callback
<WalletConnect>
Wallet connection interface with multi-wallet support.
<WalletConnect
showBalance={true}
showDisconnect={true}
buttonProps={{
variant: 'outline',
size: 'medium'
}}
/><TransactionStatus>
Display transaction status with automatic updates.
<TransactionStatus
signature={txSignature}
showExplorer={true}
autoHide={5000}
/><BlinkCard>
Card component for displaying Blink information.
<BlinkCard
title="Premium Subscription"
description="Subscribe for exclusive features"
price={5}
currency="SOL"
action={subscribeAction}
image="/subscription.png"
badge="Popular"
/><ActionList>
List of executable actions with icons and descriptions.
<ActionList
actions={[
{
type: 'transfer',
label: 'Send Payment',
icon: '💸',
amount: 10
},
{
type: 'swap',
label: 'Swap Tokens',
icon: '🔄',
fromToken: 'SOL',
toToken: 'USDC'
}
]}
onSelect={handleActionSelect}
/>Hooks
useWallet
Access wallet connection state and methods.
const {
connected,
connecting,
publicKey,
wallet,
connect,
disconnect,
signTransaction,
signMessage
} = useWallet();useBlink
Execute Blink actions programmatically.
const { execute, executing, error } = useBlink();
const handleTransfer = async () => {
const signature = await execute({
type: 'transfer',
recipient: recipientAddress,
amount: 1.0
});
};useBalance
Get wallet balance and token balances.
const { balance, tokens, loading, refresh } = useBalance();
// SOL balance
console.log(`Balance: ${balance} SOL`);
// Token balances
tokens.forEach(token => {
console.log(`${token.symbol}: ${token.balance}`);
});useTransaction
Monitor transaction status.
const { status, confirmations, error } = useTransaction(signature);
if (status === 'confirmed') {
console.log('Transaction confirmed!');
}useAction
Create and manage Blink actions.
const action = useAction({
type: 'custom',
handler: async (params) => {
// Custom logic
return { success: true };
}
});
<button onClick={() => action.execute()}>
Execute Custom Action
</button>Styling
Theme Configuration
import { BlinkProvider, createTheme } from '@fliidotdev/blinks-react';
const customTheme = createTheme({
colors: {
primary: '#7B3FF2',
secondary: '#2FC5CC',
success: '#00D395',
error: '#FF6B6B',
background: '#1A1B23',
surface: '#2D2E3F',
text: '#FFFFFF'
},
fonts: {
body: 'Inter, sans-serif',
heading: 'Poppins, sans-serif'
},
radii: {
small: '4px',
medium: '8px',
large: '16px'
},
shadows: {
small: '0 2px 4px rgba(0,0,0,0.1)',
medium: '0 4px 8px rgba(0,0,0,0.15)',
large: '0 8px 16px rgba(0,0,0,0.2)'
}
});
<BlinkProvider theme={customTheme}>
{/* Your app */}
</BlinkProvider>CSS Classes
All components support className props for custom styling:
<BlinkButton
className="custom-button"
action={action}
>
Custom Styled Button
</BlinkButton>.custom-button {
background: linear-gradient(45deg, #7B3FF2, #2FC5CC);
border-radius: 12px;
font-weight: bold;
}Advanced Usage
Custom Action Handler
function CustomActionButton() {
const { execute } = useBlink();
const handleCustomAction = async () => {
const result = await execute({
type: 'custom',
handler: async () => {
// Your custom logic
const tx = await buildCustomTransaction();
return await sendTransaction(tx);
}
});
};
return <button onClick={handleCustomAction}>Execute</button>;
}Batch Transactions
function BatchActions() {
const { executeBatch } = useBlink();
const handleBatch = async () => {
const results = await executeBatch([
{ type: 'transfer', recipient: addr1, amount: 1 },
{ type: 'transfer', recipient: addr2, amount: 2 },
{ type: 'transfer', recipient: addr3, amount: 3 }
]);
console.log('All transactions:', results);
};
return <button onClick={handleBatch}>Send to Multiple</button>;
}SSR with Next.js
// pages/_app.tsx
import { BlinkProvider } from '@fliidotdev/blinks-react';
import dynamic from 'next/dynamic';
const WalletProvider = dynamic(
() => import('../components/WalletProvider'),
{ ssr: false }
);
function MyApp({ Component, pageProps }) {
return (
<WalletProvider>
<BlinkProvider>
<Component {...pageProps} />
</BlinkProvider>
</WalletProvider>
);
}Error Handling
function SafeBlinkButton() {
const [error, setError] = useState(null);
return (
<>
<BlinkButton
action={action}
onError={(err) => {
setError(err.message);
// Log to error tracking service
trackError(err);
}}
>
Execute Action
</BlinkButton>
{error && (
<ErrorAlert message={error} onDismiss={() => setError(null)} />
)}
</>
);
}Testing
import { render, screen, fireEvent } from '@testing-library/react';
import { MockBlinkProvider } from '@fliidotdev/blinks-react/testing';
test('BlinkButton executes action', async () => {
render(
<MockBlinkProvider mockWallet={mockWallet}>
<BlinkButton action={mockAction}>
Click Me
</BlinkButton>
</MockBlinkProvider>
);
fireEvent.click(screen.getByText('Click Me'));
await waitFor(() => {
expect(mockAction).toHaveBeenCalled();
});
});Performance Optimization
Lazy Loading
import { lazy, Suspense } from 'react';
const BlinkCard = lazy(() => import('@fliidotdev/blinks-react/BlinkCard'));
function App() {
return (
<Suspense fallback={<Loading />}>
<BlinkCard {...props} />
</Suspense>
);
}Memoization
import { memo, useMemo } from 'react';
const ExpensiveBlinkList = memo(({ actions }) => {
const sortedActions = useMemo(
() => actions.sort((a, b) => b.priority - a.priority),
[actions]
);
return <ActionList actions={sortedActions} />;
});Accessibility
All components follow WCAG 2.1 guidelines:
- Keyboard navigation support
- Screen reader announcements
- Focus management
- ARIA attributes
- Color contrast compliance
License
MIT © fliidotdev
Contributing
We welcome contributions! Please see our Contributing Guide.
