Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f6abb3f
feat(widget-checkout): add mock onramp session API server
tomiiide Mar 17, 2026
3f9f296
fix(widget-checkout): fix Transak staging API integration
tomiiide Mar 17, 2026
25cf1f0
build(widget-checkout): configure package for publication
tomiiide Mar 19, 2026
0e15516
feat(widget-checkout): add error simulation and Core proxy toggle
tomiiide Mar 19, 2026
ec83411
feat(widget-checkout): path v1 shell, mui router, playground toggle
tomiiide Mar 20, 2026
9ccae79
feat(widget-checkout): embed widget runtime and source flow
tomiiide Mar 25, 2026
671dfcd
feat(checkout): integrate Transak deposit flow via onramp session API
tomiiide Mar 25, 2026
6fc9b15
feat(widget-checkout): pluggable on-ramp and remove funding picker
tomiiide Mar 25, 2026
24bd5c8
feat(widget-checkout): add i18n and export deepMerge from widget
tomiiide Mar 25, 2026
3da8f60
feat(wallet-management): open wallet menu at pre-selected wallet
tomiiide Mar 25, 2026
44837bd
feat(widget-checkout): add error boundary, wallet callbacks, and fixes
tomiiide Mar 25, 2026
340a7ab
refactor(widget-checkout): restructure to match widget conventions
tomiiide Mar 25, 2026
2e38197
refactor(widget-checkout): drop Checkout prefix, rename Drawer to Modal
tomiiide Mar 25, 2026
945ab7e
refactor(checkout): merge widget-checkout package into @lifi/widget
tomiiide Apr 1, 2026
c77d21f
refactor(checkout): simplify config API to use WidgetConfig directly
tomiiide Apr 1, 2026
6b28646
feat(checkout): add onSuccess callback for completed onramp orders
tomiiide Apr 1, 2026
21db4f9
refactor(checkout): simplify theme access and migrate applyStyles
tomiiide Apr 1, 2026
55b1b35
fix(hooks): restore list height on early return in getContentHeight
tomiiide Apr 1, 2026
d682837
refactor(checkout): replace hardcoded rgba with CSS variable channels
tomiiide Apr 1, 2026
dd20231
refactor(checkout): replace hardcoded rgba with CSS variable channels
tomiiide Apr 1, 2026
3111d63
feat(checkout): add Mesh CEX on-ramp provider
tomiiide Apr 1, 2026
f094cc6
feat(checkout): add useCheckoutUserId hook and wire userId into Mesh …
tomiiide Apr 2, 2026
ede3464
feat(checkout): close Transak modal on route change
tomiiide Apr 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,6 @@ next-env.d.ts
/.nuxt/
/.output/

