-
Notifications
You must be signed in to change notification settings - Fork 635
[MNY-226] Add Bridge Widget playgrounds (script, iframe, react) #8571
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
WalkthroughReplace legacy buy/swap tab UI with a unified BridgeWidget entry point, add/forward a new showThirdwebBranding prop, extend BridgeWidget props (connectOptions, className, style), and add a Bridge Widget playground (UI, codegen, iframe builder), docs, nav entry, and small styling/lint fixes. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant PlaygroundUI as BridgeWidgetPlayground
participant CodeGen
participant BridgeWidget
participant Iframe as WidgetIframe
User->>PlaygroundUI: configure options (theme, prefill, amounts, branding, integrationType)
PlaygroundUI->>PlaygroundUI: update options state
alt integrationType == "component" or "script"
PlaygroundUI->>BridgeWidget: render with props (theme, buy/sell prefill, currency, showThirdwebBranding, connectOptions)
BridgeWidget-->>User: interactive widget (buy/swap flows)
BridgeWidget->>PlaygroundUI: emit events (onSuccess/onError/onCancel)
else integrationType == "iframe"
PlaygroundUI->>CodeGen: build iframe URL via buildIframeUrl(options)
CodeGen->>Iframe: provide iframe src
Iframe-->>User: iframe loads remote widget with query params (tokens, amounts, theme, branding)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
Comment |
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (8)
apps/playground-web/src/app/x402/components/X402LeftSection.tsx (1)
66-79: Prefer a type guard over non-null assertion.The non-null assertion bypasses TypeScript's type safety. While the assertion appears safe due to conditional rendering, a type guard makes the safety explicit and prevents potential runtime errors if the component structure changes.
As per coding guidelines, avoid type-safety bypasses unless unavoidable.
Apply this diff to use a type guard:
const handleTokenChange = (token: TokenMetadata) => { + if (selectedChain === undefined) { + return; + } + setSelectedToken({ address: token.address, - // biome-ignore lint/style/noNonNullAssertion: ok - chainId: selectedChain!, + chainId: selectedChain, }); setOptions((v) => ({ ...v, tokenAddress: token.address as `0x${string}`, tokenSymbol: token.symbol ?? "", tokenDecimals: token.decimals ?? 18, })); };apps/playground-web/src/app/data/pages-metadata.ts (1)
120-147: Consider using distinct icons for better visual scanning.Using
SquareIconuniformly across five bridge widgets reduces visual distinction between card types. Different icons help users quickly scan and identify the widget they need.Additionally, note the inconsistency: the Transaction Button card (line 154) still uses
RectangleHorizontalIconwhile other bridge cards were updated toSquareIcon.If icon uniformity is a deliberate design decision, consider documenting the rationale. Otherwise, restoring distinct icons (e.g., credit card for Buy Widget, arrows for Bridge Widget) would improve the user experience.
apps/playground-web/src/hooks/chains.ts (1)
7-16: Consider reusing the BridgeChain type from packages.The local BridgeChain type might duplicate
packages/thirdweb/src/bridge/types/Chain.ts. If the package type matches these requirements, importing it would reduce duplication.apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
119-152: Consider extracting chainId resolution logic.The pattern of extracting
buyChainIdfrom quote types is repeated across error, cancel, and success handlers (lines 122-127, 155-160, 187-192). This could be refactored into a helper function to reduce duplication and improve maintainability.Example helper:
+function extractBuyChainId(quote: BuyOrOnrampPrepareResult | undefined): number | undefined { + if (!quote) return undefined; + return quote.type === "buy" + ? quote.intent.destinationChainId + : quote.type === "onramp" + ? quote.intent.chainId + : undefined; +}Then simplify the handlers:
onError: (e, quote) => { const errorMessage = parseError(e); - const buyChainId = - quote?.type === "buy" - ? quote.intent.destinationChainId - : quote?.type === "onramp" - ? quote.intent.chainId - : undefined; + const buyChainId = extractBuyChainId(quote);apps/portal/tsconfig.json (1)
38-38: Consider moving shared UI component to a common package.Including
../playground-web/src/components/ui/tab-buttons.tsxdirectly from the portal app creates tight coupling between these applications. Shared components are typically better placed in a common UI package (e.g.,packages/uior similar) to:
- Avoid build ordering issues
- Improve reusability
- Prevent circular dependencies
- Clarify component ownership
If this is a temporary solution for prototyping, consider tracking this as technical debt.
apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (2)
103-106: Replace inline style with Tailwind class.Per coding guidelines, use Tailwind CSS instead of inline styles.
<iframe src={buildIframeUrl(props.options)} height="750px" width="100%" title="Bridge Widget" className="fade-in-0 duration-500 animate-in rounded-xl" - style={{ - border: "0", - }} + className="fade-in-0 duration-500 animate-in rounded-xl border-0" />
115-143: Consider reusing the sharedTabButtonscomponent.A shared
TabButtonscomponent exists at@/components/ui/tab-buttons. This local implementation duplicates functionality. If the shared component's features (underline animation, tooltips) aren't needed here, the local version is acceptable, but consider using the shared one withhideBottomLineprop for consistency.apps/playground-web/src/components/ui/tab-buttons.tsx (1)
107-145: Consider usingrequestAnimationFrameinstead ofsetTimeout.The
setTimeoutcalls at lines 119-121 and 132-134 use arbitrary delays. UsingrequestAnimationFramewould be more reliable for visual updates and avoid potential timing issues:- setTimeout(() => { - lineEl.style.transition = "transform 0.3s, width 0.3s"; - }, 0); + requestAnimationFrame(() => { + lineEl.style.transition = "transform 0.3s, width 0.3s"; + });resizeObserver = new ResizeObserver(() => { - setTimeout(() => { - update(); - }, 100); + requestAnimationFrame(update); });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (25)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx(1 hunks)apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx(2 hunks)apps/dashboard/src/app/bridge/widget/page.tsx(3 hunks)apps/playground-web/src/app/ai/components/ChatPageContent.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/types.ts(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/page.tsx(1 hunks)apps/playground-web/src/app/bridge/page.tsx(2 hunks)apps/playground-web/src/app/data/pages-metadata.ts(2 hunks)apps/playground-web/src/app/navLinks.ts(1 hunks)apps/playground-web/src/app/transactions/users/page.tsx(2 hunks)apps/playground-web/src/app/x402/components/X402LeftSection.tsx(1 hunks)apps/playground-web/src/components/blocks/FeatureCard.tsx(1 hunks)apps/playground-web/src/components/ui/tab-buttons.tsx(1 hunks)apps/playground-web/src/hooks/chains.ts(1 hunks)apps/playground-web/src/icons/PayIcon.tsx(0 hunks)apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx(3 hunks)apps/portal/tsconfig.json(1 hunks)packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx(8 hunks)packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- apps/playground-web/src/icons/PayIcon.tsx
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes in TypeScript
Avoidanyandunknownin TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.) in TypeScript
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose
Files:
apps/playground-web/src/app/bridge/bridge-widget/page.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.tsapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxapps/dashboard/src/app/bridge/widget/page.tsxapps/playground-web/src/app/navLinks.tsapps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/playground-web/src/app/transactions/users/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/code.tsxapps/playground-web/src/components/blocks/FeatureCard.tsxapps/playground-web/src/components/ui/tab-buttons.tsxapps/playground-web/src/app/bridge/bridge-widget/components/types.tsapps/playground-web/src/hooks/chains.tsapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxapps/playground-web/src/app/bridge/page.tsxapps/playground-web/src/app/ai/components/ChatPageContent.tsxapps/playground-web/src/app/x402/components/X402LeftSection.tsxapps/playground-web/src/app/data/pages-metadata.ts
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Usecn()from@/lib/utilsfor conditional Tailwind class merging
Use design system tokens for styling (backgrounds:bg-card, borders:border-border, muted text:text-muted-foreground)
ExposeclassNameprop on root element for component overrides
Files:
apps/playground-web/src/app/bridge/bridge-widget/page.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.tsapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxapps/dashboard/src/app/bridge/widget/page.tsxapps/playground-web/src/app/navLinks.tsapps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/playground-web/src/app/transactions/users/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/code.tsxapps/playground-web/src/components/blocks/FeatureCard.tsxapps/playground-web/src/components/ui/tab-buttons.tsxapps/playground-web/src/app/bridge/bridge-widget/components/types.tsapps/playground-web/src/hooks/chains.tsapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/bridge/page.tsxapps/playground-web/src/app/ai/components/ChatPageContent.tsxapps/playground-web/src/app/x402/components/X402LeftSection.tsxapps/playground-web/src/app/data/pages-metadata.ts
**/*.{js,jsx,ts,tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Biome governs formatting and linting; its rules live in biome.json. Run
pnpm fix&pnpm lintbefore committing, ensure there are no linting errors
Files:
apps/playground-web/src/app/bridge/bridge-widget/page.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.tsapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxapps/dashboard/src/app/bridge/widget/page.tsxapps/playground-web/src/app/navLinks.tsapps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/playground-web/src/app/transactions/users/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/code.tsxapps/playground-web/src/components/blocks/FeatureCard.tsxapps/playground-web/src/components/ui/tab-buttons.tsxapps/playground-web/src/app/bridge/bridge-widget/components/types.tsapps/playground-web/src/hooks/chains.tsapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxapps/playground-web/src/app/bridge/page.tsxapps/portal/tsconfig.jsonapps/playground-web/src/app/ai/components/ChatPageContent.tsxapps/playground-web/src/app/x402/components/X402LeftSection.tsxapps/playground-web/src/app/data/pages-metadata.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Lazy-import optional features; avoid top-level side-effects
Files:
apps/playground-web/src/app/bridge/bridge-widget/page.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.tsapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxapps/dashboard/src/app/bridge/widget/page.tsxapps/playground-web/src/app/navLinks.tsapps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/playground-web/src/app/transactions/users/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/code.tsxapps/playground-web/src/components/blocks/FeatureCard.tsxapps/playground-web/src/components/ui/tab-buttons.tsxapps/playground-web/src/app/bridge/bridge-widget/components/types.tsapps/playground-web/src/hooks/chains.tsapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxapps/playground-web/src/app/bridge/page.tsxapps/playground-web/src/app/ai/components/ChatPageContent.tsxapps/playground-web/src/app/x402/components/X402LeftSection.tsxapps/playground-web/src/app/data/pages-metadata.ts
apps/dashboard/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/dashboard/src/**/*.{ts,tsx}: UseNavLinkfor internal navigation with automatic active states in dashboard
Start server component files withimport "server-only";in Next.js
Read cookies/headers withnext/headersin server components
Access server-only environment variables in server components
Perform heavy data fetching in server components
Implement redirect logic withredirect()fromnext/navigationin server components
Begin client component files with'use client';directive in Next.js
Handle interactive UI with React hooks (useState,useEffect, React Query, wallet hooks) in client components
Access browser APIs (localStorage,window,IntersectionObserver) in client components
Support fast transitions with prefetched data in client components
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader for API calls – never embed tokens in URLs
Return typed results (Project[],User[]) from server-side data fetches – avoidany
Wrap client-side API calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysin React Query for cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components – only use analytics client-side
Files:
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/dashboard/src/app/bridge/widget/page.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/dashboard/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
apps/dashboard/**/*.{ts,tsx}: Always import from the central UI library under@/components/ui/*for reusable core UI components likeButton,Input,Select,Tabs,Card,Sidebar,Separator,Badge
UseNavLinkfrom@/components/ui/NavLinkfor internal navigation to ensure active states are handled automatically
For notices and skeletons, rely onAnnouncementBanner,GenericLoadingPage, andEmptyStateCardcomponents
Import icons fromlucide-reactor the project-specific…/iconsexports; never embed raw SVG
Keep components pure; fetch data outside using server components or hooks and pass it down via props
Use Tailwind CSS as the styling system; avoid inline styles or CSS modules
Merge class names withcnfrom@/lib/utilsto keep conditional logic readable
Stick to design tokens: usebg-card,border-border,text-muted-foregroundand other Tailwind variables instead of hard-coded colors
Use spacing utilities (px-*,py-*,gap-*) instead of custom margins
Follow mobile-first responsive design with Tailwind helpers (max-sm,md,lg,xl)
Never hard-code colors; always use Tailwind variables
Combine class names viacn, and exposeclassNameprop if useful in components
Use React Query (@tanstack/react-query) for all client-side data fetching with typed hooks
Files:
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/dashboard/src/app/bridge/widget/page.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{tsx,ts}: Import UI primitives from @/components/ui/_ (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in Dashboard and Playground apps
Use NavLink for internal navigation so active states are handled automatically
Use Tailwind CSS for styling – no inline styles or CSS modules
Merge class names with cn() from @/lib/utils to keep conditional logic readable
Stick to design tokens for styling: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
Server Components: Read cookies/headers with next/headers, access server-only environment variables or secrets, perform heavy data fetching, implement redirect logic with redirect() from next/navigation, and start files with import 'server-only'; to prevent client bundling
Client Components: Begin files with 'use client'; before imports, handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks), access browser APIs (localStorage, window, IntersectionObserver, etc.), and support fast transitions with client-side data prefetching
For client-side data fetching: Wrap calls in React Query (@tanstack/react-query), use descriptive and stable queryKeys for cache hits, configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s), and keep tokens secret by calling internal API routes or server actions
Files:
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/dashboard/src/app/bridge/widget/page.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: For server-side data fetching: Always call getAuthToken() to retrieve the JWT from cookies and inject the token as an Authorization: Bearer header – never embed it in the URL. Return typed results (Project[], User[], …) – avoid any
Never import posthog-js in server components; analytics reporting is client-side only
Files:
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/dashboard/src/app/bridge/widget/page.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/dashboard/**/page.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
Use the
containerclass with amax-w-7xlcap for consistent page width
Files:
apps/dashboard/src/app/bridge/widget/page.tsx
apps/dashboard/**/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
Add
classNameprop to the root element of every component to allow external overrides
Files:
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}: Group feature-specific components under feature/components/_ and expose a barrel index.ts when necessary
Expose a className prop on the root element of every component for styling overrides
Files:
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
packages/thirdweb/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
packages/thirdweb/src/**/*.{ts,tsx}: Comment only ambiguous logic in SDK code; avoid restating TypeScript in prose
Load heavy dependencies inside async paths to keep initial bundle lean (e.g.const { jsPDF } = await import("jspdf");)Lazy-load heavy dependencies inside async paths to keep the initial bundle lean (e.g., const { jsPDF } = await import('jspdf');)
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx
**/*.stories.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
Add Storybook stories (
*.stories.tsx) alongside new UI components for documentation
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
**/*.stories.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
For new UI components, add Storybook stories (*.stories.tsx) alongside the code
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
🧬 Code graph analysis (7)
apps/playground-web/src/app/bridge/bridge-widget/page.tsx (2)
apps/playground-web/src/app/bridge/page.tsx (1)
Page(5-14)apps/playground-web/src/components/blocks/APIHeader.tsx (1)
PageLayout(49-70)
apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts (1)
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
BridgeWidgetPlaygroundOptions(7-28)
apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx (4)
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
BridgeWidgetPlaygroundOptions(7-28)apps/playground-web/src/components/ui/tab-buttons.tsx (1)
TabButtons(16-96)apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx (1)
LeftSection(20-119)apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (1)
RightSection(13-113)
apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx (4)
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
BridgeWidgetPlaygroundOptions(7-28)apps/playground-web/src/lib/code-gen.ts (2)
quotes(17-19)stringifyImports(21-29)apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts (1)
buildIframeUrl(5-67)apps/playground-web/src/app/bridge/components/CodeGen.tsx (1)
CodeGen(24-39)
apps/playground-web/src/hooks/chains.ts (1)
packages/thirdweb/src/bridge/types/Chain.ts (1)
BridgeChain(42-42)
apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (3)
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
BridgeWidgetPlaygroundOptions(7-28)apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts (1)
buildIframeUrl(5-67)apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx (1)
CodeGen(21-33)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (3)
packages/thirdweb/src/exports/react.ts (1)
BridgeWidget(148-148)apps/dashboard/src/@/constants/connect.ts (1)
appMetadata(1-5)apps/dashboard/src/@/analytics/report.ts (9)
reportTokenBuyFailed(264-266)reportAssetBuyFailed(342-350)reportTokenBuyCancelled(276-278)reportAssetBuyCancelled(360-367)reportTokenBuySuccessful(252-254)reportAssetBuySuccessful(221-228)reportTokenSwapFailed(314-320)reportTokenSwapSuccessful(288-290)reportTokenSwapCancelled(330-332)
🪛 LanguageTool
apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx
[style] ~103-~103: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...9&outputChain=137" />
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: Size
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Lint Packages
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Build Packages
- GitHub Check: Unit Tests
- GitHub Check: Analyze (javascript)
🔇 Additional comments (26)
apps/playground-web/src/app/ai/components/ChatPageContent.tsx (1)
87-87: PreferNumber.isNaN()over globalisNaN().The change to use
Number.isNaN()is the idiomatic choice for numeric validation in modern TypeScript. While both functions produce the same result here (sinceNumber(id)is called explicitly),Number.isNaN()is more explicit and avoids relying on legacy global coercion behavior. As per coding guidelines, this aligns with writing idiomatic TypeScript.apps/playground-web/src/components/blocks/FeatureCard.tsx (1)
16-16: LGTM!The font weight increase to
font-semiboldimproves the visual hierarchy for card titles.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx (1)
286-286: LGTM – Typography refinement aligns with design system updates.The change from
font-boldtofont-semiboldis a deliberate design refinement that maintains readability while improving visual hierarchy for token metric values.apps/playground-web/src/app/data/pages-metadata.ts (1)
120-125: LGTM: Explicit field structure improves clarity.The addition of explicit
title,link, anddescriptionfields makes the first Bridge Widget entry more consistent with the other entries and improves code readability.apps/playground-web/src/hooks/chains.ts (1)
33-48: LGTM! Clean sorting implementation.The sorting logic correctly prioritizes non-numeric chain names and handles edge cases appropriately. The optional chaining on line 36-37 safely handles empty strings, and
localeCompareensures locale-aware alphabetical ordering.apps/playground-web/src/app/transactions/users/page.tsx (1)
34-97: LGTM! Unnecessary fragment removed.The React fragment was redundant since
UserTransactionsreturns a single element. Removing it improves code clarity.packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (1)
45-67: Direct rendering is appropriate for custom theme objects.The change from using the
Varianthelper to directly renderingBridgeWidgetScriptis correct. TheVarianthelper overrides thethemeprop with string values ("dark"/"light"), which would defeat the purpose of demonstrating a custom theme object that already specifiestype: "light"within its structure. This aligns with the other stories (BasicUsage, CurrencySet, NoThirdwebBranding) which useVariantbecause they rely on theme strings, while CustomTheme uses direct rendering since it uses a theme object.apps/playground-web/src/app/bridge/page.tsx (1)
1-1: LGTM! Icon choice is semantically appropriate.The change from
PayIcontoBringToFrontIconbetter represents bridge functionality.Also applies to: 11-11
apps/playground-web/src/app/navLinks.ts (1)
190-193: LGTM! Navigation entry is consistent and well-placed.The new "Bridge Widget" link follows the established pattern and is logically positioned in the menu structure.
apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx (1)
64-65: LGTM! Comprehensive documentation with clear examples.The new sections for token amounts and branding control are well-documented with working examples. The structure is clear and consistent with the existing documentation style.
Also applies to: 103-122, 175-180
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
104-259: LGTM! BridgeWidget integration is well-structured.The refactor from separate Buy/Swap widgets to BridgeWidget is comprehensive. Analytics reporting is properly preserved, callbacks are correctly wired, and error handling covers all necessary cases.
packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx (2)
35-36: LGTM! API expansion is well-structured and documented.The addition of
className,style, andconnectOptionsprops significantly enhances configurability while maintaining backward compatibility. TheconnectOptionsdocumentation is comprehensive and follows the established pattern of other thirdweb components.Also applies to: 202-311
471-479: LGTM! Explicit styling improves consistency.The TabButton styling changes from implicit to explicit values (height: "36px", paddingInline/paddingBlock) improve predictability and maintainability.
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx (1)
28-28: LGTM! Proper prop threading.The
showThirdwebBrandingprop is correctly added and forwarded toBuyAndSwapEmbed.Also applies to: 38-38
apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts (1)
9-66: LGTM! URL building logic is clean and efficient.The implementation correctly:
- Disables token persistence for playground consistency
- Only adds non-default parameters to keep URLs clean
- Properly handles optional fields with conditional logic
apps/playground-web/src/app/bridge/bridge-widget/page.tsx (1)
1-33: LGTM!Clean page setup following the existing pattern from other bridge pages. Proper use of
ThirdwebProvider,PageLayout, andcreateMetadata. Structure is consistent with the codebase conventions.apps/dashboard/src/app/bridge/widget/page.tsx (2)
44-47: Verify default behavior forshowThirdwebBranding.When the
showThirdwebBrandingsearch param is not provided,parsereturnsundefined(nottrue). If the intent is to show branding by default when the param is absent, consider providing a fallback:const showThirdwebBranding = parse( searchParams.showThirdwebBranding, (v) => v !== "false", - ); + ) ?? true;Otherwise, ensure
UniversalBridgeEmbedcorrectly interpretsundefinedas "show branding."
77-99: LGTM on amount handling.The conditional string conversion for
buyAmountandsellAmountcorrectly handles the undefined case, avoiding potential runtime errors from calling.toString()on undefined.apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (1)
56-93: LGTM on BridgeWidget integration.The widget configuration correctly passes theme, prefill data, currency, and branding options. The
keyprop usingJSON.stringifyensures the widget re-renders when prefill changes.apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx (1)
39-73: LGTM on layout and tab structure.Clean composition of
LeftSectionandRightSectionwith proper state management. The responsive layout withxl:breakpoints and tab switching logic work correctly.apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx (1)
20-118: LGTM on LeftSection structure.Well-organized configuration UI with proper separation of concerns. Good use of collapsible sections, form controls, and conditional rendering for iframe-specific restrictions on color customization.
apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx (2)
120-202: LGTM on React component code generation.Clean implementation with proper import management, theme handling, and prop construction. The
stringifyImportsandstringifyPropsutilities keep the code generation readable.
54-72: I'm unable to verify this review comment because the repository could not be accessed and web search is not available. To complete verification, I need to:
- Examine the actual code at lines 54-72 in
apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx- Compare with the React component generation at lines 131-133
- Check the BridgeWidget API documentation to confirm the expected theme structure
- Verify if spreading overrides at the root level vs. nesting under
colorsis indeed an errorPlease provide access to the codebase or confirm the file contents so I can validate whether the theme configuration inconsistency exists and if the suggested fix is correct.
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
1-28: LGTM!Clean type definition that properly leverages
thirdweb/reacttypes for consistency. The structure withintegrationType,theme,prefill, andshowThirdwebBrandingaligns well with the component requirements.apps/playground-web/src/components/ui/tab-buttons.tsx (2)
16-95: LGTM on TabButtons component structure.Well-designed reusable component with good customization options through className props. The active underline animation and tooltip integration provide a polished UX.
5-7: Replace cross-boundary imports from portal with@/components/uialiases.These imports reach into the portal app's source directory, violating coding guidelines. Per project conventions, import from
@/components/ui/*in playground-web. Verify whether these components exist inapps/playground-web/src/components/ui/or need to be extracted to a shared workspace package.- import { Button } from "../../../../portal/src/components/ui/button"; - import { ScrollShadow } from "../../../../portal/src/components/ui/ScrollShadow"; - import { ToolTipLabel } from "../../../../portal/src/components/ui/tooltip"; + import { Button } from "@/components/ui/button"; + import { ScrollShadow } from "@/components/ui/ScrollShadow"; + import { ToolTipLabel } from "@/components/ui/tooltip";
apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx
Show resolved
Hide resolved
apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts
Outdated
Show resolved
Hide resolved
apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx
Show resolved
Hide resolved
size-limit report 📦
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (2)
apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx (1)
174-185: Token selection clears the amount field.When selecting a new token, the current
amountvalue is lost because the update doesn't spread the existing prefill data for the token type. Apply the same pattern used in chain selection (lines 153-154):onChange={(token) => { setOptions((v) => ({ ...v, prefill: { ...v.prefill, [props.type]: { + ...v.prefill?.[props.type], chainId: token.chainId, tokenAddress: token.address, }, }, })); }}apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx (1)
22-37: UseresolvedThemefor accurate theme detection.The
themevalue fromuseTheme()can be"system", which doesn't match the expected"dark" | "light"comparison. UseresolvedThemeinstead:export function BridgeWidgetPlayground() { - const { theme } = useTheme(); + const { resolvedTheme } = useTheme(); const [options, setOptions] = useState<BridgeWidgetPlaygroundOptions>(defaultOptions); // change theme on global theme change useEffect(() => { setOptions((prev) => ({ ...prev, theme: { ...prev.theme, - type: theme === "dark" ? "dark" : "light", + type: resolvedTheme === "dark" ? "dark" : "light", }, })); - }, [theme]); + }, [resolvedTheme]);
🧹 Nitpick comments (7)
apps/playground-web/src/hooks/chains.ts (1)
35-48: Simplify regex check for numeric-starting names.The current approach uses
a.name[0]?.match(/^\d/)to detect if a name starts with a digit. Consider using/^\d/.test(a.name)instead, which is more idiomatic and directly tests the entire string without needing to access the first character.Apply this diff:
return data.sort((a, b) => { - const aStartsWithNumber = a.name[0]?.match(/^\d/); - const bStartsWithNumber = b.name[0]?.match(/^\d/); + const aStartsWithNumber = /^\d/.test(a.name); + const bStartsWithNumber = /^\d/.test(b.name); if (aStartsWithNumber && !bStartsWithNumber) { return 1; } if (!aStartsWithNumber && bStartsWithNumber) { return -1; } return a.name.localeCompare(b.name); });apps/playground-web/src/app/data/pages-metadata.ts (1)
120-120: Consider using distinct icons for visual differentiation.All five bridge widget cards now use
SquareIcon, which reduces visual hierarchy and makes it harder for users to quickly scan and distinguish between options. Consider assigning unique icons (e.g.,ArrowLeftRightIconfor Bridge,RepeatIconfor Swap,DollarSignIconfor Buy) to improve scannability.Also applies to: 127-127, 133-133, 140-140, 147-147
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (4)
13-20: Add explicit return types to story functions.These exported story functions lack explicit return types. As per coding guidelines, TypeScript functions should have explicit return types.
Apply this diff to add return types:
-export function BasicUsage() { +export function BasicUsage(): React.JSX.Element { return ( <Variant clientId={storyClient.clientId} buy={{ chainId: 8453, amount: "0.1" }} /> ); } -export function CurrencySet() { +export function CurrencySet(): React.JSX.Element { return ( <Variant clientId={storyClient.clientId} currency="JPY" buy={{ chainId: 8453, amount: "0.1" }} /> ); } -export function NoThirdwebBranding() { +export function NoThirdwebBranding(): React.JSX.Element { return ( <Variant clientId={storyClient.clientId} theme="light" buy={{ chainId: 8453, amount: "0.1" }} showThirdwebBranding={false} /> ); }Also applies to: 22-30, 32-41
43-69: Add explicit return type to CustomTheme story.The CustomTheme function lacks an explicit return type. As per coding guidelines, TypeScript functions should have explicit return types.
Apply this diff:
-export function CustomTheme() { +export function CustomTheme(): React.JSX.Element { return ( <divThe refactored implementation (directly rendering BridgeWidgetScript with custom theme) looks good and is more appropriate for demonstrating custom theming than the previous Variant-based approach.
71-85: Add explicit return type to Variant helper.The Variant helper function lacks an explicit return type. As per coding guidelines, TypeScript functions should have explicit return types.
Apply this diff:
-function Variant(props: BridgeWidgetScriptProps) { +function Variant(props: BridgeWidgetScriptProps): React.JSX.Element { return (
17-17: Consider extracting repeated buy configuration.The
buy={{ chainId: 8453, amount: "0.1" }}configuration is repeated across all stories. Consider extracting it to a constant for maintainability.Example:
const DEFAULT_BUY_CONFIG = { chainId: 8453, amount: "0.1" } as const; export function BasicUsage(): React.JSX.Element { return ( <Variant clientId={storyClient.clientId} buy={DEFAULT_BUY_CONFIG} /> ); }Also applies to: 27-27, 37-37, 55-55
apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (1)
115-143: Consider reusing the shared TabButtons component.A
TabButtonscomponent already exists at@/components/ui/tab-buttons.tsxwith more features (icons, tooltips, disabled states, underline animation). Consider using it here for consistency, or if the simpler styling is intentional for this context, add a brief comment explaining the choice.+"use client"; +import { useState } from "react"; +import { BridgeWidget, darkTheme, lightTheme } from "thirdweb/react"; +import { Button } from "@/components/ui/button"; ++import { TabButtons } from "@/components/ui/tab-buttons"; +import { THIRDWEB_CLIENT } from "@/lib/client";Then replace the local
TabButtonsusage with the shared one, or keep the local version if the simplified styling is intentional for this pill-button design.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (24)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx(1 hunks)apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx(2 hunks)apps/dashboard/src/app/bridge/widget/page.tsx(3 hunks)apps/playground-web/src/app/ai/components/ChatPageContent.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/types.ts(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/page.tsx(1 hunks)apps/playground-web/src/app/bridge/page.tsx(2 hunks)apps/playground-web/src/app/data/pages-metadata.ts(2 hunks)apps/playground-web/src/app/navLinks.ts(1 hunks)apps/playground-web/src/app/transactions/users/page.tsx(2 hunks)apps/playground-web/src/app/x402/components/X402LeftSection.tsx(1 hunks)apps/playground-web/src/components/blocks/FeatureCard.tsx(1 hunks)apps/playground-web/src/components/ui/tab-buttons.tsx(1 hunks)apps/playground-web/src/hooks/chains.ts(1 hunks)apps/playground-web/src/icons/PayIcon.tsx(0 hunks)apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx(3 hunks)packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx(8 hunks)packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- apps/playground-web/src/icons/PayIcon.tsx
🚧 Files skipped from review as they are similar to previous changes (12)
- apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts
- apps/playground-web/src/app/x402/components/X402LeftSection.tsx
- apps/playground-web/src/app/bridge/bridge-widget/components/types.ts
- apps/playground-web/src/app/transactions/users/page.tsx
- apps/dashboard/src/app/bridge/widget/page.tsx
- apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx
- apps/playground-web/src/components/blocks/FeatureCard.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
- apps/playground-web/src/components/ui/tab-buttons.tsx
- apps/playground-web/src/app/bridge/page.tsx
- apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx
- apps/playground-web/src/app/ai/components/ChatPageContent.tsx
🧰 Additional context used
📓 Path-based instructions (13)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes in TypeScript
Avoidanyandunknownin TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.) in TypeScript
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose
Files:
apps/playground-web/src/app/bridge/bridge-widget/page.tsxapps/playground-web/src/app/data/pages-metadata.tspackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/playground-web/src/app/navLinks.tsapps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/playground-web/src/hooks/chains.tsapps/playground-web/src/app/bridge/bridge-widget/components/code.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Usecn()from@/lib/utilsfor conditional Tailwind class merging
Use design system tokens for styling (backgrounds:bg-card, borders:border-border, muted text:text-muted-foreground)
ExposeclassNameprop on root element for component overrides
Files:
apps/playground-web/src/app/bridge/bridge-widget/page.tsxapps/playground-web/src/app/data/pages-metadata.tsapps/playground-web/src/app/navLinks.tsapps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/playground-web/src/hooks/chains.tsapps/playground-web/src/app/bridge/bridge-widget/components/code.tsx
**/*.{js,jsx,ts,tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Biome governs formatting and linting; its rules live in biome.json. Run
pnpm fix&pnpm lintbefore committing, ensure there are no linting errors
Files:
apps/playground-web/src/app/bridge/bridge-widget/page.tsxapps/playground-web/src/app/data/pages-metadata.tspackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/playground-web/src/app/navLinks.tsapps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/playground-web/src/hooks/chains.tsapps/playground-web/src/app/bridge/bridge-widget/components/code.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Lazy-import optional features; avoid top-level side-effects
Files:
apps/playground-web/src/app/bridge/bridge-widget/page.tsxapps/playground-web/src/app/data/pages-metadata.tspackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/playground-web/src/app/navLinks.tsapps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/playground-web/src/hooks/chains.tsapps/playground-web/src/app/bridge/bridge-widget/components/code.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx
packages/thirdweb/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
packages/thirdweb/src/**/*.{ts,tsx}: Comment only ambiguous logic in SDK code; avoid restating TypeScript in prose
Load heavy dependencies inside async paths to keep initial bundle lean (e.g.const { jsPDF } = await import("jspdf");)Lazy-load heavy dependencies inside async paths to keep the initial bundle lean (e.g., const { jsPDF } = await import('jspdf');)
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx
**/*.stories.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
Add Storybook stories (
*.stories.tsx) alongside new UI components for documentation
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
**/*.stories.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
For new UI components, add Storybook stories (*.stories.tsx) alongside the code
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
apps/dashboard/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/dashboard/src/**/*.{ts,tsx}: UseNavLinkfor internal navigation with automatic active states in dashboard
Start server component files withimport "server-only";in Next.js
Read cookies/headers withnext/headersin server components
Access server-only environment variables in server components
Perform heavy data fetching in server components
Implement redirect logic withredirect()fromnext/navigationin server components
Begin client component files with'use client';directive in Next.js
Handle interactive UI with React hooks (useState,useEffect, React Query, wallet hooks) in client components
Access browser APIs (localStorage,window,IntersectionObserver) in client components
Support fast transitions with prefetched data in client components
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader for API calls – never embed tokens in URLs
Return typed results (Project[],User[]) from server-side data fetches – avoidany
Wrap client-side API calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysin React Query for cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components – only use analytics client-side
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/dashboard/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
apps/dashboard/**/*.{ts,tsx}: Always import from the central UI library under@/components/ui/*for reusable core UI components likeButton,Input,Select,Tabs,Card,Sidebar,Separator,Badge
UseNavLinkfrom@/components/ui/NavLinkfor internal navigation to ensure active states are handled automatically
For notices and skeletons, rely onAnnouncementBanner,GenericLoadingPage, andEmptyStateCardcomponents
Import icons fromlucide-reactor the project-specific…/iconsexports; never embed raw SVG
Keep components pure; fetch data outside using server components or hooks and pass it down via props
Use Tailwind CSS as the styling system; avoid inline styles or CSS modules
Merge class names withcnfrom@/lib/utilsto keep conditional logic readable
Stick to design tokens: usebg-card,border-border,text-muted-foregroundand other Tailwind variables instead of hard-coded colors
Use spacing utilities (px-*,py-*,gap-*) instead of custom margins
Follow mobile-first responsive design with Tailwind helpers (max-sm,md,lg,xl)
Never hard-code colors; always use Tailwind variables
Combine class names viacn, and exposeclassNameprop if useful in components
Use React Query (@tanstack/react-query) for all client-side data fetching with typed hooks
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/dashboard/**/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
Add
classNameprop to the root element of every component to allow external overrides
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{tsx,ts}: Import UI primitives from @/components/ui/_ (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in Dashboard and Playground apps
Use NavLink for internal navigation so active states are handled automatically
Use Tailwind CSS for styling – no inline styles or CSS modules
Merge class names with cn() from @/lib/utils to keep conditional logic readable
Stick to design tokens for styling: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
Server Components: Read cookies/headers with next/headers, access server-only environment variables or secrets, perform heavy data fetching, implement redirect logic with redirect() from next/navigation, and start files with import 'server-only'; to prevent client bundling
Client Components: Begin files with 'use client'; before imports, handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks), access browser APIs (localStorage, window, IntersectionObserver, etc.), and support fast transitions with client-side data prefetching
For client-side data fetching: Wrap calls in React Query (@tanstack/react-query), use descriptive and stable queryKeys for cache hits, configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s), and keep tokens secret by calling internal API routes or server actions
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}: Group feature-specific components under feature/components/_ and expose a barrel index.ts when necessary
Expose a className prop on the root element of every component for styling overrides
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: For server-side data fetching: Always call getAuthToken() to retrieve the JWT from cookies and inject the token as an Authorization: Bearer header – never embed it in the URL. Return typed results (Project[], User[], …) – avoid any
Never import posthog-js in server components; analytics reporting is client-side only
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
🧬 Code graph analysis (6)
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (2)
packages/thirdweb/src/script-exports/bridge-widget-script.tsx (1)
BridgeWidgetScript(69-79)packages/thirdweb/src/stories/utils.tsx (1)
storyClient(14-16)
apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx (6)
apps/playground-web/src/app/wallets/sign-in/components/CollapsibleSection.tsx (1)
CollapsibleSection(4-33)packages/thirdweb/src/react/web/ui/components/formElements.tsx (1)
Label(20-28)apps/playground-web/src/app/wallets/sign-in/components/ColorFormGroup.tsx (1)
ColorFormGroup(9-111)apps/dashboard/src/@/components/ui/checkbox.tsx (1)
Checkbox(34-34)apps/playground-web/src/app/x402/components/constants.ts (1)
token(4-9)packages/thirdweb/src/exports/thirdweb.ts (1)
NATIVE_TOKEN_ADDRESS(31-31)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (4)
packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx (1)
BridgeWidget(363-455)packages/thirdweb/src/exports/react.ts (1)
BridgeWidget(148-148)apps/dashboard/src/@/constants/connect.ts (1)
appMetadata(1-5)apps/dashboard/src/@/analytics/report.ts (9)
reportTokenBuyFailed(264-266)reportAssetBuyFailed(342-350)reportTokenBuyCancelled(276-278)reportAssetBuyCancelled(360-367)reportTokenBuySuccessful(252-254)reportAssetBuySuccessful(221-228)reportTokenSwapFailed(314-320)reportTokenSwapSuccessful(288-290)reportTokenSwapCancelled(330-332)
apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx (4)
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
BridgeWidgetPlaygroundOptions(7-28)apps/playground-web/src/components/ui/tab-buttons.tsx (1)
TabButtons(16-96)apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx (1)
LeftSection(20-119)apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (1)
RightSection(13-113)
apps/playground-web/src/hooks/chains.ts (1)
packages/thirdweb/src/bridge/types/Chain.ts (1)
BridgeChain(42-42)
packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx (2)
packages/thirdweb/src/exports/react.ts (2)
ConnectButton_connectModalOptions(16-16)SiweAuthOptions(12-12)packages/thirdweb/src/wallets/types.ts (1)
AppMetadata(3-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Size
- GitHub Check: Unit Tests
- GitHub Check: Lint Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (15)
apps/playground-web/src/app/data/pages-metadata.ts (1)
120-125: LGTM!The Bridge Widget entry now has explicit metadata fields that align with the feature card structure and accurately describe the widget's capabilities (bridging with cross-chain support and fiat onramp).
apps/playground-web/src/app/navLinks.ts (1)
190-193: LGTM!The new Bridge Widget navigation link follows the established pattern and is correctly placed in the bridge section.
apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx (2)
1-19: LGTM!Imports are well-organized and appropriate for the component's functionality. Good use of thirdweb utilities and UI components from the shared library.
20-119: LGTM!The LeftSection component properly manages theme state and conditionally disables color customization for iframe mode (which makes sense since iframes can't pass complex theme objects).
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (2)
103-259: LGTM!The refactored BridgeWidget integration properly consolidates buy/swap flows and correctly propagates the new
showThirdwebBrandingprop. The error handling callbacks appropriately extract chain/token information from quotes and report to analytics.
227-256: Swap callbacks correctly access quote intent data.The swap
onError,onSuccess, andonCancelhandlers safely accessquote.intentproperties sinceSwapPreparedQuoteguarantees these fields are present when the callbacks are invoked.packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx (3)
34-36: LGTM!Good addition of
classNameandstyleprops for styling flexibility, following React component conventions.
202-311: Comprehensive connectOptions configuration.The
connectOptionsprop is well-documented with JSDoc comments and provides flexible wallet connection configuration. This aligns with existing patterns in the thirdweb SDK.
376-454: Props correctly forwarded to child widgets.The
className,style, andconnectOptionsprops are properly applied toEmbedContainerand forwarded toSwapWidget/BuyWidgetrespectively.apps/playground-web/src/app/bridge/bridge-widget/page.tsx (1)
1-33: LGTM!The page follows the established playground pattern with proper metadata configuration, ThirdwebProvider wrapping, and PageLayout usage with appropriate props.
apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx (2)
10-20: LGTM!Default options are properly structured with sensible defaults for the playground.
39-73: LGTM!The layout structure with TabButtons and responsive flex layout is well-implemented. The tab click handlers correctly update the
integrationType.apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (2)
1-32: LGTM!Imports and theme object construction are correct. The conditional theme creation based on
options.theme.typeproperly applies color overrides.
56-93: Good use ofkeyprop for remounting on prefill changes.Using
key={JSON.stringify(props.options.prefill)}ensures the BridgeWidget remounts when prefill data changes, which is appropriate for resetting the widget state.apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx (1)
85-98: The overlap betweenbuyandswap.prefillproperties is intentional and correct.The BridgeWidget renders two separate tabs with distinct widgets: the Buy tab uses BuyWidget with individual props (
amount,chainId,tokenAddress), while the Swap tab uses SwapWidget with aprefillobject. WhenbuyTokenis specified in options, populating both properties allows:
- The Buy tab to be pre-configured with the token for purchasing via onramp
- The Swap tab to have the token pre-selected as the starting buyToken for swapping
This design ensures both tabs are properly initialized when a user specifies a buyToken, which is the expected behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (3)
apps/playground-web/src/app/transactions/users/page.tsx (1)
32-32: Add explicit return type annotation.The
UserTransactionsfunction is still missing an explicit return type, which is required by the coding guidelines.Apply this diff:
-function UserTransactions() { +function UserTransactions(): JSX.Element {apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx (1)
23-37: UseresolvedThemefor accurate theme detection.The
themevalue fromuseTheme()can be"system", which doesn't match your expected"dark" | "light". UseresolvedThemeinstead.apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx (1)
174-185: Token selection clears the amount field.When selecting a new token, the current
amountvalue is lost because the update doesn't spread the existing prefill data. This differs from the chain selection logic (lines 148-159) and amount input logic (lines 210-223) which both preserve other fields.
🧹 Nitpick comments (12)
apps/playground-web/src/app/x402/components/X402LeftSection.tsx (1)
66-79: Make the suppression comment more descriptive or add a defensive guard.The biome-ignore comment "ok" doesn't explain why the non-null assertion on line 70 is safe. While the assertion is technically safe (because
TokenSelectoronly renders whenselectedChainis defined), the vague comment harms maintainability.Consider one of these approaches:
Option 1: Replace with a descriptive comment explaining the safety:
- // biome-ignore lint/style/noNonNullAssertion: ok + // biome-ignore lint/style/noNonNullAssertion: TokenSelector only renders when selectedChain is defined chainId: selectedChain!,Option 2: Add a defensive guard (preferred for robustness):
const handleTokenChange = (token: TokenMetadata) => { + if (!selectedChain) return; + setSelectedToken({ address: token.address, - // biome-ignore lint/style/noNonNullAssertion: ok chainId: selectedChain!, });packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (2)
45-51: Consider extracting duplicated wrapper styling.The div styling here is identical to the Variant helper's wrapper styling (lines 74-79). To reduce duplication, consider extracting a shared
StoryWrappercomponent or const.Example refactor:
const storyWrapperStyle = { display: "flex", flexDirection: "column", gap: "40px", alignItems: "center", } as const; export function CustomTheme() { return ( <div style={storyWrapperStyle}> <BridgeWidgetScript // ... props /> </div> ); } function Variant(props: BridgeWidgetScriptProps) { return ( <div style={storyWrapperStyle}> {/* ... */} </div> ); }
43-43: Add explicit return type annotation.Per coding guidelines, TypeScript functions should have explicit return types.
As per coding guidelines, TypeScript functions should have explicit return types.
-export function CustomTheme() { +export function CustomTheme(): JSX.Element {apps/dashboard/src/app/bridge/widget/page.tsx (1)
44-47: Non-standard boolean parsing could confuse users.The current logic treats any value other than the exact string
"false"as true. This means"0","no","FALSE","off", etc., would all be interpreted as true, which may not match user expectations.Consider using a more explicit allow-list approach:
- const showThirdwebBranding = parse( - searchParams.showThirdwebBranding, - (v) => v !== "false", - ); + const showThirdwebBranding = parse( + searchParams.showThirdwebBranding, + (v) => v === "true" || v === "1", + ) ?? true; // default to true if not specifiedAlternatively, if the current behavior is intentional, document it clearly in the query parameter documentation.
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
119-217: Extract helper for buy token info to reduce duplication.The logic for extracting
buyChainIdandbuyTokenAddressfrom quotes is duplicated acrossonError,onCancel, andonSuccesscallbacks. This increases maintenance burden and the risk of inconsistencies.Consider extracting a helper function:
function getBuyTokenInfo(quote: BuyQuote | OnrampQuote | undefined) { if (!quote) return undefined; if (quote.type === "buy") { return { chainId: quote.intent.destinationChainId, tokenAddress: quote.intent.destinationTokenAddress, }; } if (quote.type === "onramp") { return { chainId: quote.intent.chainId, tokenAddress: quote.intent.tokenAddress, }; } return undefined; }Then use it in callbacks:
onError: (e, quote) => { const errorMessage = parseError(e); const tokenInfo = getBuyTokenInfo(quote); if (!tokenInfo) return; reportTokenBuyFailed({ buyTokenChainId: tokenInfo.chainId, buyTokenAddress: tokenInfo.tokenAddress, pageType: props.pageType, }); if (props.pageType === "asset") { reportAssetBuyFailed({ assetType: "coin", chainId: tokenInfo.chainId, error: errorMessage, contractType: undefined, is_testnet: false, }); } },apps/playground-web/src/app/data/pages-metadata.ts (1)
120-160: Consider unique icons for each bridge widget to improve visual distinction.The
bridgeFeatureCardscurrently usesSquareIconfor all five widgets (Bridge, Swap, Buy, Checkout, Transaction Widget) while the Transaction Button usesRectangleHorizontalIcon. This icon choice appears intentional—Transaction Button uses the same icon pattern as "Connect Button" in the wallets section, semantically distinguishing button-like components from widget components.However, reusing the same icon for five distinct widgets reduces visual distinction compared to other feature card groups like
walletsFeatureCards, which assigns unique icons to each item. Consider whether each bridge widget would benefit from a unique icon to improve user discoverability and visual hierarchy.apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (2)
115-143: Consider using the sharedTabButtonscomponent instead of duplicating.There's already a
TabButtonscomponent at@/components/ui/tab-buttonswith additional features (underline animation, icons, tooltips). This local implementation duplicates functionality and diverges in styling.-import { Button } from "@/components/ui/button"; +import { TabButtons } from "@/components/ui/tab-buttons";Then remove the local
TabButtonsfunction (lines 115-143) and update the usage at lines 35-48 to match the shared component's API.
103-105: Use Tailwind class instead of inline style.Per coding guidelines, use Tailwind CSS only – no inline styles.
className="fade-in-0 duration-500 animate-in rounded-xl" - style={{ - border: "0", - }} + className="fade-in-0 duration-500 animate-in rounded-xl border-0"apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx (1)
45-60: Use functional state updates to avoid stale closure.The
onClickhandlers captureoptionsat render time. If multiple tabs are clicked rapidly, this could cause stale state issues. Use functional updates for consistency with other state updates in this codebase.{ name: "Iframe", - onClick: () => - setOptions({ ...options, integrationType: "iframe" }), + onClick: () => + setOptions((prev) => ({ ...prev, integrationType: "iframe" })), isActive: options.integrationType === "iframe", }, { name: "Script", - onClick: () => - setOptions({ ...options, integrationType: "script" }), + onClick: () => + setOptions((prev) => ({ ...prev, integrationType: "script" })), isActive: options.integrationType === "script", }, { name: "React", - onClick: () => - setOptions({ ...options, integrationType: "component" }), + onClick: () => + setOptions((prev) => ({ ...prev, integrationType: "component" })), isActive: options.integrationType === "component", },apps/playground-web/src/components/ui/tab-buttons.tsx (2)
5-7: Avoid deep relative imports to sibling app directories.These imports reach into the
portalapp's source code, creating tight coupling between apps. Consider:
- Moving shared UI components to a shared package
- Or importing from
@/components/ui/*if these components exist in playground-web#!/bin/bash # Check if these components exist locally in playground-web fd -t f "button.tsx" apps/playground-web/src/components/ui/ fd -t f "ScrollShadow.tsx" apps/playground-web/src/components/ui/ fd -t f "tooltip.tsx" apps/playground-web/src/components/ui/
131-135: The 100ms delay in ResizeObserver may cause visible lag.The arbitrary
setTimeout(..., 100)delay before updating the underline position could cause a noticeable visual delay during resize. Consider removing the delay or reducing it significantly.resizeObserver = new ResizeObserver(() => { - setTimeout(() => { - update(); - }, 100); + update(); });If debouncing is needed for performance, consider using
requestAnimationFrameinstead for smoother visual updates.apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx (1)
103-122: Token amounts documentation is clear and follows existing patterns.The new section with practical examples effectively demonstrates how to use
inputCurrencyAmountandoutputCurrencyAmount. The structure is consistent with other sections in the document.Consider adding a brief note about the expected amount format for completeness:
- Are decimal values supported (e.g.,
0.5)?- What units are expected (token units, not wei/smallest unit)?
- Are there any minimum/maximum limits?
This would help developers avoid common mistakes when setting amounts.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (25)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx(1 hunks)apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx(2 hunks)apps/dashboard/src/app/bridge/widget/page.tsx(3 hunks)apps/playground-web/src/app/ai/components/ChatPageContent.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/types.ts(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/page.tsx(1 hunks)apps/playground-web/src/app/bridge/page.tsx(2 hunks)apps/playground-web/src/app/data/pages-metadata.ts(2 hunks)apps/playground-web/src/app/navLinks.ts(1 hunks)apps/playground-web/src/app/transactions/users/page.tsx(2 hunks)apps/playground-web/src/app/x402/components/X402LeftSection.tsx(1 hunks)apps/playground-web/src/components/blocks/FeatureCard.tsx(1 hunks)apps/playground-web/src/components/ui/tab-buttons.tsx(1 hunks)apps/playground-web/src/hooks/chains.ts(1 hunks)apps/playground-web/src/icons/PayIcon.tsx(0 hunks)apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx(3 hunks)packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx(8 hunks)packages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsx(1 hunks)packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- apps/playground-web/src/icons/PayIcon.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
- apps/playground-web/src/hooks/chains.ts
- apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts
- apps/playground-web/src/app/ai/components/ChatPageContent.tsx
- apps/playground-web/src/app/bridge/bridge-widget/page.tsx
- apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx
- apps/playground-web/src/app/navLinks.ts
🧰 Additional context used
📓 Path-based instructions (15)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes in TypeScript
Avoidanyandunknownin TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.) in TypeScript
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/playground-web/src/app/transactions/users/page.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxapps/playground-web/src/app/data/pages-metadata.tspackages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsxapps/playground-web/src/app/x402/components/X402LeftSection.tsxapps/dashboard/src/app/bridge/widget/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxapps/playground-web/src/components/ui/tab-buttons.tsxapps/playground-web/src/components/blocks/FeatureCard.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/playground-web/src/app/bridge/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/types.tsapps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Usecn()from@/lib/utilsfor conditional Tailwind class merging
Use design system tokens for styling (backgrounds:bg-card, borders:border-border, muted text:text-muted-foreground)
ExposeclassNameprop on root element for component overrides
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/transactions/users/page.tsxapps/playground-web/src/app/data/pages-metadata.tsapps/playground-web/src/app/x402/components/X402LeftSection.tsxapps/dashboard/src/app/bridge/widget/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxapps/playground-web/src/components/ui/tab-buttons.tsxapps/playground-web/src/components/blocks/FeatureCard.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/playground-web/src/app/bridge/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/types.tsapps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx
apps/dashboard/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/dashboard/src/**/*.{ts,tsx}: UseNavLinkfor internal navigation with automatic active states in dashboard
Start server component files withimport "server-only";in Next.js
Read cookies/headers withnext/headersin server components
Access server-only environment variables in server components
Perform heavy data fetching in server components
Implement redirect logic withredirect()fromnext/navigationin server components
Begin client component files with'use client';directive in Next.js
Handle interactive UI with React hooks (useState,useEffect, React Query, wallet hooks) in client components
Access browser APIs (localStorage,window,IntersectionObserver) in client components
Support fast transitions with prefetched data in client components
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader for API calls – never embed tokens in URLs
Return typed results (Project[],User[]) from server-side data fetches – avoidany
Wrap client-side API calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysin React Query for cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components – only use analytics client-side
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/widget/page.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx
apps/dashboard/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
apps/dashboard/**/*.{ts,tsx}: Always import from the central UI library under@/components/ui/*for reusable core UI components likeButton,Input,Select,Tabs,Card,Sidebar,Separator,Badge
UseNavLinkfrom@/components/ui/NavLinkfor internal navigation to ensure active states are handled automatically
For notices and skeletons, rely onAnnouncementBanner,GenericLoadingPage, andEmptyStateCardcomponents
Import icons fromlucide-reactor the project-specific…/iconsexports; never embed raw SVG
Keep components pure; fetch data outside using server components or hooks and pass it down via props
Use Tailwind CSS as the styling system; avoid inline styles or CSS modules
Merge class names withcnfrom@/lib/utilsto keep conditional logic readable
Stick to design tokens: usebg-card,border-border,text-muted-foregroundand other Tailwind variables instead of hard-coded colors
Use spacing utilities (px-*,py-*,gap-*) instead of custom margins
Follow mobile-first responsive design with Tailwind helpers (max-sm,md,lg,xl)
Never hard-code colors; always use Tailwind variables
Combine class names viacn, and exposeclassNameprop if useful in components
Use React Query (@tanstack/react-query) for all client-side data fetching with typed hooks
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/widget/page.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx
apps/dashboard/**/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
Add
classNameprop to the root element of every component to allow external overrides
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx
**/*.{js,jsx,ts,tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Biome governs formatting and linting; its rules live in biome.json. Run
pnpm fix&pnpm lintbefore committing, ensure there are no linting errors
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/playground-web/src/app/transactions/users/page.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxapps/playground-web/src/app/data/pages-metadata.tspackages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsxapps/playground-web/src/app/x402/components/X402LeftSection.tsxapps/dashboard/src/app/bridge/widget/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxapps/playground-web/src/components/ui/tab-buttons.tsxapps/playground-web/src/components/blocks/FeatureCard.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/playground-web/src/app/bridge/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/types.tsapps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx
apps/{dashboard,playground}/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{tsx,ts}: Import UI primitives from @/components/ui/_ (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in Dashboard and Playground apps
Use NavLink for internal navigation so active states are handled automatically
Use Tailwind CSS for styling – no inline styles or CSS modules
Merge class names with cn() from @/lib/utils to keep conditional logic readable
Stick to design tokens for styling: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
Server Components: Read cookies/headers with next/headers, access server-only environment variables or secrets, perform heavy data fetching, implement redirect logic with redirect() from next/navigation, and start files with import 'server-only'; to prevent client bundling
Client Components: Begin files with 'use client'; before imports, handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks), access browser APIs (localStorage, window, IntersectionObserver, etc.), and support fast transitions with client-side data prefetching
For client-side data fetching: Wrap calls in React Query (@tanstack/react-query), use descriptive and stable queryKeys for cache hits, configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s), and keep tokens secret by calling internal API routes or server actions
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/widget/page.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}: Group feature-specific components under feature/components/_ and expose a barrel index.ts when necessary
Expose a className prop on the root element of every component for styling overrides
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: For server-side data fetching: Always call getAuthToken() to retrieve the JWT from cookies and inject the token as an Authorization: Bearer header – never embed it in the URL. Return typed results (Project[], User[], …) – avoid any
Never import posthog-js in server components; analytics reporting is client-side only
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/widget/page.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Lazy-import optional features; avoid top-level side-effects
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/playground-web/src/app/transactions/users/page.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxapps/playground-web/src/app/data/pages-metadata.tspackages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsxapps/playground-web/src/app/x402/components/X402LeftSection.tsxapps/dashboard/src/app/bridge/widget/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxapps/playground-web/src/components/ui/tab-buttons.tsxapps/playground-web/src/components/blocks/FeatureCard.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/playground-web/src/app/bridge/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/types.tsapps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx
packages/thirdweb/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
packages/thirdweb/src/**/*.{ts,tsx}: Comment only ambiguous logic in SDK code; avoid restating TypeScript in prose
Load heavy dependencies inside async paths to keep initial bundle lean (e.g.const { jsPDF } = await import("jspdf");)Lazy-load heavy dependencies inside async paths to keep the initial bundle lean (e.g., const { jsPDF } = await import('jspdf');)
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxpackages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsx
**/*.stories.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
Add Storybook stories (
*.stories.tsx) alongside new UI components for documentation
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
**/*.stories.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
For new UI components, add Storybook stories (*.stories.tsx) alongside the code
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.test.{ts,tsx}: Place tests alongside code:foo.ts↔foo.test.tsin the same directory
Use real function invocations with stub data in tests; avoid brittle mocks
Use Mock Service Worker (MSW) for fetch/HTTP call interception in tests
Keep tests deterministic and side-effect free
Use predefined test accounts fromtest/src/test-wallets.tsin tests
UseFORKED_ETHEREUM_CHAINfor mainnet interactions andANVIL_CHAINfor isolated tests
**/*.test.{ts,tsx}: Co-locate tests with source files using the pattern foo.ts ↔ foo.test.ts
Use real function invocations with stub data in tests; avoid brittle mocks
For network interactions in tests, use Mock Service Worker (MSW) to intercept fetch/HTTP calls, mocking only scenarios that are hard to reproduce
Keep tests deterministic and side-effect free; Vitest is pre-configured
Files:
packages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsx
apps/dashboard/**/page.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
Use the
containerclass with amax-w-7xlcap for consistent page width
Files:
apps/dashboard/src/app/bridge/widget/page.tsx
🧬 Code graph analysis (6)
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (2)
packages/thirdweb/src/script-exports/bridge-widget-script.tsx (1)
BridgeWidgetScript(69-79)packages/thirdweb/src/stories/utils.tsx (1)
storyClient(14-16)
packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx (2)
packages/thirdweb/src/exports/react.ts (2)
ConnectButton_connectModalOptions(16-16)SiweAuthOptions(12-12)packages/thirdweb/src/wallets/types.ts (1)
AppMetadata(3-20)
apps/dashboard/src/app/bridge/widget/page.tsx (1)
packages/thirdweb/src/exports/thirdweb.ts (1)
NATIVE_TOKEN_ADDRESS(31-31)
apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx (4)
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
BridgeWidgetPlaygroundOptions(7-28)apps/playground-web/src/components/ui/tab-buttons.tsx (1)
TabButtons(16-96)apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx (1)
LeftSection(20-119)apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (1)
RightSection(13-113)
apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (3)
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
BridgeWidgetPlaygroundOptions(7-28)apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts (1)
buildIframeUrl(5-67)apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx (1)
CodeGen(21-33)
apps/playground-web/src/app/bridge/page.tsx (1)
apps/dashboard/src/@/icons/BridgeIcon.tsx (1)
BringToFrontIcon(1-1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Unit Tests
- GitHub Check: Lint Packages
- GitHub Check: Size
- GitHub Check: Build Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (17)
apps/playground-web/src/app/bridge/page.tsx (1)
1-1: LGTM! Icon replacement aligns with dashboard usage.The change from
PayIcontoBringToFrontIconis consistent with the dashboard codebase, which uses the same icon for bridge functionality. The new icon is semantically more appropriate for bridge/transfer operations.Also applies to: 11-11
apps/playground-web/src/components/blocks/FeatureCard.tsx (1)
16-16: LGTM – Typography refinement applied correctly.The font weight increase from
font-medium(500) tofont-semibold(600) improves visual hierarchy for the card titles and aligns with the PR's UI polish objectives.apps/playground-web/src/app/transactions/users/page.tsx (1)
34-97: LGTM!The refactoring to a self-closing
CodeExampletag with inline props is cleaner and aligns with the PR's goal of simplifying the code-display pattern.apps/dashboard/src/app/bridge/widget/page.tsx (1)
38-42: LGTM: Amount parsing and conversion.The amount parsing uses
onlyNumberto validate numeric inputs and correctly converts them to strings only when defined. The conditional assignment pattern ensuresundefinedvalues remain undefined rather than becoming"undefined".Also applies to: 77-78, 87-90, 97-98
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx (1)
28-28: LGTM: Proper prop threading.The
showThirdwebBrandingprop is correctly added to the component interface and forwarded toBuyAndSwapEmbed, maintaining consistency with the existing prop-forwarding pattern.Also applies to: 38-38
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (2)
104-112: LGTM: BridgeWidget configuration.The migration from separate buy/swap widgets to
BridgeWidgetconsolidates the UI flow effectively. TheconnectOptions,theme, andshowThirdwebBrandingprops are properly configured, and the overall structure aligns well with the PR objectives.Also applies to: 257-259
221-256: LGTM: Swap callback implementation.The swap configuration correctly uses
persistTokenSelectionsandprefillfrom props, and the callbacks properly extract token information from the quote to report analytics events. The logic is cleaner than the buy callbacks since swap quotes have a consistent structure.packages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsx (1)
20-20: Remove this comment—the change is appropriate.The URL is stable and accessible (HTTP 200), and this is an intentional integration test that verifies the MediaRenderer component can actually render a real image. The coding guideline about "stub data" refers to avoiding brittle mocks, not eliminating all external resources. Real function invocations with actual dependencies are appropriate here.
apps/playground-web/src/app/data/pages-metadata.ts (1)
16-16: LGTM!The
SquareIconimport is correctly added and used throughout the bridge feature cards.apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx (1)
20-118: LGTM on the overall LeftSection structure.The component properly separates concerns with collapsible sections for Token Selection and Appearance. Theme handling, color overrides (disabled for iframe), and branding toggle are well implemented.
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
1-28: LGTM!Well-structured type definition that follows coding guidelines by using type aliases and leveraging library types via indexed access (
ThemeOverrides["colors"],SwapWidgetProps["showThirdwebBranding"]). The optional fields are appropriately marked.apps/playground-web/src/components/ui/tab-buttons.tsx (2)
98-148: OveralluseUnderlinehook implementation is solid.The hook properly handles cleanup of event listeners and ResizeObserver. Using
useLayoutEffectis correct for synchronous DOM measurements before paint.
9-14: Remove unusedTabLinktype export.The
TabLinktype is exported but never used within this file or imported elsewhere in the codebase. Delete it.apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (1)
57-93: Both thebuyprop andswap.prefill.buyTokenare intentionally configured to serve different tabs in the BridgeWidget. Thebuyprop configures the Buy tab (rendered viaBuyWidget), whileswap.prefill.buyTokenconfigures the Swap tab (rendered viaSwapWidget). This is the intended design pattern and does not constitute problematic duplication.packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx (1)
418-418: LGTM! connectOptions correctly propagated to child widgets.The connectOptions configuration is properly passed through to both SwapWidget and BuyWidget, enabling consistent wallet connection behavior across tabs.
Also applies to: 446-446
apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx (2)
175-180: Documentation ofshowThirdwebBrandingparameter is accurate and implementation-verified.The parameter name correctly matches the bridge widget implementation and is properly documented. Default behavior displays thirdweb branding, which can be hidden by setting
showThirdwebBranding=falsein the iframe URL.
58-65: Parameter names are correctly documented.The documented parameters
inputCurrencyAmountandoutputCurrencyAmountmatch the actual implementation in the bridge widget code (confirmed inapps/dashboard/src/app/bridge/widget/page.tsxandapps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts). The documentation accurately reflects the query parameters used to prefill token amounts in the iframe widget.
packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx (1)
128-128: Capitalize the sentence.The sentence should start with "If" (capital I) rather than "if".
Apply this diff:
-if the custom default token selection is specified using the query params mentioned above, it overrides the last used tokens to ensure that configuration specified in query params is always respected. +If the custom default token selection is specified using the query params mentioned above, it overrides the last used tokens to ensure that configuration specified in query params is always respected.
♻️ Duplicate comments (4)
apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx (1)
28-37: UseresolvedThemefor accurate theme detection.The
themevalue fromuseTheme()can be"system", which doesn't accurately reflect the actual rendered theme. UseresolvedThemeinstead to get the computed theme value.Apply this diff:
export function BridgeWidgetPlayground() { - const { theme } = useTheme(); + const { resolvedTheme } = useTheme(); const [options, setOptions] = useState<BridgeWidgetPlaygroundOptions>(defaultOptions); // change theme on global theme change useEffect(() => { setOptions((prev) => ({ ...prev, theme: { ...prev.theme, - type: theme === "dark" ? "dark" : "light", + type: resolvedTheme === "dark" ? "dark" : "light", }, })); - }, [theme]); + }, [resolvedTheme]);apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx (1)
35-214: Add explicit return type annotations to helper functions.Per coding guidelines, all TypeScript functions must have explicit return types. The functions
getCode,getCode_Script,getCode_ReactComponent, andgetCode_Iframeshould be annotated with: string.Based on coding guidelines: "Write idiomatic TypeScript with explicit function declarations and return types."
Apply this diff:
-function getCode(options: BridgeWidgetPlaygroundOptions) { +function getCode(options: BridgeWidgetPlaygroundOptions): string { if (options.integrationType === "script") { return getCode_Script(options); } ... } -function getCode_Script(options: BridgeWidgetPlaygroundOptions) { +function getCode_Script(options: BridgeWidgetPlaygroundOptions): string { const widgetOptions: Record<string, unknown> = { clientId: "your-thirdweb-client-id", }; ... } -function getCode_ReactComponent(options: BridgeWidgetPlaygroundOptions) { +function getCode_ReactComponent(options: BridgeWidgetPlaygroundOptions): string { const imports = { thirdweb: ["createThirdwebClient"] as string[], "thirdweb/react": ["BridgeWidget"] as string[], }; ... } -function getCode_Iframe(options: BridgeWidgetPlaygroundOptions) { +function getCode_Iframe(options: BridgeWidgetPlaygroundOptions): string { const src = buildIframeUrl(options); ... }apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx (1)
174-185: Token selection clears the amount field.When selecting a new token, the current
amountvalue is lost because the update doesn't spread the existing prefill data. This differs from the chain selection logic (lines 148-159) which preserves other fields.Apply this diff:
onChange={(token) => { setOptions((v) => ({ ...v, prefill: { ...v.prefill, [props.type]: { + ...v.prefill?.[props.type], chainId: token.chainId, tokenAddress: token.address, }, }, })); }}packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx (1)
202-311: ExtractconnectOptionstype definition to a separate types file.As noted in a previous review, this 110-line inline type definition should be extracted to maintain single-responsibility and follow the pattern established by
SwapWidgetConnectOptionsinswap-widget/types.ts.Based on coding guidelines requiring reuse of shared types from local
types.tsbarrels.
🧹 Nitpick comments (2)
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (1)
46-51: Extract shared styling to reduce duplication.The wrapper div styling is identical to the
Variantcomponent's styling (lines 74-79). Consider extracting this to a shared constant or reusing theVariantcomponent if appropriate.Apply this diff to extract the shared styles:
+const wrapperStyle: React.CSSProperties = { + display: "flex", + flexDirection: "column", + gap: "40px", + alignItems: "center", +}; + export function CustomTheme() { return ( - <div - style={{ - display: "flex", - flexDirection: "column", - gap: "40px", - alignItems: "center", - }} - > + <div style={wrapperStyle}> <BridgeWidgetScript clientId={storyClient.clientId} buy={{ chainId: 8453, amount: "0.1" }} theme={{ type: "light", colors: { modalBg: "#FFFFF0", tertiaryBg: "#DBE4C9", borderColor: "#8AA624", secondaryText: "#3E3F29", accentText: "#E43636", }, }} /> </div> ); } function Variant(props: BridgeWidgetScriptProps) { - return ( - <div - style={{ - display: "flex", - flexDirection: "column", - gap: "40px", - alignItems: "center", - }} - > + return ( + <div style={wrapperStyle}> <BridgeWidgetScript {...props} theme="dark" /> <BridgeWidgetScript {...props} theme="light" /> </div> ); }packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx (1)
471-476: Consider extracting active/inactive colors for clarity.The ternary expressions for color and border work correctly but could be more readable with extracted variables.
function TabButton(props: { isActive: boolean; onClick: () => void; children: React.ReactNode; }) { const theme = useCustomTheme(); + const textColor = props.isActive + ? theme.colors.primaryText + : theme.colors.secondaryText; + const borderColor = props.isActive + ? theme.colors.secondaryText + : theme.colors.borderColor; + return ( <Button variant="secondary" onClick={props.onClick} style={{ borderRadius: radius.full, fontSize: fontSize.sm, fontWeight: 500, paddingInline: spacing.md, paddingBlock: 0, height: "36px", - color: props.isActive - ? theme.colors.primaryText - : theme.colors.secondaryText, - border: `1px solid ${ - props.isActive ? theme.colors.secondaryText : theme.colors.borderColor - }`, + color: textColor, + border: `1px solid ${borderColor}`, }} > {props.children} </Button> ); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (25)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx(1 hunks)apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx(2 hunks)apps/dashboard/src/app/bridge/widget/page.tsx(3 hunks)apps/playground-web/src/app/ai/components/ChatPageContent.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/types.ts(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/page.tsx(1 hunks)apps/playground-web/src/app/bridge/page.tsx(2 hunks)apps/playground-web/src/app/data/pages-metadata.ts(2 hunks)apps/playground-web/src/app/navLinks.ts(1 hunks)apps/playground-web/src/app/transactions/users/page.tsx(2 hunks)apps/playground-web/src/app/x402/components/X402LeftSection.tsx(1 hunks)apps/playground-web/src/components/blocks/FeatureCard.tsx(1 hunks)apps/playground-web/src/components/ui/tab-buttons.tsx(1 hunks)apps/playground-web/src/hooks/chains.ts(1 hunks)apps/playground-web/src/icons/PayIcon.tsx(0 hunks)apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx(3 hunks)packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx(8 hunks)packages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsx(2 hunks)packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- apps/playground-web/src/icons/PayIcon.tsx
✅ Files skipped from review due to trivial changes (2)
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
- apps/playground-web/src/components/blocks/FeatureCard.tsx
🚧 Files skipped from review as they are similar to previous changes (11)
- apps/playground-web/src/app/ai/components/ChatPageContent.tsx
- packages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsx
- apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx
- apps/playground-web/src/app/x402/components/X402LeftSection.tsx
- apps/playground-web/src/hooks/chains.ts
- apps/playground-web/src/components/ui/tab-buttons.tsx
- apps/dashboard/src/app/bridge/widget/page.tsx
- apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx
- apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts
- apps/playground-web/src/app/navLinks.ts
- apps/playground-web/src/app/transactions/users/page.tsx
🧰 Additional context used
📓 Path-based instructions (13)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes in TypeScript
Avoidanyandunknownin TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.) in TypeScript
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/bridge/bridge-widget/components/types.tsapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxapps/playground-web/src/app/bridge/bridge-widget/components/code.tsxapps/playground-web/src/app/bridge/page.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxapps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsxapps/playground-web/src/app/bridge/bridge-widget/page.tsxapps/playground-web/src/app/data/pages-metadata.ts
packages/thirdweb/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
packages/thirdweb/src/**/*.{ts,tsx}: Comment only ambiguous logic in SDK code; avoid restating TypeScript in prose
Load heavy dependencies inside async paths to keep initial bundle lean (e.g.const { jsPDF } = await import("jspdf");)Lazy-load heavy dependencies inside async paths to keep the initial bundle lean (e.g., const { jsPDF } = await import('jspdf');)
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx
**/*.stories.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
Add Storybook stories (
*.stories.tsx) alongside new UI components for documentation
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
**/*.{js,jsx,ts,tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Biome governs formatting and linting; its rules live in biome.json. Run
pnpm fix&pnpm lintbefore committing, ensure there are no linting errors
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/bridge/bridge-widget/components/types.tsapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxapps/playground-web/src/app/bridge/bridge-widget/components/code.tsxapps/playground-web/src/app/bridge/page.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxapps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsxapps/playground-web/src/app/bridge/bridge-widget/page.tsxapps/playground-web/src/app/data/pages-metadata.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Lazy-import optional features; avoid top-level side-effects
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/bridge/bridge-widget/components/types.tsapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxapps/playground-web/src/app/bridge/bridge-widget/components/code.tsxapps/playground-web/src/app/bridge/page.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxapps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsxapps/playground-web/src/app/bridge/bridge-widget/page.tsxapps/playground-web/src/app/data/pages-metadata.ts
**/*.stories.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
For new UI components, add Storybook stories (*.stories.tsx) alongside the code
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Usecn()from@/lib/utilsfor conditional Tailwind class merging
Use design system tokens for styling (backgrounds:bg-card, borders:border-border, muted text:text-muted-foreground)
ExposeclassNameprop on root element for component overrides
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/bridge/bridge-widget/components/types.tsapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxapps/playground-web/src/app/bridge/bridge-widget/components/code.tsxapps/playground-web/src/app/bridge/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsxapps/playground-web/src/app/bridge/bridge-widget/page.tsxapps/playground-web/src/app/data/pages-metadata.ts
apps/dashboard/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/dashboard/src/**/*.{ts,tsx}: UseNavLinkfor internal navigation with automatic active states in dashboard
Start server component files withimport "server-only";in Next.js
Read cookies/headers withnext/headersin server components
Access server-only environment variables in server components
Perform heavy data fetching in server components
Implement redirect logic withredirect()fromnext/navigationin server components
Begin client component files with'use client';directive in Next.js
Handle interactive UI with React hooks (useState,useEffect, React Query, wallet hooks) in client components
Access browser APIs (localStorage,window,IntersectionObserver) in client components
Support fast transitions with prefetched data in client components
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader for API calls – never embed tokens in URLs
Return typed results (Project[],User[]) from server-side data fetches – avoidany
Wrap client-side API calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysin React Query for cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components – only use analytics client-side
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/dashboard/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
apps/dashboard/**/*.{ts,tsx}: Always import from the central UI library under@/components/ui/*for reusable core UI components likeButton,Input,Select,Tabs,Card,Sidebar,Separator,Badge
UseNavLinkfrom@/components/ui/NavLinkfor internal navigation to ensure active states are handled automatically
For notices and skeletons, rely onAnnouncementBanner,GenericLoadingPage, andEmptyStateCardcomponents
Import icons fromlucide-reactor the project-specific…/iconsexports; never embed raw SVG
Keep components pure; fetch data outside using server components or hooks and pass it down via props
Use Tailwind CSS as the styling system; avoid inline styles or CSS modules
Merge class names withcnfrom@/lib/utilsto keep conditional logic readable
Stick to design tokens: usebg-card,border-border,text-muted-foregroundand other Tailwind variables instead of hard-coded colors
Use spacing utilities (px-*,py-*,gap-*) instead of custom margins
Follow mobile-first responsive design with Tailwind helpers (max-sm,md,lg,xl)
Never hard-code colors; always use Tailwind variables
Combine class names viacn, and exposeclassNameprop if useful in components
Use React Query (@tanstack/react-query) for all client-side data fetching with typed hooks
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/dashboard/**/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
Add
classNameprop to the root element of every component to allow external overrides
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{tsx,ts}: Import UI primitives from @/components/ui/_ (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in Dashboard and Playground apps
Use NavLink for internal navigation so active states are handled automatically
Use Tailwind CSS for styling – no inline styles or CSS modules
Merge class names with cn() from @/lib/utils to keep conditional logic readable
Stick to design tokens for styling: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
Server Components: Read cookies/headers with next/headers, access server-only environment variables or secrets, perform heavy data fetching, implement redirect logic with redirect() from next/navigation, and start files with import 'server-only'; to prevent client bundling
Client Components: Begin files with 'use client'; before imports, handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks), access browser APIs (localStorage, window, IntersectionObserver, etc.), and support fast transitions with client-side data prefetching
For client-side data fetching: Wrap calls in React Query (@tanstack/react-query), use descriptive and stable queryKeys for cache hits, configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s), and keep tokens secret by calling internal API routes or server actions
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}: Group feature-specific components under feature/components/_ and expose a barrel index.ts when necessary
Expose a className prop on the root element of every component for styling overrides
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: For server-side data fetching: Always call getAuthToken() to retrieve the JWT from cookies and inject the token as an Authorization: Bearer header – never embed it in the URL. Return typed results (Project[], User[], …) – avoid any
Never import posthog-js in server components; analytics reporting is client-side only
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
🧬 Code graph analysis (6)
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (2)
packages/thirdweb/src/script-exports/bridge-widget-script.tsx (1)
BridgeWidgetScript(69-79)packages/thirdweb/src/stories/utils.tsx (1)
storyClient(14-16)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (3)
packages/thirdweb/src/exports/react.ts (1)
BridgeWidget(148-148)apps/dashboard/src/@/constants/connect.ts (1)
appMetadata(1-5)apps/dashboard/src/@/analytics/report.ts (9)
reportTokenBuyFailed(264-266)reportAssetBuyFailed(342-350)reportTokenBuyCancelled(276-278)reportAssetBuyCancelled(360-367)reportTokenBuySuccessful(252-254)reportAssetBuySuccessful(221-228)reportTokenSwapFailed(314-320)reportTokenSwapSuccessful(288-290)reportTokenSwapCancelled(330-332)
apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx (4)
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
BridgeWidgetPlaygroundOptions(7-28)apps/playground-web/src/components/ui/tab-buttons.tsx (1)
TabButtons(16-96)apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx (1)
LeftSection(20-119)apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (1)
RightSection(13-113)
apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx (3)
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
BridgeWidgetPlaygroundOptions(7-28)apps/playground-web/src/lib/code-gen.ts (3)
quotes(17-19)stringifyImports(21-29)stringifyProps(1-15)apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts (1)
buildIframeUrl(5-67)
apps/playground-web/src/app/bridge/page.tsx (1)
apps/dashboard/src/@/icons/BridgeIcon.tsx (1)
BringToFrontIcon(1-1)
apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx (6)
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
BridgeWidgetPlaygroundOptions(7-28)apps/playground-web/src/app/wallets/sign-in/components/CollapsibleSection.tsx (1)
CollapsibleSection(4-33)packages/thirdweb/src/react/web/ui/components/formElements.tsx (1)
Label(20-28)apps/playground-web/src/app/wallets/sign-in/components/ColorFormGroup.tsx (1)
ColorFormGroup(9-111)packages/thirdweb/src/exports/thirdweb.ts (1)
NATIVE_TOKEN_ADDRESS(31-31)apps/playground-web/src/app/bridge/swap-widget/components/left-section.tsx (1)
LeftSection(20-115)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Unit Tests
- GitHub Check: Size
- GitHub Check: Lint Packages
- GitHub Check: Build Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (16)
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (1)
45-67: Verify the story behavior change is intentional.Unlike other stories (
BasicUsage,CurrencySet,NoThirdwebBranding) that use theVarianthelper to display both dark and light themes side by side,CustomThemenow renders only a single light theme variant. Confirm this is the desired behavior for showcasing custom theme colors.apps/playground-web/src/app/data/pages-metadata.ts (3)
16-16: LGTM!The SquareIcon import is correctly added and used consistently throughout the bridge feature cards below.
120-152: Well-structured Bridge Widget metadata.The new Bridge Widget entry and updated descriptions effectively communicate the fiat onramp and cross-chain capabilities. The icon standardization to
SquareIconprovides good visual consistency across the widget family.
118-160: No action needed. The Transaction Button's use ofRectangleHorizontalIconwhile other entries useSquareIconappears to be an intentional design pattern. InwalletsFeatureCards, the "Connect Button" entry similarly usesRectangleHorizontalIcon, establishing a consistent visual distinction between button-type and widget-type components. All widgets useSquareIconwhile buttons useRectangleHorizontalIcon.apps/playground-web/src/app/bridge/page.tsx (1)
1-14: LGTM! Icon replacement aligns with Bridge Widget branding.The change from PayIcon to BringToFrontIcon is consistent with the broader Bridge Widget playground updates and maintains the proper visual identity for the bridge functionality.
apps/playground-web/src/app/bridge/bridge-widget/page.tsx (1)
1-33: LGTM! Well-structured Next.js page component.The page follows Next.js App Router conventions with proper metadata, provider wrapping, and clean component composition. The documentation link includes proper UTM tracking.
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
7-28: LGTM! Clean and well-structured type definition.The
BridgeWidgetPlaygroundOptionstype is well-organized with proper use of optional fields and references to upstream types fromthirdweb/react. The structure clearly supports the playground's integration modes and configuration options.apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (3)
1-84: LGTM! Component setup is clean.The client directive, imports, props typing, and mounted-state tracking for analytics are all properly implemented.
221-256: LGTM! Swap callback implementations are clean.The swap flow callbacks properly extract quote data and invoke analytics reporting without unnecessary duplication.
67-67: LGTM! Branding prop properly wired.The
showThirdwebBrandingprop is correctly typed and passed through toBridgeWidget.Also applies to: 258-258
packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx (2)
35-36: LGTM! Styling props properly exposed.Adding
classNameandstyleprops aligns with the coding guideline to "exposeclassNameprop on root element for component overrides." Both are correctly forwarded toEmbedContainer.Also applies to: 380-384
418-418: LGTM! Props properly propagated to child widgets.The
connectOptionsare correctly passed through to bothSwapWidgetandBuyWidget, ensuring consistent wallet connection configuration across tabs.Also applies to: 446-446
apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx (4)
58-58: LGTM! Clearer, more concise heading.The simplified heading improves readability while the description below still conveys the functionality clearly.
103-122: Well-structured documentation—verify parameter dependencies.The Token amounts section is clear and follows the established documentation pattern. However, both examples include currency/chain parameters alongside the amount parameters. Confirm whether
inputCurrencyAmount/outputCurrencyAmountrequire the correspondinginputCurrency/outputCurrencyand chain parameters, or if they can function independently.
64-65: Parameter namesinputCurrencyAmountandoutputCurrencyAmountare correctly implemented and supported by the Bridge widget's query parameter handling.
175-180: Parameter name appears correct but iframe implementation cannot be fully verified.The
showThirdwebBrandingparameter name is correctly documented and exists in the Bridge widget SDK (BridgeWidgetScriptProps), following the same naming convention as other documented parameters likecurrency. However, the actual iframe URL handler at thirdweb.com/bridge/widget could not be located in the codebase to definitively confirm it parses this query parameter. The documentation at lines 175-180 is consistent with the SDK implementation, but endpoint verification requires access to the actual bridge widget route handler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsx (1)
35-40: Remove or fix the two skipped tests disabling core MediaRenderer functionality.Two tests are skipped without explanation at lines 28 and 35, disabling validation of core functionality (image rendering and error handling). Line 28's test also has a code smell—it uses
setTimeoutinstead of proper async/await handling withwaitFor.Either:
- Fix the tests and re-enable them
- Remove them entirely if permanently broken
- If needed temporarily, add a TODO comment explaining why and when to re-enable
♻️ Duplicate comments (2)
apps/playground-web/src/app/transactions/users/page.tsx (1)
32-32: Add explicit return type annotation.The function still lacks an explicit return type annotation as required by the coding guidelines for TypeScript files.
Apply this diff:
-function UserTransactions() { +function UserTransactions(): JSX.Element {apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
119-217: Duplicated quote extraction logic across callbacks.The chainId and tokenAddress extraction from the quote is repeated identically in
onError,onCancel, andonSuccess. This was flagged in a previous review.
🧹 Nitpick comments (6)
apps/playground-web/src/hooks/chains.ts (3)
35-48: Consider adding a comment to clarify sorting intent.The sorting logic is correct but non-trivial—it places chains with numeric names (e.g., "1inch") after alphabetic names. A brief comment would improve maintainability.
Apply this diff to add a clarifying comment:
const data = json.data as BridgeChain[]; + // Sort chains: alphabetic names first, numeric names last; within each group sort alphabetically return data.sort((a, b) => {
35-48: Add defensive null checks for chain names in localeCompare.Line 47 calls
a.name.localeCompare(b.name)without verifying thatnameis defined. While the API contract likely guarantees this, defensive coding would prevent potential runtime errors if the shape ever changes.Apply this diff to add null safety:
return data.sort((a, b) => { const aStartsWithNumber = a.name[0]?.match(/^\d/); const bStartsWithNumber = b.name[0]?.match(/^\d/); if (aStartsWithNumber && !bStartsWithNumber) { return 1; } if (!aStartsWithNumber && bStartsWithNumber) { return -1; } - return a.name.localeCompare(b.name); + return (a.name ?? "").localeCompare(b.name ?? ""); });
7-16: Consider reusing the shared BridgeChain type if accessible.A
BridgeChaintype is exported frompackages/thirdweb/src/bridge/types/Chain.ts. If the playground app has access to that package, importing the shared type would reduce duplication and keep the shape in sync. If the separation is intentional (to avoid package dependencies), the current approach is fine.Based on coding guidelines: "Re-use shared types from @/types or local types.ts barrels."
apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (3)
103-105: Avoid inline styles; use Tailwind classes instead.Per coding guidelines, dashboard and playground apps should use Tailwind CSS only with no inline styles. The
border: "0"can be replaced with Tailwind'sborder-0class.<iframe src={buildIframeUrl(props.options, "preview")} height="750px" width="100%" title="Bridge Widget" - className="fade-in-0 duration-500 animate-in rounded-xl" - style={{ - border: "0", - }} + className="fade-in-0 border-0 duration-500 animate-in rounded-xl" />
115-143: Consider reusing or renaming to avoid confusion with sharedTabButtons.This PR also introduces a
TabButtonscomponent in@/components/ui/tab-buttons.tsxwith different styling and features (underline animation, scroll shadow, icons). Having two components with the same name in the codebase may cause confusion.Consider either:
- Importing and styling the shared
TabButtonsfrom@/components/ui/tab-buttons.tsx- Renaming this local component (e.g.,
SegmentedTabsorPillTabs) to distinguish it
16-22: Simplify state setter usage.The
setPreviewTabwrapper adds no logic beyond calling_setPreviewTab. Consider using the setter directly or destructuring with the desired name.- const [previewTab, _setPreviewTab] = useState<Tab>(() => { - return "ui"; - }); - - function setPreviewTab(tab: "ui" | "code") { - _setPreviewTab(tab); - } + const [previewTab, setPreviewTab] = useState<Tab>("ui");
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (25)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx(1 hunks)apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx(2 hunks)apps/dashboard/src/app/bridge/widget/page.tsx(3 hunks)apps/playground-web/src/app/ai/components/ChatPageContent.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/types.ts(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/page.tsx(1 hunks)apps/playground-web/src/app/bridge/page.tsx(2 hunks)apps/playground-web/src/app/data/pages-metadata.ts(2 hunks)apps/playground-web/src/app/navLinks.ts(1 hunks)apps/playground-web/src/app/transactions/users/page.tsx(2 hunks)apps/playground-web/src/app/x402/components/X402LeftSection.tsx(1 hunks)apps/playground-web/src/components/blocks/FeatureCard.tsx(1 hunks)apps/playground-web/src/components/ui/tab-buttons.tsx(1 hunks)apps/playground-web/src/hooks/chains.ts(1 hunks)apps/playground-web/src/icons/PayIcon.tsx(0 hunks)apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx(3 hunks)packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx(8 hunks)packages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsx(2 hunks)packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- apps/playground-web/src/icons/PayIcon.tsx
🚧 Files skipped from review as they are similar to previous changes (13)
- apps/playground-web/src/app/x402/components/X402LeftSection.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
- apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx
- apps/playground-web/src/app/bridge/bridge-widget/page.tsx
- apps/playground-web/src/app/navLinks.ts
- apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx
- apps/dashboard/src/app/bridge/widget/page.tsx
- apps/playground-web/src/app/bridge/page.tsx
- apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx
- apps/playground-web/src/app/bridge/bridge-widget/components/types.ts
- apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts
- packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx
- apps/playground-web/src/components/blocks/FeatureCard.tsx
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes in TypeScript
Avoidanyandunknownin TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.) in TypeScript
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose
Files:
apps/playground-web/src/app/ai/components/ChatPageContent.tsxpackages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/playground-web/src/app/data/pages-metadata.tsapps/playground-web/src/hooks/chains.tsapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/playground-web/src/components/ui/tab-buttons.tsxapps/playground-web/src/app/transactions/users/page.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Usecn()from@/lib/utilsfor conditional Tailwind class merging
Use design system tokens for styling (backgrounds:bg-card, borders:border-border, muted text:text-muted-foreground)
ExposeclassNameprop on root element for component overrides
Files:
apps/playground-web/src/app/ai/components/ChatPageContent.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/playground-web/src/app/data/pages-metadata.tsapps/playground-web/src/hooks/chains.tsapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/playground-web/src/components/ui/tab-buttons.tsxapps/playground-web/src/app/transactions/users/page.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
**/*.{js,jsx,ts,tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Biome governs formatting and linting; its rules live in biome.json. Run
pnpm fix&pnpm lintbefore committing, ensure there are no linting errors
Files:
apps/playground-web/src/app/ai/components/ChatPageContent.tsxpackages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/playground-web/src/app/data/pages-metadata.tsapps/playground-web/src/hooks/chains.tsapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/playground-web/src/components/ui/tab-buttons.tsxapps/playground-web/src/app/transactions/users/page.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Lazy-import optional features; avoid top-level side-effects
Files:
apps/playground-web/src/app/ai/components/ChatPageContent.tsxpackages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/playground-web/src/app/data/pages-metadata.tsapps/playground-web/src/hooks/chains.tsapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/playground-web/src/components/ui/tab-buttons.tsxapps/playground-web/src/app/transactions/users/page.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.test.{ts,tsx}: Place tests alongside code:foo.ts↔foo.test.tsin the same directory
Use real function invocations with stub data in tests; avoid brittle mocks
Use Mock Service Worker (MSW) for fetch/HTTP call interception in tests
Keep tests deterministic and side-effect free
Use predefined test accounts fromtest/src/test-wallets.tsin tests
UseFORKED_ETHEREUM_CHAINfor mainnet interactions andANVIL_CHAINfor isolated tests
**/*.test.{ts,tsx}: Co-locate tests with source files using the pattern foo.ts ↔ foo.test.ts
Use real function invocations with stub data in tests; avoid brittle mocks
For network interactions in tests, use Mock Service Worker (MSW) to intercept fetch/HTTP calls, mocking only scenarios that are hard to reproduce
Keep tests deterministic and side-effect free; Vitest is pre-configured
Files:
packages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsx
packages/thirdweb/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
packages/thirdweb/src/**/*.{ts,tsx}: Comment only ambiguous logic in SDK code; avoid restating TypeScript in prose
Load heavy dependencies inside async paths to keep initial bundle lean (e.g.const { jsPDF } = await import("jspdf");)Lazy-load heavy dependencies inside async paths to keep the initial bundle lean (e.g., const { jsPDF } = await import('jspdf');)
Files:
packages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
apps/dashboard/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/dashboard/src/**/*.{ts,tsx}: UseNavLinkfor internal navigation with automatic active states in dashboard
Start server component files withimport "server-only";in Next.js
Read cookies/headers withnext/headersin server components
Access server-only environment variables in server components
Perform heavy data fetching in server components
Implement redirect logic withredirect()fromnext/navigationin server components
Begin client component files with'use client';directive in Next.js
Handle interactive UI with React hooks (useState,useEffect, React Query, wallet hooks) in client components
Access browser APIs (localStorage,window,IntersectionObserver) in client components
Support fast transitions with prefetched data in client components
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader for API calls – never embed tokens in URLs
Return typed results (Project[],User[]) from server-side data fetches – avoidany
Wrap client-side API calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysin React Query for cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components – only use analytics client-side
Files:
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/dashboard/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
apps/dashboard/**/*.{ts,tsx}: Always import from the central UI library under@/components/ui/*for reusable core UI components likeButton,Input,Select,Tabs,Card,Sidebar,Separator,Badge
UseNavLinkfrom@/components/ui/NavLinkfor internal navigation to ensure active states are handled automatically
For notices and skeletons, rely onAnnouncementBanner,GenericLoadingPage, andEmptyStateCardcomponents
Import icons fromlucide-reactor the project-specific…/iconsexports; never embed raw SVG
Keep components pure; fetch data outside using server components or hooks and pass it down via props
Use Tailwind CSS as the styling system; avoid inline styles or CSS modules
Merge class names withcnfrom@/lib/utilsto keep conditional logic readable
Stick to design tokens: usebg-card,border-border,text-muted-foregroundand other Tailwind variables instead of hard-coded colors
Use spacing utilities (px-*,py-*,gap-*) instead of custom margins
Follow mobile-first responsive design with Tailwind helpers (max-sm,md,lg,xl)
Never hard-code colors; always use Tailwind variables
Combine class names viacn, and exposeclassNameprop if useful in components
Use React Query (@tanstack/react-query) for all client-side data fetching with typed hooks
Files:
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/dashboard/**/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
Add
classNameprop to the root element of every component to allow external overrides
Files:
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{tsx,ts}: Import UI primitives from @/components/ui/_ (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in Dashboard and Playground apps
Use NavLink for internal navigation so active states are handled automatically
Use Tailwind CSS for styling – no inline styles or CSS modules
Merge class names with cn() from @/lib/utils to keep conditional logic readable
Stick to design tokens for styling: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
Server Components: Read cookies/headers with next/headers, access server-only environment variables or secrets, perform heavy data fetching, implement redirect logic with redirect() from next/navigation, and start files with import 'server-only'; to prevent client bundling
Client Components: Begin files with 'use client'; before imports, handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks), access browser APIs (localStorage, window, IntersectionObserver, etc.), and support fast transitions with client-side data prefetching
For client-side data fetching: Wrap calls in React Query (@tanstack/react-query), use descriptive and stable queryKeys for cache hits, configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s), and keep tokens secret by calling internal API routes or server actions
Files:
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}: Group feature-specific components under feature/components/_ and expose a barrel index.ts when necessary
Expose a className prop on the root element of every component for styling overrides
Files:
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: For server-side data fetching: Always call getAuthToken() to retrieve the JWT from cookies and inject the token as an Authorization: Bearer header – never embed it in the URL. Return typed results (Project[], User[], …) – avoid any
Never import posthog-js in server components; analytics reporting is client-side only
Files:
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
**/*.stories.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
Add Storybook stories (
*.stories.tsx) alongside new UI components for documentation
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
**/*.stories.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
For new UI components, add Storybook stories (*.stories.tsx) alongside the code
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
🧬 Code graph analysis (4)
apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (4)
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
BridgeWidgetPlaygroundOptions(7-28)apps/playground-web/src/components/ui/tab-buttons.tsx (1)
TabButtons(16-96)apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts (1)
buildIframeUrl(5-72)apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx (1)
CodeGen(21-33)
apps/playground-web/src/hooks/chains.ts (1)
packages/thirdweb/src/bridge/types/Chain.ts (1)
BridgeChain(42-42)
apps/playground-web/src/app/transactions/users/page.tsx (2)
apps/playground-web/src/components/code/code-example.tsx (1)
CodeExample(17-56)apps/playground-web/src/components/account-abstraction/gateway.tsx (1)
GatewayPreview(137-292)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (3)
packages/thirdweb/src/exports/react.ts (1)
BridgeWidget(148-148)apps/dashboard/src/@/constants/connect.ts (1)
appMetadata(1-5)apps/dashboard/src/@/analytics/report.ts (9)
reportTokenBuyFailed(264-266)reportAssetBuyFailed(342-350)reportTokenBuyCancelled(276-278)reportAssetBuyCancelled(360-367)reportTokenBuySuccessful(252-254)reportAssetBuySuccessful(221-228)reportTokenSwapFailed(314-320)reportTokenSwapSuccessful(288-290)reportTokenSwapCancelled(330-332)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Size
- GitHub Check: Unit Tests
- GitHub Check: Analyze (javascript)
🔇 Additional comments (13)
apps/playground-web/src/app/transactions/users/page.tsx (1)
34-97: LGTM! Clean refactoring.The conversion from multi-line
CodeExamplewith children to a self-closing tag with props improves readability and aligns with the component's interface.packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (1)
43-69: LGTM! Clear custom theme demonstration.The refactoring to directly render
BridgeWidgetScript(rather than using theVarianthelper) is appropriate here sinceCustomThemedemonstrates a single custom theme configuration, whereasVariantis designed to show dark and light side-by-side comparisons. The custom theme object structure withtypeandcolorsclearly showcases the theming API.apps/playground-web/src/app/ai/components/ChatPageContent.tsx (1)
87-87: LGTM!Using
Number.isNaN()is the correct best practice over the globalisNaN()function. SinceNumber(id)is already applied, the behavior is equivalent, but this is more explicit and idiomatic.apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx (3)
58-65: LGTM!The updated token selections documentation clearly lists all available query parameters including the new amount parameters.
103-122: LGTM!The new "Token amounts" section provides clear documentation with practical examples for pre-filling token amounts.
175-180: LGTM!The branding documentation is clear and consistent with the implementation.
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx (1)
28-28: LGTM!Clean prop threading for the
showThirdwebBrandingflag, following existing patterns in the component.Also applies to: 38-38
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (3)
104-112: LGTM!The BridgeWidget configuration with
connectOptionsis well-structured, properly passing wallets and appMetadata.
67-67: LGTM!The
showThirdwebBrandingprop is correctly typed and forwarded to theBridgeWidgetcomponent.Also applies to: 257-258
227-256: Verify swap callback quote parameter is always defined.The swap callbacks (
onError,onSuccess,onCancel) accessquote.intent.*properties directly without null checks. In contrast, the buy callbacks guard against undefined quote by checkingbuyChainIdbefore proceeding.If
quotecan be undefined in swap callbacks (similar to buy callbacks), accessingquote.intent.destinationChainIdwould throw a runtime error.#!/bin/bash # Search for BridgeWidget swap callback type definitions to verify if quote is always defined ast-grep --pattern 'swap: { $$$ onError: $_ $$$ }' # Also search for any swap onError type definitions rg -n --type=ts -C5 'onError.*quote.*swap|swap.*onError'apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (1)
57-93: LGTM!The
BridgeWidgetconfiguration correctly passes theme, prefill data, currency, and branding options. UsingJSON.stringify(props.options.prefill)as a key to force remount on prefill changes is appropriate for this playground use case.apps/playground-web/src/app/data/pages-metadata.ts (1)
118-160: LGTM!The new Bridge Widget entry is well-structured with appropriate metadata. The grammar issue previously flagged ("token" → "tokens") on line 137 has been addressed. Icon standardization to
SquareIconfor widget entries provides visual consistency.apps/playground-web/src/components/ui/tab-buttons.tsx (1)
98-148: LGTM with a note onsetTimeoutusage.The
useUnderlinehook correctly manages the underline position with proper cleanup of ResizeObserver and window resize listener. ThesetTimeout(0)to enable transitions after initial positioning is a standard pattern.The
setTimeout(100)in the ResizeObserver callback acts as debouncing but could potentially show stale positions briefly during rapid resizes. Consider using a more robust debounce if this becomes an issue.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8571 +/- ##
==========================================
- Coverage 54.49% 54.47% -0.03%
==========================================
Files 922 922
Lines 61361 61361
Branches 4150 4149 -1
==========================================
- Hits 33441 33425 -16
- Misses 27818 27835 +17
+ Partials 102 101 -1
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
♻️ Duplicate comments (2)
packages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsx (1)
19-20: External URL still makes tests non-deterministic.The previous review comment flagged this external URL as violating the deterministic test principle. Changing it to a different external URL doesn't address the root cause—the test still depends on an external resource that can become unavailable or change.
As per coding guidelines: "Keep tests deterministic and side-effect free" and "Use Mock Service Worker (MSW) for fetch/HTTP call interception in tests."
Apply the previously suggested fix to use an embedded test image:
-const imageLink = - "https://i2.seadn.io/ethereum/0xbd3531da5cf5857e7cfaa92426877b022e612cf8/750c4805cd12ea19c8c3909677e61988.png?w=350"; +const imageLink = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";Alternatively, use MSW to mock the image fetch if you need to test specific image loading behavior.
packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx (1)
202-311: Extract connectOptions type definition to a separate types file.This inline type definition should be extracted to
bridge-widget/types.tsfollowing the established pattern used bySwapWidgetConnectOptionsinswap-widget/types.ts, as previously noted in code reviews.
🧹 Nitpick comments (3)
apps/playground-web/src/app/x402/components/X402LeftSection.tsx (2)
69-70: Improve the biome-ignore justification and consider safer alternatives.The non-null assertion is safe because
TokenSelector(which callshandleTokenChange) is only rendered whenselectedChainis truthy (line 135). However, the justification "ok" is not descriptive. Consider:
- Better justification: Replace "ok" with an explanation like "selectedChain guaranteed by conditional rendering"
- Defensive alternative: Add a type guard at the function start:
const handleTokenChange = (token: TokenMetadata) => { + if (!selectedChain) return; + setSelectedToken({ address: token.address, - // biome-ignore lint/style/noNonNullAssertion: ok - chainId: selectedChain!, + chainId: selectedChain, });
21-116: Add explicit return types to align with coding guidelines.As per coding guidelines, "Write idiomatic TypeScript with explicit function declarations and return types." The component function and all handler functions lack explicit return types.
Apply this diff to add return types:
-export function X402LeftSection(props: { +export function X402LeftSection(props: { options: X402PlaygroundOptions; setOptions: React.Dispatch<React.SetStateAction<X402PlaygroundOptions>>; -}) { +}): React.JSX.Element { - const handleChainChange = (chainId: number) => { + const handleChainChange = (chainId: number): void => { - const handleTokenChange = (token: TokenMetadata) => { + const handleTokenChange = (token: TokenMetadata): void => { - const handleAmountChange = (e: React.ChangeEvent<HTMLInputElement>) => { + const handleAmountChange = (e: React.ChangeEvent<HTMLInputElement>): void => { - const handlePayToChange = (e: React.ChangeEvent<HTMLInputElement>) => { + const handlePayToChange = (e: React.ChangeEvent<HTMLInputElement>): void => { - const handleWaitUntilChange = ( + const handleWaitUntilChange = ( value: "simulated" | "submitted" | "confirmed", - ) => { + ): void => { - const handleSchemeChange = (value: "exact" | "upto") => { + const handleSchemeChange = (value: "exact" | "upto"): void => { - const handleMinAmountChange = (e: React.ChangeEvent<HTMLInputElement>) => { + const handleMinAmountChange = (e: React.ChangeEvent<HTMLInputElement>): void => {apps/playground-web/src/components/ui/tab-buttons.tsx (1)
55-66: Consider addingdisabledprop for accessibility.While the visual styling handles the disabled state via className, using the native
disabledprop on the Button would improve accessibility by preventing keyboard activation and communicating the state to assistive technologies.Apply this diff:
<Button className={cn( "relative inline-flex h-auto items-center gap-1.5 rounded-lg font-medium hover:bg-accent !px-3", !tab.isActive && "text-muted-foreground hover:text-foreground", - props.tabClassName, + tab.isDisabled && "cursor-not-allowed opacity-50", + props.tabClassName, tab.isActive && props.activeTabClassName, )} onClick={tab.onClick} + disabled={tab.isDisabled} ref={tab.isActive ? activeTabRef : undefined} variant="ghost" >
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (25)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx(1 hunks)apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx(2 hunks)apps/dashboard/src/app/bridge/widget/page.tsx(3 hunks)apps/playground-web/src/app/ai/components/ChatPageContent.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/types.ts(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/page.tsx(1 hunks)apps/playground-web/src/app/bridge/page.tsx(2 hunks)apps/playground-web/src/app/data/pages-metadata.ts(2 hunks)apps/playground-web/src/app/navLinks.ts(1 hunks)apps/playground-web/src/app/transactions/users/page.tsx(2 hunks)apps/playground-web/src/app/x402/components/X402LeftSection.tsx(1 hunks)apps/playground-web/src/components/blocks/FeatureCard.tsx(1 hunks)apps/playground-web/src/components/ui/tab-buttons.tsx(1 hunks)apps/playground-web/src/hooks/chains.ts(1 hunks)apps/playground-web/src/icons/PayIcon.tsx(0 hunks)apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx(3 hunks)packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx(8 hunks)packages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsx(2 hunks)packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- apps/playground-web/src/icons/PayIcon.tsx
🚧 Files skipped from review as they are similar to previous changes (10)
- apps/playground-web/src/hooks/chains.ts
- apps/playground-web/src/app/ai/components/ChatPageContent.tsx
- apps/playground-web/src/app/bridge/bridge-widget/page.tsx
- apps/playground-web/src/components/blocks/FeatureCard.tsx
- apps/playground-web/src/app/navLinks.ts
- apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
- apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts
- apps/dashboard/src/app/bridge/widget/page.tsx
- apps/playground-web/src/app/data/pages-metadata.ts
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes in TypeScript
Avoidanyandunknownin TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.) in TypeScript
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose
Files:
apps/playground-web/src/app/bridge/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/playground-web/src/app/x402/components/X402LeftSection.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/playground-web/src/app/transactions/users/page.tsxapps/playground-web/src/components/ui/tab-buttons.tsxapps/playground-web/src/app/bridge/bridge-widget/components/types.tspackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/bridge/bridge-widget/components/code.tsxpackages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsxapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Usecn()from@/lib/utilsfor conditional Tailwind class merging
Use design system tokens for styling (backgrounds:bg-card, borders:border-border, muted text:text-muted-foreground)
ExposeclassNameprop on root element for component overrides
Files:
apps/playground-web/src/app/bridge/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/playground-web/src/app/x402/components/X402LeftSection.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/playground-web/src/app/transactions/users/page.tsxapps/playground-web/src/components/ui/tab-buttons.tsxapps/playground-web/src/app/bridge/bridge-widget/components/types.tsapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/bridge/bridge-widget/components/code.tsxapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx
**/*.{js,jsx,ts,tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Biome governs formatting and linting; its rules live in biome.json. Run
pnpm fix&pnpm lintbefore committing, ensure there are no linting errors
Files:
apps/playground-web/src/app/bridge/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/playground-web/src/app/x402/components/X402LeftSection.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/playground-web/src/app/transactions/users/page.tsxapps/playground-web/src/components/ui/tab-buttons.tsxapps/playground-web/src/app/bridge/bridge-widget/components/types.tspackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/bridge/bridge-widget/components/code.tsxpackages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsxapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Lazy-import optional features; avoid top-level side-effects
Files:
apps/playground-web/src/app/bridge/page.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/playground-web/src/app/x402/components/X402LeftSection.tsxapps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/playground-web/src/app/transactions/users/page.tsxapps/playground-web/src/components/ui/tab-buttons.tsxapps/playground-web/src/app/bridge/bridge-widget/components/types.tspackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/bridge/bridge-widget/components/code.tsxpackages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsxapps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
apps/dashboard/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/dashboard/src/**/*.{ts,tsx}: UseNavLinkfor internal navigation with automatic active states in dashboard
Start server component files withimport "server-only";in Next.js
Read cookies/headers withnext/headersin server components
Access server-only environment variables in server components
Perform heavy data fetching in server components
Implement redirect logic withredirect()fromnext/navigationin server components
Begin client component files with'use client';directive in Next.js
Handle interactive UI with React hooks (useState,useEffect, React Query, wallet hooks) in client components
Access browser APIs (localStorage,window,IntersectionObserver) in client components
Support fast transitions with prefetched data in client components
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader for API calls – never embed tokens in URLs
Return typed results (Project[],User[]) from server-side data fetches – avoidany
Wrap client-side API calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysin React Query for cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components – only use analytics client-side
Files:
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/dashboard/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
apps/dashboard/**/*.{ts,tsx}: Always import from the central UI library under@/components/ui/*for reusable core UI components likeButton,Input,Select,Tabs,Card,Sidebar,Separator,Badge
UseNavLinkfrom@/components/ui/NavLinkfor internal navigation to ensure active states are handled automatically
For notices and skeletons, rely onAnnouncementBanner,GenericLoadingPage, andEmptyStateCardcomponents
Import icons fromlucide-reactor the project-specific…/iconsexports; never embed raw SVG
Keep components pure; fetch data outside using server components or hooks and pass it down via props
Use Tailwind CSS as the styling system; avoid inline styles or CSS modules
Merge class names withcnfrom@/lib/utilsto keep conditional logic readable
Stick to design tokens: usebg-card,border-border,text-muted-foregroundand other Tailwind variables instead of hard-coded colors
Use spacing utilities (px-*,py-*,gap-*) instead of custom margins
Follow mobile-first responsive design with Tailwind helpers (max-sm,md,lg,xl)
Never hard-code colors; always use Tailwind variables
Combine class names viacn, and exposeclassNameprop if useful in components
Use React Query (@tanstack/react-query) for all client-side data fetching with typed hooks
Files:
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/dashboard/**/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
Add
classNameprop to the root element of every component to allow external overrides
Files:
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{tsx,ts}: Import UI primitives from @/components/ui/_ (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in Dashboard and Playground apps
Use NavLink for internal navigation so active states are handled automatically
Use Tailwind CSS for styling – no inline styles or CSS modules
Merge class names with cn() from @/lib/utils to keep conditional logic readable
Stick to design tokens for styling: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
Server Components: Read cookies/headers with next/headers, access server-only environment variables or secrets, perform heavy data fetching, implement redirect logic with redirect() from next/navigation, and start files with import 'server-only'; to prevent client bundling
Client Components: Begin files with 'use client'; before imports, handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks), access browser APIs (localStorage, window, IntersectionObserver, etc.), and support fast transitions with client-side data prefetching
For client-side data fetching: Wrap calls in React Query (@tanstack/react-query), use descriptive and stable queryKeys for cache hits, configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s), and keep tokens secret by calling internal API routes or server actions
Files:
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}: Group feature-specific components under feature/components/_ and expose a barrel index.ts when necessary
Expose a className prop on the root element of every component for styling overrides
Files:
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: For server-side data fetching: Always call getAuthToken() to retrieve the JWT from cookies and inject the token as an Authorization: Bearer header – never embed it in the URL. Return typed results (Project[], User[], …) – avoid any
Never import posthog-js in server components; analytics reporting is client-side only
Files:
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
packages/thirdweb/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
packages/thirdweb/src/**/*.{ts,tsx}: Comment only ambiguous logic in SDK code; avoid restating TypeScript in prose
Load heavy dependencies inside async paths to keep initial bundle lean (e.g.const { jsPDF } = await import("jspdf");)Lazy-load heavy dependencies inside async paths to keep the initial bundle lean (e.g., const { jsPDF } = await import('jspdf');)
Files:
packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxpackages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.test.{ts,tsx}: Place tests alongside code:foo.ts↔foo.test.tsin the same directory
Use real function invocations with stub data in tests; avoid brittle mocks
Use Mock Service Worker (MSW) for fetch/HTTP call interception in tests
Keep tests deterministic and side-effect free
Use predefined test accounts fromtest/src/test-wallets.tsin tests
UseFORKED_ETHEREUM_CHAINfor mainnet interactions andANVIL_CHAINfor isolated tests
**/*.test.{ts,tsx}: Co-locate tests with source files using the pattern foo.ts ↔ foo.test.ts
Use real function invocations with stub data in tests; avoid brittle mocks
For network interactions in tests, use Mock Service Worker (MSW) to intercept fetch/HTTP calls, mocking only scenarios that are hard to reproduce
Keep tests deterministic and side-effect free; Vitest is pre-configured
Files:
packages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsx
**/*.stories.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
Add Storybook stories (
*.stories.tsx) alongside new UI components for documentation
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
**/*.stories.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
For new UI components, add Storybook stories (*.stories.tsx) alongside the code
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
🧬 Code graph analysis (6)
apps/playground-web/src/app/bridge/page.tsx (1)
apps/dashboard/src/@/icons/BridgeIcon.tsx (1)
BringToFrontIcon(1-1)
apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (4)
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
BridgeWidgetPlaygroundOptions(7-28)apps/playground-web/src/components/ui/tab-buttons.tsx (1)
TabButtons(9-87)apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts (1)
buildIframeUrl(5-72)apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx (1)
CodeGen(21-33)
apps/playground-web/src/app/transactions/users/page.tsx (1)
apps/playground-web/src/components/code/code-example.tsx (1)
CodeExample(17-56)
packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx (1)
packages/thirdweb/src/wallets/types.ts (1)
AppMetadata(3-20)
apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx (3)
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
BridgeWidgetPlaygroundOptions(7-28)apps/playground-web/src/lib/code-gen.ts (3)
quotes(17-19)stringifyImports(21-29)stringifyProps(1-15)apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts (1)
buildIframeUrl(5-72)
apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx (4)
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
BridgeWidgetPlaygroundOptions(7-28)apps/playground-web/src/components/ui/tab-buttons.tsx (1)
TabButtons(9-87)apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx (1)
LeftSection(20-119)apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (1)
RightSection(13-113)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Lint Packages
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Build Packages
- GitHub Check: Size
- GitHub Check: Unit Tests
- GitHub Check: Analyze (javascript)
🔇 Additional comments (25)
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (6)
1-11: LGTM!The imports and Storybook meta configuration follow standard patterns and TypeScript best practices.
13-20: LGTM!BasicUsage story appropriately demonstrates the component with both theme variants.
22-30: LGTM!CurrencySet story appropriately demonstrates currency configuration.
32-41: LGTM!NoThirdwebBranding story appropriately demonstrates the new
showThirdwebBrandingconfiguration option.
43-69: LGTM – Intentional improvement for custom theme documentation.The change from Variant-based rendering to direct BridgeWidgetScript usage better demonstrates how to construct custom theme objects. Showing a single instance with the full theme structure is clearer than showing multiple variants when the focus is on the custom theme configuration itself.
71-85: LGTM!The Variant helper appropriately provides consistent dual-theme rendering for multiple stories.
apps/playground-web/src/app/bridge/page.tsx (1)
1-1: LGTM! Good use of standard icon library.The replacement of PayIcon with BringToFrontIcon from lucide-react follows the coding guidelines to use standard icon libraries.
Also applies to: 11-11
apps/playground-web/src/app/transactions/users/page.tsx (1)
34-97: LGTM! Cleaner component structure.The consolidation of CodeExample props into a single self-closing element improves readability without changing functionality.
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (2)
67-67: LGTM! Branding prop correctly added and forwarded.The
showThirdwebBrandingprop is properly typed and forwarded to the underlying BridgeWidget component.Also applies to: 258-258
104-259: Solid refactor to unified BridgeWidget.The replacement of separate BuyWidget and SwapWidget with a single BridgeWidget entry point simplifies the component architecture and maintains proper analytics reporting. The connectOptions and callback configurations are correct.
Note: The DRY concern regarding duplicated chainId/tokenAddress extraction logic has already been flagged in a previous review.
apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx (1)
28-28: LGTM! Clean prop forwarding.The
showThirdwebBrandingprop is correctly added to the component interface and properly forwarded to BuyAndSwapEmbed.Also applies to: 38-38
apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx (1)
58-66: LGTM! Clear documentation for new features.The documentation updates properly document the new
inputCurrencyAmount,outputCurrencyAmount, andshowThirdwebBrandingquery parameters with helpful examples.Also applies to: 103-122, 175-179
apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx (2)
10-20: LGTM! Sensible default configuration.The default options provide a good starting state for the playground with reasonable defaults (iframe mode, USD currency, dark theme, branding enabled).
39-73: Well-structured component layout.The component structure cleanly separates concerns with TabButtons for integration type selection and distinct Left/Right sections. The responsive layout follows mobile-first principles with appropriate Tailwind utilities.
Note: The theme detection issue (using
themeinstead ofresolvedTheme) has already been flagged in a previous review.apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (2)
56-94: LGTM! BridgeWidget properly configured.The BridgeWidget configuration correctly forwards all options including theme, prefill data, currency, and branding. The
keyprop usingJSON.stringifyensures the widget remounts when prefill data changes, which is the correct behavior for a playground.
96-107: LGTM! iframe preview properly implemented.The iframe preview correctly uses
buildIframeUrlto construct the source URL, includes proper accessibility attributes, and has appropriate styling for the playground context.apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx (4)
21-33: LGTM! Proper lazy loading pattern.The CodeGen component correctly uses lazy loading with Suspense for the code client, which follows React best practices for code-splitting optional features.
48-118: LGTM! Script generation logic is sound.The script code generation correctly handles all configuration options including theme overrides, currency, branding, and token prefills. The conditional logic appropriately omits default values (USD, dark theme without overrides) to keep generated code clean.
Note: The missing return type annotation has already been flagged in a previous review.
120-202: LGTM! React component generation is well-structured.The React component code generation properly manages imports, conditionally includes theme overrides, and correctly formats props. The use of helper functions (
quotes,stringifyImports,stringifyProps) keeps the code clean and maintainable.Note: The missing return type annotation has already been flagged in a previous review.
204-214: LGTM! iframe code generation is correct.The iframe code generation correctly delegates URL construction to
buildIframeUrland generates a clean, valid HTML template.Note: The missing return type annotation has already been flagged in a previous review.
apps/playground-web/src/app/bridge/bridge-widget/components/types.ts (1)
1-28: LGTM! Clean type definition.The type structure is well-organized and follows TypeScript best practices. The optional properties and nested structure appropriately model the playground configuration needs.
packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx (4)
3-3: LGTM: Import additions support the new connectOptions prop.The new imports for
Chain,Wallet,SmartWalletOptions,AppMetadata,SiweAuthOptions, andConnectButton_connectModalOptionsare correctly sourced and necessary for the connectOptions type definition.Also applies to: 8-10, 21-22
35-36: LGTM: className and style props correctly implemented.The addition of
classNameandstyleprops follows standard React patterns and is correctly forwarded toEmbedContainer. The spread order ensures user-provided styles properly override defaults.Also applies to: 380-384
471-476: LGTM: TabButton styling refinements align with UI improvements.The styling updates use design system values correctly (
spacing.md,radius.full,fontSize.sm) and improve the visual hierarchy with the updated color logic (primaryTextfor active vssecondaryTextfor inactive). The fixed height with zero vertical padding is appropriate for consistent button sizing.
418-418: BothSwapWidgetandBuyWidgetsupport theconnectOptionsprop with compatible type signatures. Verification confirms thatSwapWidgetConnectOptionsandBuyWidgetConnectOptionsinclude all required properties from theBridgeWidget'sconnectOptionstype definition, ensuring proper type compatibility at lines 418 and 446.
apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx
Show resolved
Hide resolved
Merge activity
|
<!--
## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"
If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):
## Notes for the reviewer
Anything important to call out? Be sure to also clarify these in your comments.
## How to test
Unit tests, playground, etc.
-->
<!-- start pr-codex -->
---
## PR-Codex overview
This PR focuses on enhancing the `BridgeWidget` component within the playground by introducing new features, improving styling, and refining existing functionalities. It also includes updates to metadata and the handling of token selections and amounts.
### Detailed summary
- Removed `PayIcon` and replaced with `BringToFrontIcon`.
- Added `showThirdwebBranding` option to `UniversalBridgeEmbed`.
- Updated `BridgeWidget` to support token amounts and selections.
- Enhanced sorting of bridge chains in `chains.ts`.
- Improved styling for various components, including `FeatureCard` and `ChatPageContent`.
- Updated documentation for widget parameters.
- Refactored code for better readability and maintainability in multiple components.
> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`
<!-- end pr-codex -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit
* **New Features**
* Bridge Widget playground: interactive preview, code generation (script/component/iframe), theme, token/amount prefills, and preview modes.
* Unified buy/swap experience under a single Bridge widget and a new branding toggle (hide/show branding).
* Expanded connection options for wallet/connect flows.
* **Documentation**
* Added docs for token amounts, branding, and iframe examples.
* **Style**
* Minor typography and spacing refinements.
* **Chores**
* Navigation and feature card updates; small test adjustment (one image test skipped).
<sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
fc1ad2f to
aad3e64
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/playground-web/src/hooks/chains.ts (2)
18-18: Add explicit return type annotation.The function lacks an explicit return type. As per coding guidelines, TypeScript functions should have explicit return types.
Apply this diff:
-async function fetchBridgeSupportedChainsFromApi() { +async function fetchBridgeSupportedChainsFromApi(): Promise<BridgeChain[]> {
7-16: Import BridgeChain from the library to avoid type duplication.The
BridgeChaintype defined locally (lines 7–16) is identical to theBridgeChainexport frompackages/thirdweb/src/bridge/types/Chain.ts. Remove the local definition and import the library type instead to ensure consistency and prevent drift.
♻️ Duplicate comments (4)
apps/playground-web/src/app/transactions/users/page.tsx (1)
32-32: Add explicit return type annotation (previously flagged).The
UserTransactionsfunction still lacks an explicit return type, which is required by the coding guidelines for TypeScript functions.Apply this diff:
-function UserTransactions() { +function UserTransactions(): React.JSX.Element {packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx (1)
202-311: ExtractconnectOptionstype definition to a separate types file.This 110-line inline type definition should be extracted to
bridge-widget/types.tsfollowing the same pattern asSwapWidgetConnectOptionsinswap-widget/types.ts. The coding guidelines require reusing shared types from localtypes.tsbarrels, and keeping files focused on single-responsibility.Based on coding guidelines: "Re-use shared types from @/types or local types.ts barrels" and "Limit each file to one stateless, single-responsibility function for clarity."
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
119-153: Extract helper functions to reduce repetition.The quote type-checking and chain/token extraction logic is duplicated across
onError,onCancel, andonSuccesscallbacks, violating the DRY principle stated in the coding guidelines.Based on coding guidelines: "Choose composition over inheritance" and implicit DRY (Don't Repeat Yourself) principle.
Also applies to: 154-185, 186-217
apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (1)
115-143: Replace duplicate TabButtons with shared component.A
TabButtonscomponent already exists atapps/playground-web/src/components/ui/tab-buttons.tsxwith more features. This internal implementation duplicates that functionality and violates the DRY principle.Based on coding guidelines: "Choose composition over inheritance" and DRY principle.
🧹 Nitpick comments (3)
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (1)
13-85: Optional: Consider adding explicit return types to story functions.Per coding guidelines, exported functions should have explicit return types. While React component return types are often inferred in Storybook stories, you could add
: JSX.Elementfor stricter TypeScript compliance.Example:
-export function BasicUsage() { +export function BasicUsage(): JSX.Element { return (apps/playground-web/src/hooks/chains.ts (1)
35-48: Consider simplifying the regex check.The current approach uses
a.name[0]?.match(/^\d/)to check if a name starts with a digit. This can be simplified to/^\d/.test(a.name), which is more direct and idiomatic for boolean checks.Apply this diff:
return data.sort((a, b) => { - const aStartsWithNumber = a.name[0]?.match(/^\d/); - const bStartsWithNumber = b.name[0]?.match(/^\d/); + const aStartsWithNumber = /^\d/.test(a.name); + const bStartsWithNumber = /^\d/.test(b.name); if (aStartsWithNumber && !bStartsWithNumber) { return 1; } if (!aStartsWithNumber && bStartsWithNumber) { return -1; } return a.name.localeCompare(b.name); });apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (1)
92-92: Avoid JSON.stringify for React keys.Using
JSON.stringify(props.options.prefill)as a React key is a code smell that can cause performance issues. Prefer a more specific key derived from relevant prefill fields, or useuseMemoto compute a stable key string.Apply this diff to compute a more efficient key:
+ const prefillKey = useMemo(() => { + const prefill = props.options.prefill; + if (!prefill) return 'no-prefill'; + return [ + prefill.buyToken?.chainId, + prefill.buyToken?.tokenAddress, + prefill.buyToken?.amount, + prefill.sellToken?.chainId, + prefill.sellToken?.tokenAddress, + prefill.sellToken?.amount, + ].filter(Boolean).join('-'); + }, [props.options.prefill]); + <BridgeWidget className="shadow-xl" client={THIRDWEB_CLIENT} theme={themeObj} // ... props - key={JSON.stringify(props.options.prefill)} + key={prefillKey} />Don't forget to import
useMemoat the top of the file.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (25)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx(1 hunks)apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx(2 hunks)apps/dashboard/src/app/bridge/widget/page.tsx(3 hunks)apps/playground-web/src/app/ai/components/ChatPageContent.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/components/types.ts(1 hunks)apps/playground-web/src/app/bridge/bridge-widget/page.tsx(1 hunks)apps/playground-web/src/app/bridge/page.tsx(2 hunks)apps/playground-web/src/app/data/pages-metadata.ts(2 hunks)apps/playground-web/src/app/navLinks.ts(1 hunks)apps/playground-web/src/app/transactions/users/page.tsx(2 hunks)apps/playground-web/src/app/x402/components/X402LeftSection.tsx(1 hunks)apps/playground-web/src/components/blocks/FeatureCard.tsx(1 hunks)apps/playground-web/src/components/ui/tab-buttons.tsx(1 hunks)apps/playground-web/src/hooks/chains.ts(1 hunks)apps/playground-web/src/icons/PayIcon.tsx(0 hunks)apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx(3 hunks)packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx(8 hunks)packages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsx(2 hunks)packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- apps/playground-web/src/icons/PayIcon.tsx
🚧 Files skipped from review as they are similar to previous changes (14)
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
- apps/playground-web/src/components/blocks/FeatureCard.tsx
- apps/dashboard/src/app/bridge/widget/page.tsx
- apps/playground-web/src/app/bridge/bridge-widget/components/left-section.tsx
- apps/dashboard/src/app/bridge/(general)/components/client/UniversalBridgeEmbed.tsx
- apps/playground-web/src/app/bridge/bridge-widget/components/buildIframeUrl.ts
- apps/playground-web/src/app/bridge/bridge-widget/components/types.ts
- apps/playground-web/src/app/x402/components/X402LeftSection.tsx
- packages/thirdweb/src/react/web/ui/MediaRenderer/MediaRenderer.test.tsx
- apps/playground-web/src/app/bridge/page.tsx
- apps/playground-web/src/app/bridge/bridge-widget/components/code.tsx
- apps/playground-web/src/app/bridge/bridge-widget/components/bridge-playground.tsx
- apps/playground-web/src/components/ui/tab-buttons.tsx
- apps/playground-web/src/app/data/pages-metadata.ts
🧰 Additional context used
📓 Path-based instructions (13)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each TypeScript file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes in TypeScript
Avoidanyandunknownin TypeScript unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.) in TypeScript
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity and testability
Re-use shared types from @/types or local types.ts barrel exports
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics whenever possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic in TypeScript files; avoid restating TypeScript types and signatures in prose
Files:
apps/playground-web/src/hooks/chains.tsapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/transactions/users/page.tsxapps/playground-web/src/app/bridge/bridge-widget/page.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/playground-web/src/app/ai/components/ChatPageContent.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/playground-web/src/app/navLinks.ts
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/src/**/*.{ts,tsx}: Import UI component primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground
Use Tailwind CSS only – no inline styles or CSS modules in dashboard and playground
Usecn()from@/lib/utilsfor conditional Tailwind class merging
Use design system tokens for styling (backgrounds:bg-card, borders:border-border, muted text:text-muted-foreground)
ExposeclassNameprop on root element for component overrides
Files:
apps/playground-web/src/hooks/chains.tsapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/transactions/users/page.tsxapps/playground-web/src/app/bridge/bridge-widget/page.tsxapps/playground-web/src/app/ai/components/ChatPageContent.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/playground-web/src/app/navLinks.ts
**/*.{js,jsx,ts,tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Biome governs formatting and linting; its rules live in biome.json. Run
pnpm fix&pnpm lintbefore committing, ensure there are no linting errors
Files:
apps/playground-web/src/hooks/chains.tsapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/transactions/users/page.tsxapps/playground-web/src/app/bridge/bridge-widget/page.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/playground-web/src/app/ai/components/ChatPageContent.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/playground-web/src/app/navLinks.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Lazy-import optional features; avoid top-level side-effects
Files:
apps/playground-web/src/hooks/chains.tsapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/playground-web/src/app/transactions/users/page.tsxapps/playground-web/src/app/bridge/bridge-widget/page.tsxpackages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsxapps/playground-web/src/app/ai/components/ChatPageContent.tsxapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsxapps/playground-web/src/app/navLinks.ts
apps/dashboard/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/dashboard/src/**/*.{ts,tsx}: UseNavLinkfor internal navigation with automatic active states in dashboard
Start server component files withimport "server-only";in Next.js
Read cookies/headers withnext/headersin server components
Access server-only environment variables in server components
Perform heavy data fetching in server components
Implement redirect logic withredirect()fromnext/navigationin server components
Begin client component files with'use client';directive in Next.js
Handle interactive UI with React hooks (useState,useEffect, React Query, wallet hooks) in client components
Access browser APIs (localStorage,window,IntersectionObserver) in client components
Support fast transitions with prefetched data in client components
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader for API calls – never embed tokens in URLs
Return typed results (Project[],User[]) from server-side data fetches – avoidany
Wrap client-side API calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysin React Query for cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components – only use analytics client-side
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/dashboard/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
apps/dashboard/**/*.{ts,tsx}: Always import from the central UI library under@/components/ui/*for reusable core UI components likeButton,Input,Select,Tabs,Card,Sidebar,Separator,Badge
UseNavLinkfrom@/components/ui/NavLinkfor internal navigation to ensure active states are handled automatically
For notices and skeletons, rely onAnnouncementBanner,GenericLoadingPage, andEmptyStateCardcomponents
Import icons fromlucide-reactor the project-specific…/iconsexports; never embed raw SVG
Keep components pure; fetch data outside using server components or hooks and pass it down via props
Use Tailwind CSS as the styling system; avoid inline styles or CSS modules
Merge class names withcnfrom@/lib/utilsto keep conditional logic readable
Stick to design tokens: usebg-card,border-border,text-muted-foregroundand other Tailwind variables instead of hard-coded colors
Use spacing utilities (px-*,py-*,gap-*) instead of custom margins
Follow mobile-first responsive design with Tailwind helpers (max-sm,md,lg,xl)
Never hard-code colors; always use Tailwind variables
Combine class names viacn, and exposeclassNameprop if useful in components
Use React Query (@tanstack/react-query) for all client-side data fetching with typed hooks
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/dashboard/**/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/dashboard.mdc)
Add
classNameprop to the root element of every component to allow external overrides
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{tsx,ts}: Import UI primitives from @/components/ui/_ (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in Dashboard and Playground apps
Use NavLink for internal navigation so active states are handled automatically
Use Tailwind CSS for styling – no inline styles or CSS modules
Merge class names with cn() from @/lib/utils to keep conditional logic readable
Stick to design tokens for styling: backgrounds (bg-card), borders (border-border), muted text (text-muted-foreground), etc.
Server Components: Read cookies/headers with next/headers, access server-only environment variables or secrets, perform heavy data fetching, implement redirect logic with redirect() from next/navigation, and start files with import 'server-only'; to prevent client bundling
Client Components: Begin files with 'use client'; before imports, handle interactive UI relying on React hooks (useState, useEffect, React Query, wallet hooks), access browser APIs (localStorage, window, IntersectionObserver, etc.), and support fast transitions with client-side data prefetching
For client-side data fetching: Wrap calls in React Query (@tanstack/react-query), use descriptive and stable queryKeys for cache hits, configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s), and keep tokens secret by calling internal API routes or server actions
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/components/**/*.{tsx,ts}: Group feature-specific components under feature/components/_ and expose a barrel index.ts when necessary
Expose a className prop on the root element of every component for styling overrides
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: For server-side data fetching: Always call getAuthToken() to retrieve the JWT from cookies and inject the token as an Authorization: Bearer header – never embed it in the URL. Return typed results (Project[], User[], …) – avoid any
Never import posthog-js in server components; analytics reporting is client-side only
Files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
packages/thirdweb/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
packages/thirdweb/src/**/*.{ts,tsx}: Comment only ambiguous logic in SDK code; avoid restating TypeScript in prose
Load heavy dependencies inside async paths to keep initial bundle lean (e.g.const { jsPDF } = await import("jspdf");)Lazy-load heavy dependencies inside async paths to keep the initial bundle lean (e.g., const { jsPDF } = await import('jspdf');)
Files:
packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsxpackages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
**/*.stories.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
Add Storybook stories (
*.stories.tsx) alongside new UI components for documentation
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
**/*.stories.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
For new UI components, add Storybook stories (*.stories.tsx) alongside the code
Files:
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
🧬 Code graph analysis (6)
apps/playground-web/src/hooks/chains.ts (1)
packages/thirdweb/src/bridge/types/Chain.ts (1)
BridgeChain(42-42)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (3)
packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx (1)
BridgeWidget(363-455)apps/dashboard/src/@/constants/connect.ts (1)
appMetadata(1-5)apps/dashboard/src/@/analytics/report.ts (9)
reportTokenBuyFailed(264-266)reportAssetBuyFailed(342-350)reportTokenBuyCancelled(276-278)reportAssetBuyCancelled(360-367)reportTokenBuySuccessful(252-254)reportAssetBuySuccessful(221-228)reportTokenSwapFailed(314-320)reportTokenSwapSuccessful(288-290)reportTokenSwapCancelled(330-332)
apps/playground-web/src/app/transactions/users/page.tsx (2)
apps/playground-web/src/components/code/code-example.tsx (1)
CodeExample(17-56)apps/playground-web/src/components/account-abstraction/gateway.tsx (1)
GatewayPreview(137-292)
apps/playground-web/src/app/bridge/bridge-widget/page.tsx (2)
apps/playground-web/src/components/blocks/APIHeader.tsx (1)
PageLayout(49-70)apps/dashboard/src/@/icons/BridgeIcon.tsx (1)
BringToFrontIcon(1-1)
packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx (2)
packages/thirdweb/src/exports/react.ts (2)
ConnectButton_connectModalOptions(16-16)SiweAuthOptions(12-12)packages/thirdweb/src/wallets/types.ts (1)
AppMetadata(3-20)
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (2)
packages/thirdweb/src/script-exports/bridge-widget-script.tsx (1)
BridgeWidgetScript(69-79)packages/thirdweb/src/stories/utils.tsx (1)
storyClient(14-16)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Build Packages
- GitHub Check: Unit Tests
- GitHub Check: Size
- GitHub Check: Lint Packages
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: Analyze (javascript)
🔇 Additional comments (16)
apps/playground-web/src/app/transactions/users/page.tsx (1)
34-97: LGTM: Fragment removal simplifies the JSX structure.The refactoring correctly removes the unnecessary fragment wrapper around
CodeExample, improving code clarity. All props (code,header,lang,preview) are properly structured and aligned with the component signature.packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (1)
43-69: LGTM! Story refactor improves focus.The change from using the
Varianthelper to directly renderingBridgeWidgetScriptis appropriate. The story now clearly demonstrates a single custom theme rather than showing both dark and light variants, which makes sense since the custom theme object already specifiestype: "light".packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx (3)
3-3: LGTM! Necessary type imports for connectOptions.The new type imports support the connectOptions configuration and align with the types used in the inline type definition.
Also applies to: 8-10, 21-22
35-36: LGTM! Proper className and style prop exposure.The addition of
classNameandstyleprops follows the coding guidelines requiring root element style overrides, and they are correctly forwarded toEmbedContainer.Also applies to: 380-383
418-418: LGTM! Proper prop forwarding and styling refinements.The
connectOptionsare correctly passed to bothSwapWidgetandBuyWidget, and theTabButtonstyling updates are reasonable refinements (tighter padding, fixed height, and dynamic text color based on active state).Also applies to: 446-446, 471-476
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (2)
5-6: LGTM! Proper BridgeWidget import and branding prop addition.The migration from separate
BuyWidget/SwapWidgetimports to the unifiedBridgeWidgetis correct, and theshowThirdwebBrandingprop is properly added to the public API surface.Also applies to: 67-67
103-112: LGTM! Correct BridgeWidget integration.The
BridgeWidgetis properly configured with theme, client, connect options, and branding settings. Theswapconfiguration correctly maps prefill data and callbacks, and theshowThirdwebBrandingprop is properly forwarded.Also applies to: 220-258
apps/playground-web/src/app/ai/components/ChatPageContent.tsx (1)
87-87: LGTM! Improved NaN check with explicit method.Changing from
!isNaN(Number(id))to!Number.isNaN(Number(id))is a good improvement.Number.isNaNis more explicit and follows modern JavaScript best practices, though the behavior is identical here sinceNumber(id)is already called.apps/playground-web/src/app/navLinks.ts (1)
190-193: LGTM! Bridge Widget navigation link properly added.The new navigation entry is correctly structured and positioned within the Bridge submenu, matching the pattern of existing links.
apps/playground-web/src/app/bridge/bridge-widget/page.tsx (1)
1-33: LGTM! Well-structured Bridge Widget playground page.The new page follows Next.js App Router conventions and coding guidelines:
- Proper metadata export using
createMetadata- Correct icon usage (
BringToFrontIcon)ThirdwebProviderwrapping for client-side functionalityPageLayoutconfiguration with all required props including docs linkapps/playground-web/src/app/bridge/bridge-widget/components/right-section.tsx (2)
24-31: LGTM! Correct theme computation.The theme object is correctly computed using
darkThemeorlightThemefrom thirdweb/react with appropriate color overrides based on the options.
56-107: LGTM! Proper BridgeWidget and preview rendering.The component correctly:
- Renders
BridgeWidgetwith properly mapped prefill data, theme, currency, and branding settings- Conditionally renders an iframe preview using
buildIframeUrlfor iframe integration type- Displays
CodeGenin the code tabThe prefill data mapping from
optionstoBridgeWidgetprops is accurate.Also applies to: 109-109
apps/portal/src/app/bridge/bridge-widget/iframe/page.mdx (4)
58-58: LGTM: Header simplification improves clarity.The simplified header "Token selections" is more concise and better encompasses both token selection and amount configuration documented in this section.
103-122: LGTM: Clear documentation with concrete examples.The new Token amounts section is well-structured and provides clear, concrete examples showing how to use
inputCurrencyAmountandoutputCurrencyAmountparameters. The Details blocks follow the established pattern used elsewhere in the documentation.
64-65: The parameter namesinputCurrencyAmountandoutputCurrencyAmountin the documentation are correct and match the implementation. No public aliases exist for these parameters in the iframe widget API.
175-180: Parameter name verified - documentation is accurate.The
showThirdwebBrandingquery parameter name matches the implementation inapps/dashboard/src/app/bridge/widget/page.tsx, which parses this parameter and defaults totruewhen not specified. Setting it tofalsecorrectly hides the branding as documented. The example URL is properly formed and functional.

PR-Codex overview
This PR focuses on enhancing the
BridgeWidgetcomponent and its associated functionalities, including UI improvements, new options for token selection, and error handling enhancements. It also updates the metadata and documentation for better user guidance.Detailed summary
PayIconand replaced withBringToFrontIcon.showThirdwebBrandingoption inUniversalBridgeEmbed.useBridgeSupportedChains.bridgeFeatureCardswith new titles and icons.BridgeWidgetPlaygroundwith new options for theme and branding.BuyAndSwapEmbed.Summary by CodeRabbit
New Features
Documentation
Style
Chores
✏️ Tip: You can customize this high-level summary in your review settings.