# claude
/.claude
/.omc
4 changes: 4 additions & 0 deletions knip.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
"@walletconnect/ethereum-provider",
"porto"
]
},
"packages/widget": {
"ignore": ["src/config/version.ts"],
"ignoreDependencies": ["@transak/ui-js-sdk", "@meshconnect/web-link-sdk"]
}
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"dev:dev": "pnpm --filter widget-playground-vite dev:dev",
"dev:staging": "pnpm --filter widget-playground-vite dev:staging",
"dev:local": "pnpm --filter widget-playground-vite dev:local",
"dev:mock-api": "pnpm --filter @lifi/widget dev:mock-api",
"dev:next": "pnpm --filter widget-playground-next dev",
"release": "pnpm release:version && pnpm release:build && pnpm standard-version -a -s",
"release:alpha": "pnpm release:version --preid alpha && pnpm release:build && pnpm standard-version -a -s --prerelease alpha --skip.changelog",
Expand Down
47 changes: 44 additions & 3 deletions packages/wallet-management/src/components/WalletMenuContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
List,
Typography,
} from '@mui/material'
import { useMemo, useReducer, useRef } from 'react'
import { useEffect, useMemo, useReducer, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { useAccount } from '../hooks/useAccount.js'
import type { CombinedWallet } from '../hooks/useCombinedWallets.js'
Expand Down Expand Up @@ -82,7 +82,19 @@ export const WalletMenuContent: React.FC<WalletMenuContentProps> = ({
.filter(Boolean)
}, [accounts])

const [state, dispatch] = useReducer(reducer, { view: 'wallet-list' })
const openedWithWalletId = Boolean(walletChainArgs?.walletId)

const [state, dispatch] = useReducer(reducer, undefined, (): State => {
const walletId = walletChainArgs?.walletId
if (!walletId) {
return { view: 'wallet-list' }
}
const wallet = installedWallets.find((w) => w.id === walletId)
if (!wallet) {
return { view: 'wallet-list' }
}
return { view: 'multi-ecosystem', selectedWalletId: walletId }
})

const handleMultiEcosystem = (id: string) => {
dispatch({ type: 'SHOW_MULTI_ECOSYSTEM', id })
Expand All @@ -93,7 +105,18 @@ export const WalletMenuContent: React.FC<WalletMenuContentProps> = ({
}

const handleBack = () => {
dispatch({ type: 'SHOW_WALLET_LIST' })
if (openedWithWalletId) {
if (state.view === 'connecting') {
dispatch({
type: 'SHOW_MULTI_ECOSYSTEM',
id: state.selectedWalletId!,
})
} else {
onClose()
}
} else {
dispatch({ type: 'SHOW_WALLET_LIST' })
}
}

const handleError = (id: string, error: any) => {
Expand All @@ -118,6 +141,10 @@ export const WalletMenuContent: React.FC<WalletMenuContentProps> = ({
const targetChainType =
walletChainArgs.chain?.chainType ?? walletChainArgs.chainType

if (!targetChainType) {
return installedWallets
}

return installedWallets
.map((wallet) => {
const filteredConnectors = wallet.connectors.filter(
Expand All @@ -130,6 +157,20 @@ export const WalletMenuContent: React.FC<WalletMenuContentProps> = ({
.filter(Boolean) as typeof installedWallets
}, [installedWallets, walletChainArgs])

useEffect(() => {
const walletId = walletChainArgs?.walletId
if (!walletId) {
dispatch({ type: 'SHOW_WALLET_LIST' })
return
}
const wallet = filteredWallets.find((w) => w.id === walletId)
if (!wallet) {
dispatch({ type: 'SHOW_WALLET_LIST' })
return
}
dispatch({ type: 'SHOW_MULTI_ECOSYSTEM', id: walletId })
}, [walletChainArgs?.walletId, filteredWallets])

const isMultiEcosystem = state.view === 'multi-ecosystem'
const isConnecting = state.view === 'connecting'

Expand Down
10 changes: 10 additions & 0 deletions packages/wallet-management/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import type {} from '@mui/material/themeCssVarsAugmentation'

export * from './components/BitcoinListItemButton.js'
export * from './components/CardListItemButton.js'
export * from './components/EthereumListItemButton.js'
export * from './components/SolanaListItemButton.js'
export * from './components/SuiListItemButton.js'
export * from './hooks/useAccount.js'
export * from './hooks/useAccountDisconnect.js'
export * from './hooks/useCombinedWallets.js'
export * from './hooks/useWalletManagementEvents.js'
export * from './icons.js'
export * from './providers/WalletManagementProvider/types.js'
export * from './providers/WalletManagementProvider/WalletManagementProvider.js'
export type { WalletMenuOpenArgs } from './providers/WalletMenuProvider/types.js'
export * from './providers/WalletMenuProvider/WalletMenuContext.js'
export * from './types/events.js'
export * from './types/walletTagType.js'
export * from './utils/getConnectorIcon.js'
export * from './utils/getConnectorId.js'
export * from './utils/getSortedByTags.js'
export * from './utils/getWalletPriority.js'
export * from './utils/walletTags.js'
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { ChainType, ExtendedChain } from '@lifi/sdk'
export interface WalletMenuOpenArgs {
chain?: ExtendedChain
chainType?: ChainType
walletId?: string
}

export interface WalletMenuContext {
Expand Down
1 change: 1 addition & 0 deletions packages/widget-playground-next/src/app/AppProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const AppProvider = ({ children }: PropsWithChildren) => {
return (
<EnvVariablesProvider
EVMWalletConnectId={process.env.NEXT_PUBLIC_EVM_WALLET_CONNECT!}
onrampSessionApiUrl={process.env.NEXT_PUBLIC_ONRAMP_SESSION_API_URL!}
>
<QueryClientProvider client={queryClient}>
<WidgetConfigProvider defaultWidgetConfig={defaultWidgetConfig}>
Expand Down
1 change: 1 addition & 0 deletions packages/widget-playground-vite/.env
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
VITE_EVM_WALLET_CONNECT=5432e3507d41270bee46b7b85bbc2ef8
VITE_API_URL=https://li.quest/v1
VITE_ONRAMP_SESSION_API_URL=http://localhost:8080
4 changes: 3 additions & 1 deletion packages/widget-playground-vite/.env.staging
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
VITE_API_URL=https://staging.li.quest/v1
# Set VITE_API_KEY in .env.staging.local (git-ignored)
# in .env.dev.local (git-ignored)
# VITE_API_KEY
# VITE_ONRAMP_SESSION_API_URL
3 changes: 3 additions & 0 deletions packages/widget-playground-vite/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ const AppProvider = ({ children }: PropsWithChildren) => {
return (
<EnvVariablesProvider
EVMWalletConnectId={import.meta.env.VITE_EVM_WALLET_CONNECT}
onrampSessionApiUrl={
import.meta.env.VITE_ONRAMP_SESSION_API_URL || undefined
}
>
<QueryClientProvider client={queryClient}>
<WidgetConfigProvider defaultWidgetConfig={defaultWidgetConfig}>
Expand Down
2 changes: 2 additions & 0 deletions packages/widget-playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@lifi/widget": "workspace:*",
"@meshconnect/web-link-sdk": "^3.9.1",
"@transak/ui-js-sdk": "^1.0.0",
"@lifi/widget-provider-bitcoin": "workspace:*",
"@lifi/widget-provider-ethereum": "workspace:*",
"@lifi/widget-provider-solana": "workspace:*",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { SyntheticEvent } from 'react'
import type { PlaygroundWidgetMode } from '../../../store/widgetConfig/types.js'
import { useConfigActions } from '../../../store/widgetConfig/useConfigActions.js'
import { usePlaygroundWidgetMode } from '../../../store/widgetConfig/useConfigValues.js'
import { CardValue } from '../../Card/Card.style.js'
import { ExpandableCard } from '../../Card/ExpandableCard.js'
import { Tab, Tabs } from '../../Tabs/Tabs.style.js'

const modeLabels: Record<PlaygroundWidgetMode, string> = {
swap: 'Swap / bridge',
checkout: 'Checkout (Path v1)',
}

export const WidgetModeControl = () => {
const { playgroundWidgetMode } = usePlaygroundWidgetMode()
const { setPlaygroundWidgetMode } = useConfigActions()

const handleChange = (_: SyntheticEvent, value: PlaygroundWidgetMode) => {
if (value === 'swap' || value === 'checkout') {
setPlaygroundWidgetMode(value)
}
}

return (
<ExpandableCard
title="Widget mode"
value={
<CardValue sx={{ textTransform: 'none' }}>
{modeLabels[playgroundWidgetMode]}
</CardValue>
}
>
<Tabs
value={playgroundWidgetMode}
aria-label="Playground widget mode"
indicatorColor="primary"
onChange={handleChange}
sx={{ mt: 0.5 }}
orientation="vertical"
>
<Tab label={modeLabels.swap} value="swap" disableRipple />
<Tab label={modeLabels.checkout} value="checkout" disableRipple />
</Tabs>
</ExpandableCard>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { ThemeControl } from './DesignControls/ThemeControl.js'
import { VariantControl } from './DesignControls/VariantControl.js'
import { WalletManagementControl } from './DesignControls/WalletManagementControl.js'
import { WidgetEventControls } from './DesignControls/WidgetEventsControls.js'
import { WidgetModeControl } from './DesignControls/WidgetModeControl.js'
import {
Drawer,
DrawerContentContainer,
Expand Down Expand Up @@ -116,6 +117,7 @@ export const DrawerControls = () => {
>
<ExpandableCardAccordion>
<WidgetConfigControls>
<WidgetModeControl />
<VariantControl />
<SubvariantControl />
<AppearanceControl />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { type CheckoutModalRef, LifiWidgetCheckout } from '@lifi/widget'
import { Box, Button, Typography } from '@mui/material'
import { useCallback, useRef } from 'react'
import { widgetBaseConfig } from '../../defaultWidgetConfig.js'
import { useEnvVariables } from '../../providers/EnvVariablesProvider.js'
import { useConfig } from '../../store/widgetConfig/useConfig.js'

/** Default on-ramp target for Path checkout (Lido stETH on Ethereum). Playground `config` overrides when set. */
const DEFAULT_CHECKOUT_ONRAMP_TARGET = {
toChain: 1,
toToken: '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84',
} as const

export function CheckoutWidgetView() {
const { config } = useConfig()
const { onrampSessionApiUrl } = useEnvVariables()
const checkoutRef = useRef<CheckoutModalRef>(null)

const handleOpen = useCallback(() => {
checkoutRef.current?.open()
}, [])

const checkoutConfig = {
...config,
providers: config?.providers ?? widgetBaseConfig.providers,
toChain: config?.toChain ?? DEFAULT_CHECKOUT_ONRAMP_TARGET.toChain,
toToken: config?.toToken ?? DEFAULT_CHECKOUT_ONRAMP_TARGET.toToken,
}

return (
<Box
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
gap: 2,
p: 3,
flex: 1,
minHeight: 320,
}}
>
<Typography variant="body2" color="text.secondary" textAlign="center">
Path v1 checkout — opens as a centered widget via ref (
<code>open()</code> / <code>close()</code>).
</Typography>
<Button variant="contained" onClick={handleOpen}>
Deposit
</Button>
<LifiWidgetCheckout
ref={checkoutRef}
integrator={config?.integrator ?? 'li.fi-playground'}
onrampSessionApiUrl={onrampSessionApiUrl?.trim() || undefined}
config={checkoutConfig}
onClose={() => {}}
/>
</Box>
)
}
11 changes: 11 additions & 0 deletions packages/widget-playground/src/components/Widget/WidgetView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ import { useCallback, useEffect, useRef } from 'react'
import { useFormValues } from '../../store/editTools/useFormValues.js'
import { useSkeletonToolValues } from '../../store/editTools/useSkeletonToolValues.js'
import { useConfig } from '../../store/widgetConfig/useConfig.js'
import { usePlaygroundWidgetMode } from '../../store/widgetConfig/useConfigValues.js'
import { CheckoutWidgetView } from './CheckoutWidgetView.js'
import { WidgetViewContainer } from './WidgetViewContainer.js'

export function WidgetView() {
const { config } = useConfig()
const { playgroundWidgetMode } = usePlaygroundWidgetMode()
const drawerRef = useRef<WidgetDrawer>(null)
const formRef = useRef<FormState>(null)
const { isSkeletonShown, isSkeletonSideBySide } = useSkeletonToolValues()
Expand All @@ -29,6 +32,14 @@ export function WidgetView() {
}
}, [formValues])

if (playgroundWidgetMode === 'checkout') {
return (
<WidgetViewContainer>
<CheckoutWidgetView />
</WidgetViewContainer>
)
}

return (
<WidgetViewContainer toggleDrawer={toggleDrawer}>
{!isSkeletonShown || isSkeletonSideBySide ? (
Expand Down
15 changes: 13 additions & 2 deletions packages/widget-playground/src/providers/EnvVariablesProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
import type { PropsWithChildren } from 'react'
import { createContext, useContext } from 'react'

const EnvVariablesContext = createContext({
export interface PlaygroundEnvVariables {
EVMWalletConnectId: string
/** Base URL for checkout cash on-ramp (mock or deployed), e.g. `http://localhost:8080`. */
onrampSessionApiUrl?: string
}

const EnvVariablesContext = createContext<PlaygroundEnvVariables>({
EVMWalletConnectId: '',
onrampSessionApiUrl: undefined,
})

interface EvnVariablesProviderProps extends PropsWithChildren {
EVMWalletConnectId: string
onrampSessionApiUrl?: string
}

export const EnvVariablesProvider = ({
children,
EVMWalletConnectId,
onrampSessionApiUrl,
}: EvnVariablesProviderProps) => {
return (
<EnvVariablesContext.Provider value={{ EVMWalletConnectId }}>
<EnvVariablesContext.Provider
value={{ EVMWalletConnectId, onrampSessionApiUrl }}
>
{children}
</EnvVariablesContext.Provider>
)
Expand Down
Loading