Skip to content

Conversation

MananTank
Copy link
Member

@MananTank MananTank commented Sep 12, 2025


PR-Codex overview

This PR focuses on enhancing the Bridge functionality within the thirdweb package, improving UI components, adding new features, and refining existing code for better usability and performance.

Detailed summary

  • Added BridgeChain type in Chain.ts.
  • Introduced cleanedChainName function in utils.ts.
  • Updated DynamicHeight component's transition effect.
  • Modified Text component to include multiline prop.
  • Changed skeletonBg color in design system.
  • Added full radius option in design system.
  • Enhanced Skeleton component to accept additional styles.
  • Updated Line component to allow dashed variants.
  • Added style prop to Spinner component.
  • Implemented useBridgeChains hook for fetching bridge chains.
  • Enhanced Input component to accept background color.
  • Introduced ArrowUpDownIcon component.
  • Updated messages in UnsupportedTokenScreen.
  • Added storybook examples for SwapWidget and BuyWidget.
  • Refined getFiatSymbol function for better currency handling.
  • Added trackingTight prop to Text component.
  • Implemented hooks for active wallet information.
  • Enhanced button variants in Button component.
  • Added SearchInput component for better token selection.
  • Improved error handling in SwapWidget.
  • Refactored SelectBuyToken and SelectSellToken components for better UX.
  • Added loading states and improved token selection logic.

The following files were skipped due to too many changes: packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features

    • Added Bridge Swap Widget with multi-step flow, token/chain selection, search, and live quotes.
    • Expanded fiat currency symbol coverage.
    • Image component now supports custom fallbacks.
    • New “ghost-solid” button variant and ArrowUpDown icon.
  • Style/Improvements

    • Updated copy and multiline rendering in Bridge screens.
    • Smoother height transitions; added Input background prop.
    • Text supports tighter tracking; adjusted default weight.
    • Spinner/Skeleton accept style overrides.
    • Added full corner radius and refined skeleton backgrounds.
  • Documentation

    • New Storybook stories for SwapWidget, SelectChain/Token flows, and BuyWidget.
  • Chores

    • Added npm type-check script.

@MananTank MananTank requested review from a team as code owners September 12, 2025 22:00
Copy link

changeset-bot bot commented Sep 12, 2025

⚠️ No Changeset found

Latest commit: ce099a3

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link

vercel bot commented Sep 12, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
docs-v2 Ready Ready Preview Comment Sep 12, 2025 11:25pm
nebula Ready Ready Preview Comment Sep 12, 2025 11:25pm
thirdweb_playground Ready Ready Preview Comment Sep 12, 2025 11:25pm
thirdweb-www Ready Ready Preview Comment Sep 12, 2025 11:25pm
wallet-ui Ready Ready Preview Comment Sep 12, 2025 11:25pm

Copy link
Contributor

coderabbitai bot commented Sep 12, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Adds a new Bridge Swap widget with multi-step UI (token selection, quote loading, preview, execution), new hooks for chains/tokens, supporting UI components, and Storybook stories. Updates design-system primitives (radius, inputs, buttons, text, line, dynamic height), image handling with fallback, spinner/skeleton styling, minor bridge UI text tweaks, a Chain type alias, fiat symbol refactor, and a new npm typecheck script.

Changes

Cohort / File(s) Summary
Build & scripts
packages/thirdweb/package.json
Adds a typecheck script running tsc --project ./tsconfig.build.json --module nodenext --moduleResolution nodenext --noEmit.
Bridge type alias
packages/thirdweb/src/bridge/types/Chain.ts
Exports type BridgeChain = Chain; with no runtime changes.
Fiat symbol resolution
packages/thirdweb/src/pay/convert/type.ts
Replaces switch-case with a currencySymbol map in getFiatSymbol; defaults to "$" for unknown currencies; no API signature changes.
Design system: tokens & primitives
packages/thirdweb/src/react/core/design-system/index.ts, packages/thirdweb/src/react/web/ui/components/basic.tsx, .../components/buttons.tsx, .../components/formElements.tsx, .../components/text.tsx, .../components/DynamicHeight.tsx
Theme: skeletonBg uses colors.base4; radius gains full. Components: Line supports dashed; Button adds ghost-solid variant; Input supports optional bg; Text default weight 400 and trackingTight; DynamicHeight uses ease timing.
Media & loaders
packages/thirdweb/src/react/web/ui/components/Img.tsx, .../components/Skeleton.tsx, .../components/Spinner.tsx
Img adds pending/loaded/fallback states and fallback prop; Skeleton and Spinner accept optional style prop.
Icons
packages/thirdweb/src/react/web/ui/ConnectWallet/icons/ArrowUpDownIcon.tsx
Adds ArrowUpDownIcon SVG component.
Bridge UI copy/props tweaks
packages/thirdweb/src/react/web/ui/Bridge/StepRunner.tsx, .../Bridge/UnsupportedTokenScreen.tsx
StepRunner: adds multiline to Text. UnsupportedTokenScreen: updates two user-facing strings.
Swap widget: core feature
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx, .../swap-widget/swap-ui.tsx
Introduces SwapWidget and container, with 4-screen flow: swap UI → quote loading → preview → execution. SwapUI handles amount inputs, token selection, live quotes, wallet gating.
Swap widget: selectors & inputs
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx, .../swap-widget/SelectChainButton.tsx, .../swap-widget/select-chain.tsx, .../swap-widget/select-buy-token.tsx, .../swap-widget/select-sell-token.tsx
Adds search input, chain button, chain selection UI, buy-token selector (with lazy price fetch), and sell-token selector (wallet-aware, balances, pagination, search).
Swap widget: hooks, utils, types
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-bridge-chains.ts, .../swap-widget/use-tokens.ts, .../swap-widget/utils.ts, .../swap-widget/types.ts
Adds hooks for bridge chains and tokens/balances; utility cleanedChainName; types for connect options and active wallet info.
Storybook
packages/thirdweb/src/stories/Bridge/Swap/SelectBuyToken.stories.tsx, .../Bridge/Swap/SelectChain.stories.tsx, .../Bridge/Swap/SelectSellToken.stories.tsx, packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx, packages/thirdweb/src/stories/BuyWidget.stories.tsx
New stories for Swap widget screens and flows; scenarios include loading, connected/disconnected, currency/theme variants, and BuyWidget samples.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant SW as SwapWidget
  participant UI as SwapUI
  participant Q as QuoteLoader
  participant PV as PaymentDetails
  participant EX as StepRunner
  participant W as Wallet
  participant B as Bridge API

  U->>SW: Open widget
  SW->>UI: Render base swap UI
  UI->>W: Check active wallet (optional)
  U->>UI: Select sell/buy tokens, enter amount
  UI->>B: Fetch quote (poll ~20s)
  B-->>UI: Quote result
  U->>UI: Click Swap
  UI->>SW: onSwap(quote, request)
  SW->>Q: Load quote details
  Q-->>SW: preparedQuote, request
  SW->>PV: Show preview
  U->>PV: Confirm
  PV->>SW: onConfirm(preparedQuote, request)
  SW->>EX: Execute steps
  loop For each step
    EX->>W: Request transaction/signature
    W-->>EX: Tx result
    EX->>B: Report / query status
    B-->>EX: Status update
  end
  EX-->>SW: Complete / Cancel / Error
  SW-->>U: Final status
Loading
sequenceDiagram
  autonumber
  actor U as User
  participant SB as SelectBuyToken
  participant CH as useBridgeChains
  participant TK as useTokens
  participant API as Bridge API

  U->>SB: Open "Select Buy Token"
  SB->>CH: Query bridge chains
  CH-->>SB: Chains list
  U->>SB: Choose chain / Search tokens
  SB->>TK: Fetch tokens (chainId, search, offset/limit)
  TK->>API: tokens({ includePrices:false, name/tokenAddress })
  API-->>TK: Token list
  TK-->>SB: Tokens
  U->>SB: Click token
  SB->>API: getToken(...) (with prices)
  API-->>SB: TokenWithPrices
  SB-->>U: Selection applied
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mnn/swap-ui

Comment @coderabbitai help to get the list of available commands and usage tips.

Pre-merge checks

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description Check ⚠️ Warning The PR description currently contains the repository's commented template plus an auto-generated PR-Codex overview, but it does not fill the required template sections. The repository template expects a formatted PR title (e.g. "[SDK/Dashboard/Portal] Feature/Fix: ..."), an optional Linear/issue tag, a "Notes for the reviewer" section, and a "How to test" section with concrete test steps, which are missing or left commented out. Because those required sections and testing instructions are not present, the description does not meet the repository's template requirements. Please update the PR description to follow the repository template: set the PR title in the required format, add the Linear/issue tag if available, populate "Notes for the reviewer" with scope, risk, and important decisions, and add a "How to test" section with concrete steps (unit/test commands, storybook/playground steps, and any env setup). Also include any breaking changes, migration notes, or screenshots that help reviewers. After updating the description, re-run CI and note any remaining TODOs or follow-ups in the description.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title "SDK: SwapWidget [WIP]" is concise and directly relates to the main change in this PR (the new SwapWidget and related bridge swap UI components), so it correctly signals the primary purpose of the changeset. It is short and easy to scan, but includes a "[WIP]" marker and does not fully follow the repository's suggested "[SDK/Dashboard/Portal] Feature/Fix: Concise title" format from the template. Overall the title is accurate and focused enough to pass a basic PR-title check.

Copy link
Contributor

graphite-app bot commented Sep 12, 2025

How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

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.

Copy link
Contributor

github-actions bot commented Sep 12, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 63.96 KB (0%) 1.3 s (0%) 264 ms (+320.55% 🔺) 1.6 s
thirdweb (cjs) 356.86 KB (0%) 7.2 s (0%) 622 ms (+30.45% 🔺) 7.8 s
thirdweb (minimal + tree-shaking) 5.73 KB (0%) 115 ms (0%) 99 ms (+4637.95% 🔺) 213 ms
thirdweb/chains (tree-shaking) 526 B (0%) 11 ms (0%) 62 ms (+3158.31% 🔺) 72 ms
thirdweb/react (minimal + tree-shaking) 19.15 KB (0%) 383 ms (0%) 159 ms (+3646.92% 🔺) 542 ms

Copy link

codecov bot commented Sep 12, 2025

Codecov Report

❌ Patch coverage is 56.41026% with 34 lines in your changes missing coverage. Please review.
✅ Project coverage is 56.64%. Comparing base (a724bc3) to head (ce099a3).
⚠️ Report is 9 commits behind head on main.

Files with missing lines Patch % Lines
...kages/thirdweb/src/react/web/ui/components/Img.tsx 30.00% 21 Missing ⚠️
...s/thirdweb/src/react/web/ui/components/buttons.tsx 11.11% 8 Missing ⚠️
packages/thirdweb/src/pay/convert/type.ts 96.42% 1 Missing ⚠️
...es/thirdweb/src/react/web/ui/Bridge/StepRunner.tsx 0.00% 1 Missing ⚠️
...ges/thirdweb/src/react/web/ui/components/basic.tsx 50.00% 1 Missing ⚠️
...rdweb/src/react/web/ui/components/formElements.tsx 0.00% 1 Missing ⚠️
...ages/thirdweb/src/react/web/ui/components/text.tsx 50.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##             main    #8044    +/-   ##
========================================
  Coverage   56.63%   56.64%            
========================================
  Files         904      904            
  Lines       58685    58805   +120     
  Branches     4166     4172     +6     
========================================
+ Hits        33238    33310    +72     
- Misses      25341    25389    +48     
  Partials      106      106            
Flag Coverage Δ
packages 56.64% <56.41%> (+<0.01%) ⬆️
Files with missing lines Coverage Δ
...ges/thirdweb/src/react/core/design-system/index.ts 84.02% <100.00%> (+0.11%) ⬆️
...src/react/web/ui/Bridge/UnsupportedTokenScreen.tsx 14.28% <ø> (ø)
...dweb/src/react/web/ui/components/DynamicHeight.tsx 87.17% <100.00%> (ø)
.../thirdweb/src/react/web/ui/components/Skeleton.tsx 96.55% <100.00%> (+0.12%) ⬆️
...s/thirdweb/src/react/web/ui/components/Spinner.tsx 94.44% <100.00%> (+0.15%) ⬆️
packages/thirdweb/src/pay/convert/type.ts 94.64% <96.42%> (+25.75%) ⬆️
...es/thirdweb/src/react/web/ui/Bridge/StepRunner.tsx 3.90% <0.00%> (ø)
...ges/thirdweb/src/react/web/ui/components/basic.tsx 87.16% <50.00%> (-0.76%) ⬇️
...rdweb/src/react/web/ui/components/formElements.tsx 97.00% <0.00%> (-1.00%) ⬇️
...ages/thirdweb/src/react/web/ui/components/text.tsx 97.43% <50.00%> (-2.57%) ⬇️
... and 2 more

... and 24 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 18

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
packages/thirdweb/src/bridge/types/Chain.ts (1)

42-43: Add required TSDoc for public alias per package guidelines

Public symbols here must include TSDoc with an example and a custom stability tag.

Add docs:

+
+/**
+ * Alias of {@link Chain} used across the Bridge UI/API surface.
+ * @beta
+ * @public
+ * @example
+ * import type { BridgeChain } from "thirdweb/bridge";
+ * function onSelect(chain: BridgeChain) {
+ *   console.log(chain.chainId, chain.name);
+ * }
+ */
 export type BridgeChain = Chain;
packages/thirdweb/src/react/web/ui/components/formElements.tsx (1)

36-106: Add TSDoc or mark internal for exported UI primitives

Per repo guidelines, exported symbols in packages/thirdweb need TSDoc with an example or an explicit @internal. Please annotate Label, Input, and InputContainer.

-export const Input = /* @__PURE__ */ StyledInput<InputProps>((props) => {
+/**
+ * @internal
+ */
+export const Input = /* @__PURE__ */ StyledInput<InputProps>((props) => {
packages/thirdweb/src/react/web/ui/components/buttons.tsx (1)

26-157: Add TSDoc or mark internal for Button exports

Please annotate Button, ButtonLink, and IconButton per packages/thirdweb guidelines.

-export const Button = /* @__PURE__ */ StyledButton((props: ButtonProps) => {
+/**
+ * @internal
+ */
+export const Button = /* @__PURE__ */ StyledButton((props: ButtonProps) => {
packages/thirdweb/src/react/web/ui/components/Img.tsx (1)

37-41: Fix “undefinedpx” sizing when width/height are omitted

widthPx/heightPx produce invalid values if props are undefined. Provide safe defaults.

-  const widthPx = `${props.width}px`;
-  const heightPx = `${props.height || props.width}px`;
+  const DEFAULT_SIZE = "24px";
+  const widthPx = props.width ? `${props.width}px` : undefined;
+  const heightPx = props.height
+    ? `${props.height}px`
+    : props.width
+      ? `${props.width}px`
+      : DEFAULT_SIZE;
🧹 Nitpick comments (51)
packages/thirdweb/src/react/web/ui/ConnectWallet/icons/ArrowUpDownIcon.tsx (3)

3-16: Forward SVG props and add a sane default size.

Enable consumers to pass className/aria-label/etc. and avoid undefined width/height.

-export const ArrowUpDownIcon: IconFC = (props) => {
+export const ArrowUpDownIcon: IconFC = ({ size = 24, ...props }) => {
   return (
     <svg
       xmlns="http://www.w3.org/2000/svg"
       viewBox="0 0 24 24"
       fill="none"
       stroke="currentColor"
-      strokeWidth="2"
+      strokeWidth={2}
       strokeLinecap="round"
       strokeLinejoin="round"
-      role="presentation"
-      width={props.size}
-      height={props.size}
+      role="presentation"
+      width={size}
+      height={size}
+      {...props}
     >

13-16: A11y: mark decorative SVGs as hidden to AT (or provide an accessible name).

If this icon is purely decorative, prefer aria-hidden and prevent focus; if it conveys meaning, pass an aria-label via props and keep role="img".

-      role="presentation"
+      aria-hidden="true"
+      focusable="false"

3-3: Add TSDoc with a custom tag per packages/thirdweb policy.

Mark as @internal if not part of the public API; otherwise add an @example.

+/**
+ * Up/down arrows icon used in wallet/bridge UIs.
+ * @internal
+ */
 export const ArrowUpDownIcon: IconFC = ({ size = 24, ...props }) => {
packages/thirdweb/src/react/web/ui/Bridge/UnsupportedTokenScreen.tsx (3)

97-98: Add missing period for consistency and polish.

The preceding testnet message ends with a period. Mirror that here.

-        This token or chain is not supported by the Bridge
+        This token or chain is not supported by the Bridge.

30-40: Don’t use React Query for a side-effect-only analytics ping.

Using useQuery here adds caching semantics and a static key that won’t re-fire if props change within the same mount. Prefer useEffect (or a useMutation) tied to the relevant deps.

-import { useQuery } from "@tanstack/react-query";
+import { useEffect } from "react";
@@
-  useQuery({
-    queryFn: () => {
-      trackPayEvent({
-        chainId: chain.id,
-        client,
-        event: "ub:ui:unsupported_token",
-        fromToken: tokenAddress,
-      });
-    },
-    queryKey: ["unsupported_token"],
-  });
+  useEffect(() => {
+    trackPayEvent({
+      chainId: chain.id,
+      client,
+      event: "ub:ui:unsupported_token",
+      fromToken: tokenAddress,
+    });
+  }, [chain.id, client, tokenAddress]);

If you must keep React Query, at least include chain.id and tokenAddress in the queryKey and set staleTime: Infinity.


25-25: Add explicit return type to match TS guidelines.

Declare the component’s return type for clarity and tooling.

-export function UnsupportedTokenScreen(props: UnsupportedTokenScreenProps) {
+export function UnsupportedTokenScreen(props: UnsupportedTokenScreenProps): JSX.Element {
packages/thirdweb/src/react/web/ui/components/DynamicHeight.tsx (1)

20-21: Smoother height animation and consistency with DS transitions

Consider ease-in-out and explicitly hint painting for slightly smoother expansion; also centralize duration/timing as a design token to keep consistent across components.

Apply this minimal tweak:

-        transition: "height 210ms ease",
+        transition: "height 210ms ease-in-out",
+        willChange: "height",
packages/thirdweb/package.json (1)

344-345: Avoid duplicating tsc invocation between lint and typecheck

You can route lint to call the new typecheck script for one source of truth.

Update scripts:

-    "lint": "knip && biome check ./src && tsc --project ./tsconfig.build.json --module nodenext --moduleResolution nodenext --noEmit",
+    "lint": "knip && biome check ./src && pnpm typecheck",
     "typedoc": "node scripts/typedoc.mjs && node scripts/parse.mjs",
     "typecheck": "tsc --project ./tsconfig.build.json --module nodenext --moduleResolution nodenext --noEmit",
packages/thirdweb/src/react/web/ui/components/Skeleton.tsx (1)

18-26: Hide decorative skeletons from assistive tech

Marking as decorative avoids noisy announcements while loading.

-    <SkeletonDiv
+    <SkeletonDiv
+      aria-hidden
       className={props.className || ""}
       color={props.color}
       style={{
         height: props.height,
         width: props.width || "auto",
         ...props.style,
       }}
     />
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/utils.ts (1)

1-3: Make chain-name cleanup more robust

Limit removal to trailing “Mainnet”, handle case/parentheses, and avoid returning empty strings.

-export function cleanedChainName(name: string) {
-  return name.replace("Mainnet", "");
-}
+export function cleanedChainName(name: string) {
+  const cleaned = name.replace(/\s*\(?Mainnet\)?$/i, "").trim();
+  return cleaned.length > 0 ? cleaned : name;
+}

Happy to add a tiny test matrix (e.g., "Ethereum Mainnet", "Mainnet", "Zora (Mainnet)", "Arbitrum mainnet").

packages/thirdweb/src/react/web/ui/components/buttons.tsx (1)

120-127: Hover styling fine; improve transition and default background

Use transparent (clearer intent) and animate background for smoother UX.

-    transition: "border 200ms ease",
+    transition: "border 200ms ease, background 200ms ease, color 200ms ease",
...
-      if (props.variant === "ghost-solid") {
+      if (props.variant === "ghost-solid") {
         return {
           "&:hover": {
             background: theme.colors.tertiaryBg,
           },
-          border: "1px solid transparent",
+          background: "transparent",
+          border: "1px solid transparent",
         };
       }
packages/thirdweb/src/pay/convert/type.ts (1)

36-60: Optional: disambiguate $-prefixed locales

Consider locale-specific prefixes (e.g., HK$, CA$, A$) if UI needs clarity across multiple “$” currencies.

packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts (1)

1-37: Mark hooks as internal

These widget-specific hooks should be annotated to avoid being treated as public API.

-export function useTokens(options: {
+/**
+ * @internal
+ */
+export function useTokens(options: {
packages/thirdweb/src/react/web/ui/Bridge/StepRunner.tsx (1)

164-177: Simplify background color helper

All branches return the same color; collapse the switch.

-  const getStepBackgroundColor = (
-    status: "pending" | "executing" | "completed" | "failed",
-  ) => {
-    switch (status) {
-      case "completed":
-        return theme.colors.tertiaryBg;
-      case "executing":
-        return theme.colors.tertiaryBg;
-      case "failed":
-        return theme.colors.tertiaryBg;
-      default:
-        return theme.colors.tertiaryBg;
-    }
-  };
+  const getStepBackgroundColor = () => theme.colors.tertiaryBg;
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-bridge-chains.ts (2)

5-12: Include client in queryKey; set a sane cache policy

Prevents cross-client cache bleed and reduces refetch churn.

-export function useBridgeChains(client: ThirdwebClient) {
-  return useQuery({
-    queryKey: ["bridge-chains"],
-    queryFn: () => {
-      return chains({ client });
-    },
-  });
-}
+export function useBridgeChains(client: ThirdwebClient) {
+  return useQuery({
+    queryKey: ["bridge-chains", client.clientId],
+    staleTime: 5 * 60 * 1000,
+    queryFn: () => chains({ client }),
+  });
+}

5-12: Mark internal

This is widget plumbing, not a public SDK surface.

-export function useBridgeChains(client: ThirdwebClient) {
+/**
+ * @internal
+ */
+export function useBridgeChains(client: ThirdwebClient) {
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx (3)

17-28: Make icon decorative and click‑through

Set the search icon to be ignored by screen readers and not intercept pointer events.

       <Container color="secondaryText">
         <MagnifyingGlassIcon
           width={iconSize.md}
           height={iconSize.md}
+          aria-hidden="true"
           style={{
             position: "absolute",
             left: spacing.sm,
             top: "50%",
             transform: "translateY(-50%)",
+            pointerEvents: "none",
           }}
         />
       </Container>

30-38: Avoid magic number; improve a11y

Compute left padding from tokens, set proper input type, and add an accessible label.

       <Input
-        variant="outline"
+        variant="outline"
+        type="search"
         placeholder={props.placeholder}
         value={props.value}
         style={{
-          paddingLeft: "44px",
+          paddingLeft: `calc(${spacing.sm} + ${iconSize.md}px + ${spacing.xs})`,
         }}
-        onChange={(e) => props.onChange(e.target.value)}
+        aria-label={props.placeholder}
+        onChange={(e) => props.onChange(e.target.value)}
       />

6-10: Add explicit types per guidelines

Add a props alias and explicit return type for the component.

-export function SearchInput(props: {
-  value: string;
-  onChange: (value: string) => void;
-  placeholder: string;
-}) {
+type SearchInputProps = {
+  value: string;
+  onChange: (value: string) => void;
+  placeholder: string;
+};
+
+export function SearchInput(props: SearchInputProps): JSX.Element {
packages/thirdweb/src/stories/Bridge/Swap/SelectBuyToken.stories.tsx (2)

19-39: Loading story renders a non-functional “Load More” button

Passing a no-op showMore causes the button to render while loading. Omit it in the loading story.

-export function ChainLoading() {
+export function ChainLoading(): JSX.Element {
@@
-        showMore={() => {}}
         setSearch={() => {}}
       />

42-53: Add explicit return types to stories

Align with explicit return types guideline.

-export function WithData() {
+export function WithData(): JSX.Element {
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SelectChainButton.tsx (3)

13-17: Add explicit return type

-export function SelectChainButton(props: {
+export function SelectChainButton(props: {
   selectedChain: BridgeChain;
   client: ThirdwebClient;
   onClick: () => void;
-}) {
+}): JSX.Element {

19-31: Button semantics and accessibility

Ensure it doesn’t submit forms and is labeled for screen readers.

     <Button
       variant="secondary"
       fullWidth
+      type="button"
+      aria-label="Select chain"
       style={{
         justifyContent: "flex-start",
         fontWeight: 500,
         fontSize: fontSize.md,
         padding: `${spacing.sm} ${spacing.sm}`,
         minHeight: "48px",
       }}

32-39: Alt text and name cleanup

Provide alt text and trim the cleaned name to avoid trailing spaces.

       <Img
         src={props.selectedChain.icon}
         client={props.client}
         width={iconSize.lg}
         height={iconSize.lg}
+        alt={cleanedChainName(props.selectedChain.name).trim()}
       />
-      <span> {cleanedChainName(props.selectedChain.name)} </span>
+      <span> {cleanedChainName(props.selectedChain.name).trim()} </span>
packages/thirdweb/src/stories/Bridge/Swap/SelectChain.stories.tsx (2)

19-33: Add explicit return type

-export function WithData() {
+export function WithData(): JSX.Element {

35-51: Add explicit return type

-export function Loading() {
+export function Loading(): JSX.Element {
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx (3)

13-15: Add explicit return type

-export function BasicUsage() {
+export function BasicUsage(): JSX.Element {

17-19: Add explicit return type

-export function CurrencySet() {
+export function CurrencySet(): JSX.Element {

21-23: Add explicit return type

-export function LightMode() {
+export function LightMode(): JSX.Element {
packages/thirdweb/src/react/web/ui/components/Img.tsx (1)

60-66: Remove unused/ineffective flex property

justifyItems has no effect on flex containers.

       style={{
         alignItems: "center",
         display: "inline-flex",
         flexShrink: 0,
-        justifyItems: "center",
         position: "relative",
       }}
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/types.ts (3)

45-51: Grammar/clarity in Account Abstraction section.

Small wording fixes for correctness and tone.

- * Enable Account abstraction for all wallets. This will connect to the users's smart account based on the connected personal wallet and the given options.
- *
- * This allows to sponsor gas fees for your user's transaction using the thirdweb account abstraction infrastructure.
+ * Enable Account Abstraction for all wallets. This connects to the user's smart account based on the connected personal wallet and the given options.
+ *
+ * This allows you to sponsor gas fees for your user's transactions using thirdweb's Account Abstraction infrastructure.

121-126: Minor grammar: article before “All Wallets”.

-   * By default, ConnectButton modal shows a "All Wallets" button that shows a list of 500+ wallets.
+   * By default, the ConnectButton modal shows an "All Wallets" button that lists 500+ wallets.

129-134: Typo: “Ethererum” → “Ethereum”.

-   * Enable SIWE (Sign in with Ethererum) by passing an object of type `SiweAuthOptions` to
+   * Enable SIWE (Sign in with Ethereum) by passing an object of type `SiweAuthOptions` to
packages/thirdweb/src/stories/Bridge/Swap/SelectSellToken.stories.tsx (1)

25-70: Add explicit return types for story exports.

Keep TSX explicit per repo guidelines.

-export function ChainLoading() {
+export function ChainLoading(): JSX.Element {
   ...
}
-export function Disconnected() {
+export function Disconnected(): JSX.Element {
   ...
}
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-chain.tsx (3)

19-26: Rename prop type to match component purpose and add return types.

Type name says “BuyToken” but this is a chain selector. Also add explicit return types.

-type SelectBuyTokenProps = {
+type SelectBridgeChainProps = {
   onBack: () => void;
   client: ThirdwebClient;
   onSelectChain: (chain: BridgeChain) => void;
   selectedChain: BridgeChain | undefined;
 };
 
-export function SelectBridgeChain(props: SelectBuyTokenProps) {
+export function SelectBridgeChain(props: SelectBridgeChainProps): JSX.Element {
   ...
 }
 
 export function SelectBridgeChainUI(
-  props: SelectBuyTokenProps & {
+  props: SelectBridgeChainProps & {
     isPending: boolean;
     chains: BridgeChain[];
     onSelectChain: (chain: BridgeChain) => void;
     selectedChain: BridgeChain | undefined;
-  },
-) {
+  },
+): JSX.Element {

Also applies to: 39-46


95-99: Provide keys instead of suppressing lints on skeleton list.

-{props.isPending &&
-  new Array(20).fill(0).map(() => (
-    // biome-ignore lint/correctness/useJsxKeyInIterable: ok
-    <ChainButtonSkeleton />
-  ))}
+{props.isPending &&
+  new Array(20).fill(0).map((_, i) => <ChainButtonSkeleton key={`sk-${i}`} />)}

156-163: Add accessible alt text for chain icons.

-      <Img
+      <Img
         src={props.chain.icon}
         client={props.client}
         width={iconSize.lg}
         height={iconSize.lg}
+        alt={`${cleanedChainName(props.chain.name)} icon`}
       />
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx (2)

65-70: Make className optional in SwapWidgetContainer props.

It’s currently required but can be undefined.

-export function SwapWidgetContainer(props: {
-  theme: SwapWidgetProps["theme"];
-  className: string | undefined;
+export function SwapWidgetContainer(props: {
+  theme: SwapWidgetProps["theme"];
+  className?: string;

28-30: Type annotate useActiveWalletInfo() with the exported type.

Improves readability and avoids structural drift.

-import type { SwapWidgetConnectOptions } from "./types.js";
+import type { ActiveWalletInfo, SwapWidgetConnectOptions } from "./types.js";
-function useActiveWalletInfo() {
+function useActiveWalletInfo(): ActiveWalletInfo | undefined {

Also applies to: 266-280

packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx (3)

500-541: Add an accessible label to the switch button control.

-      <SwitchButtonInner
+      <SwitchButtonInner
+        aria-label="Swap selected tokens"
         variant="outline"
         onClick={(e) => {

435-467: Alt text for token/chain images.

-        <Img
+        <Img
           src={props.selectedToken.iconUri || ""}
           client={props.client}
           width={iconSize.lg}
           height={iconSize.lg}
+          alt={`${props.selectedToken.symbol} token icon`}
           style={{
             borderRadius: radius.full,
           }}
         />
...
-            <Img
+            <Img
               src={props.chain.icon}
               client={props.client}
               width={iconSize.sm}
               height={iconSize.sm}
+              alt={`${cleanedChainName(props.chain.name)} icon`}
               style={{
                 borderRadius: radius.full,
               }}
             />

Also applies to: 459-467


50-58: Explicit return types for exported components.

Keep function return types explicit for TSX per guidelines.

-export function SwapUI(props: SwapUIProps) {
+export function SwapUI(props: SwapUIProps): JSX.Element {
-export function SwapUIBase(
+export function SwapUIBase(
   props: SwapUIProps & { onSelectToken: (type: "buy" | "sell") => void },
-)
+) : JSX.Element
-function TokenSection(props: {
+function TokenSection(props: {
   ...
-}) {
+}): JSX.Element {

Also applies to: 98-101, 321-331

packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-buy-token.tsx (4)

34-39: Graceful default chain fallback when preferred chain not present

Defaulting to chainId 1 may return undefined if it’s not in the list. Fallback to first available.

-  return chains.find((chain) => chain.chainId === (activeChainId || 1));
+  return (
+    chains.find((chain) => chain.chainId === (activeChainId || 1)) ??
+    chains[0]
+  );

45-46: Right-size pagination: start smaller and increment predictably

limit=1000 is heavy for initial render. Start smaller and grow linearly to reduce query/render cost.

-  const [limit, setLimit] = useState(1000);
+  const [limit, setLimit] = useState(50);
@@
-        tokensQuery.data?.length === limit
+        tokensQuery.data?.length === limit
           ? () => {
-              setLimit(limit * 2);
+              setLimit(limit + 50);
             }
           : undefined

Also applies to: 95-99


175-183: Address comparison should be case-insensitive

Normalize both addresses to avoid false negatives.

-                    isSelected={props.selectedToken?.address === token.address}
+                    isSelected={
+                      props.selectedToken
+                        ? props.selectedToken.address.toLowerCase() ===
+                          token.address.toLowerCase()
+                        : false
+                    }

197-201: Add keys for skeleton rows

Prevents React diff churn even if lint is suppressed.

-                {props.isPending &&
-                  new Array(20).fill(0).map(() => (
-                    // biome-ignore lint/correctness/useJsxKeyInIterable: ok
-                    <TokenButtonSkeleton />
-                  ))}
+                {props.isPending &&
+                  new Array(20).fill(0).map((_, i) => (
+                    <TokenButtonSkeleton key={i} />
+                  ))}
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-sell-token.tsx (5)

41-46: Graceful default chain fallback when preferred chain not present

Mirror buy-side fix to avoid undefined default when chainId 1 isn’t available.

-  return chains.find((chain) => chain.chainId === (chainId || 1));
+  return (
+    chains.find((chain) => chain.chainId === (chainId || 1)) ?? chains[0]
+  );

247-276: Reuse shared SearchInput to remove duplicated markup

Use the shared SearchInput component for consistency and less DOM noise. Add the import and replace the inline block.

+import { SearchInput } from "./SearchInput.js";
-            <Container px="md">
-              <div
-                style={{
-                  position: "relative",
-                }}
-              >
-                <Container color="secondaryText">
-                  <MagnifyingGlassIcon
-                    width={iconSize.md}
-                    height={iconSize.md}
-                    style={{
-                      position: "absolute",
-                      left: spacing.sm,
-                      top: "50%",
-                      transform: "translateY(-50%)",
-                    }}
-                  />
-                </Container>
-
-                <Input
-                  variant="outline"
-                  placeholder="Search by Token or Address"
-                  value={props.search}
-                  style={{
-                    paddingLeft: "44px",
-                  }}
-                  onChange={(e) => props.setSearch(e.target.value)}
-                />
-              </div>
-            </Container>
+            <Container px="md">
+              <SearchInput
+                value={props.search}
+                onChange={props.setSearch}
+                placeholder="Search by Token or Address"
+              />
+            </Container>

Also applies to: 1-33


470-471: Use locale-aware currency formatting

Improves readability and i18n.

-            {usdValue < 0.01 ? "~$0.00" : `$${usdValue.toFixed(2)}`}
+            {usdValue < 0.01
+              ? "~$0.00"
+              : usdValue.toLocaleString(undefined, {
+                  style: "currency",
+                  currency: "USD",
+                  maximumFractionDigits: 2,
+                })}

281-289: Consider virtualization for long lists

Height-locked, scrollable lists of balances can render many rows; virtualize to keep perf smooth on slower devices.


319-323: Add keys for skeleton rows

Same nit as buy-side.

-                {props.isPending &&
-                  new Array(20).fill(0).map(() => (
-                    // biome-ignore lint/correctness/useJsxKeyInIterable: ok
-                    <TokenButtonSkeleton />
-                  ))}
+                {props.isPending &&
+                  new Array(20).fill(0).map((_, i) => (
+                    <TokenButtonSkeleton key={i} />
+                  ))}
📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between c82b606 and 50c1a19.

📒 Files selected for processing (31)
  • packages/thirdweb/package.json (1 hunks)
  • packages/thirdweb/src/bridge/types/Chain.ts (1 hunks)
  • packages/thirdweb/src/pay/convert/type.ts (1 hunks)
  • packages/thirdweb/src/react/core/design-system/index.ts (2 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/StepRunner.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/UnsupportedTokenScreen.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SelectChainButton.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-buy-token.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-chain.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-sell-token.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/types.ts (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-bridge-chains.ts (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/utils.ts (1 hunks)
  • packages/thirdweb/src/react/web/ui/ConnectWallet/icons/ArrowUpDownIcon.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/components/DynamicHeight.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/components/Img.tsx (5 hunks)
  • packages/thirdweb/src/react/web/ui/components/Skeleton.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/components/Spinner.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/components/basic.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/components/buttons.tsx (3 hunks)
  • packages/thirdweb/src/react/web/ui/components/formElements.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/components/text.tsx (2 hunks)
  • packages/thirdweb/src/stories/Bridge/Swap/SelectBuyToken.stories.tsx (1 hunks)
  • packages/thirdweb/src/stories/Bridge/Swap/SelectChain.stories.tsx (1 hunks)
  • packages/thirdweb/src/stories/Bridge/Swap/SelectSellToken.stories.tsx (1 hunks)
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx (1 hunks)
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from @/types where applicable
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size

Files:

  • packages/thirdweb/src/react/web/ui/components/Spinner.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/utils.ts
  • packages/thirdweb/src/react/web/ui/components/DynamicHeight.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SelectChainButton.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/UnsupportedTokenScreen.tsx
  • packages/thirdweb/src/react/web/ui/components/text.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-bridge-chains.ts
  • packages/thirdweb/src/react/web/ui/ConnectWallet/icons/ArrowUpDownIcon.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SelectBuyToken.stories.tsx
  • packages/thirdweb/src/react/web/ui/components/basic.tsx
  • packages/thirdweb/src/react/web/ui/components/Img.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SelectChain.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/StepRunner.tsx
  • packages/thirdweb/src/react/core/design-system/index.ts
  • packages/thirdweb/src/bridge/types/Chain.ts
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/types.ts
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx
  • packages/thirdweb/src/react/web/ui/components/formElements.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-chain.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SelectSellToken.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-sell-token.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-buy-token.tsx
  • packages/thirdweb/src/pay/convert/type.ts
  • packages/thirdweb/src/react/web/ui/components/buttons.tsx
  • packages/thirdweb/src/react/web/ui/components/Skeleton.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • packages/thirdweb/src/react/web/ui/components/Spinner.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/utils.ts
  • packages/thirdweb/src/react/web/ui/components/DynamicHeight.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SelectChainButton.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/UnsupportedTokenScreen.tsx
  • packages/thirdweb/src/react/web/ui/components/text.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-bridge-chains.ts
  • packages/thirdweb/src/react/web/ui/ConnectWallet/icons/ArrowUpDownIcon.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SelectBuyToken.stories.tsx
  • packages/thirdweb/src/react/web/ui/components/basic.tsx
  • packages/thirdweb/src/react/web/ui/components/Img.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SelectChain.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/StepRunner.tsx
  • packages/thirdweb/src/react/core/design-system/index.ts
  • packages/thirdweb/src/bridge/types/Chain.ts
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/types.ts
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx
  • packages/thirdweb/src/react/web/ui/components/formElements.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-chain.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SelectSellToken.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-sell-token.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-buy-token.tsx
  • packages/thirdweb/src/pay/convert/type.ts
  • packages/thirdweb/src/react/web/ui/components/buttons.tsx
  • packages/thirdweb/src/react/web/ui/components/Skeleton.tsx
packages/thirdweb/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

packages/thirdweb/**/*.{ts,tsx}: Every public symbol must have comprehensive TSDoc with at least one compiling @example and a custom tag (@beta, @internal, @experimental, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Lazy‑load heavy dependencies inside async paths (e.g., const { jsPDF } = await import("jspdf"))

Files:

  • packages/thirdweb/src/react/web/ui/components/Spinner.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/utils.ts
  • packages/thirdweb/src/react/web/ui/components/DynamicHeight.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SelectChainButton.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/UnsupportedTokenScreen.tsx
  • packages/thirdweb/src/react/web/ui/components/text.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-bridge-chains.ts
  • packages/thirdweb/src/react/web/ui/ConnectWallet/icons/ArrowUpDownIcon.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SelectBuyToken.stories.tsx
  • packages/thirdweb/src/react/web/ui/components/basic.tsx
  • packages/thirdweb/src/react/web/ui/components/Img.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SelectChain.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/StepRunner.tsx
  • packages/thirdweb/src/react/core/design-system/index.ts
  • packages/thirdweb/src/bridge/types/Chain.ts
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/types.ts
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx
  • packages/thirdweb/src/react/web/ui/components/formElements.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-chain.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SelectSellToken.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-sell-token.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-buy-token.tsx
  • packages/thirdweb/src/pay/convert/type.ts
  • packages/thirdweb/src/react/web/ui/components/buttons.tsx
  • packages/thirdweb/src/react/web/ui/components/Skeleton.tsx
**/*.stories.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

For new UI components, add Storybook stories (*.stories.tsx) alongside the code

Files:

  • packages/thirdweb/src/stories/Bridge/Swap/SelectBuyToken.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SelectChain.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SelectSellToken.stories.tsx
**/types.ts

📄 CodeRabbit inference engine (AGENTS.md)

Provide and re‑use local type barrels in a types.ts file

Files:

  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/types.ts
**/package.json

📄 CodeRabbit inference engine (AGENTS.md)

Track bundle budgets via package.json#size-limit

Files:

  • packages/thirdweb/package.json
🧠 Learnings (16)
📓 Common learnings
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Pull‑request titles must start with the affected workspace in brackets (e.g., [SDK], [Dashboard], [Portal], [Playground])
📚 Learning: 2025-07-02T20:04:53.982Z
Learnt from: MananTank
PR: thirdweb-dev/js#7505
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/webhook-metrics.tsx:40-40
Timestamp: 2025-07-02T20:04:53.982Z
Learning: The Spinner component imported from "@/components/ui/Spinner/Spinner" in the dashboard accepts a className prop, not a size prop. The correct usage is <Spinner className="size-4" />, not <Spinner size="sm" />. The component defaults to "size-4" if no className is provided.

Applied to files:

  • packages/thirdweb/src/react/web/ui/components/Spinner.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.

Applied to files:

  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-bridge-chains.ts
  • packages/thirdweb/src/react/web/ui/components/Img.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-bridge-chains.ts
  • packages/thirdweb/src/react/web/ui/components/Img.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Use React Query (`tanstack/react-query`) for all client data fetching.

Applied to files:

  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-bridge-chains.ts
📚 Learning: 2025-07-07T21:21:47.488Z
Learnt from: saminacodes
PR: thirdweb-dev/js#7543
File: apps/portal/src/app/pay/page.mdx:4-4
Timestamp: 2025-07-07T21:21:47.488Z
Learning: In the thirdweb-dev/js repository, lucide-react icons must be imported with the "Icon" suffix (e.g., ExternalLinkIcon, RocketIcon) as required by the new linting rule, contrary to the typical lucide-react convention of importing without the suffix.

Applied to files:

  • packages/thirdweb/src/react/web/ui/ConnectWallet/icons/ArrowUpDownIcon.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.stories.tsx : Add Storybook stories (`*.stories.tsx`) alongside new UI components

Applied to files:

  • packages/thirdweb/src/stories/Bridge/Swap/SelectBuyToken.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SelectChain.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SelectSellToken.stories.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.stories.tsx : For new UI components, add Storybook stories (`*.stories.tsx`) alongside the code

Applied to files:

  • packages/thirdweb/src/stories/Bridge/Swap/SelectBuyToken.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SelectChain.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SelectSellToken.stories.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/components/*.{stories,test}.{tsx,ts} : Provide a Storybook story (`MyComponent.stories.tsx`) or unit test alongside the component.

Applied to files:

  • packages/thirdweb/src/stories/Bridge/Swap/SelectBuyToken.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx
📚 Learning: 2025-05-29T10:49:52.981Z
Learnt from: MananTank
PR: thirdweb-dev/js#7177
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/ContractHeader.tsx:26-43
Timestamp: 2025-05-29T10:49:52.981Z
Learning: In React image components, conditional rendering of the entire image container (e.g., `{props.image && <Img />}`) serves a different purpose than fallback handling. The conditional prevents rendering any image UI when no image metadata exists, while the fallback prop handles cases where image metadata exists but the image fails to load. This pattern is intentional to distinguish between "no image intended" vs "image intended but failed to load".

Applied to files:

  • packages/thirdweb/src/react/web/ui/components/Img.tsx
📚 Learning: 2025-08-09T15:37:30.990Z
Learnt from: MananTank
PR: thirdweb-dev/js#7822
File: apps/dashboard/src/@/components/contracts/contract-card/contract-publisher.tsx:22-31
Timestamp: 2025-08-09T15:37:30.990Z
Learning: The Img component at apps/dashboard/src/@/components/blocks/Img.tsx properly handles empty string src values by immediately setting status to "fallback" and converting empty strings to undefined in the img element's src attribute, preventing unnecessary network requests.

Applied to files:

  • packages/thirdweb/src/react/web/ui/components/Img.tsx
📚 Learning: 2025-06-17T18:30:52.976Z
Learnt from: MananTank
PR: thirdweb-dev/js#7356
File: apps/nebula/src/app/not-found.tsx:1-1
Timestamp: 2025-06-17T18:30:52.976Z
Learning: In the thirdweb/js project, the React namespace is available for type annotations (like React.FC) without needing to explicitly import React. This is project-specific configuration that differs from typical TypeScript/React setups.

Applied to files:

  • packages/thirdweb/src/react/web/ui/components/Img.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to **/*.test.{ts,tsx} : Keep tests deterministic and side‑effect free; use Vitest

Applied to files:

  • packages/thirdweb/package.json
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.test.{ts,tsx} : Keep tests deterministic and side-effect free

Applied to files:

  • packages/thirdweb/package.json
📚 Learning: 2025-06-26T19:46:04.024Z
Learnt from: gregfromstl
PR: thirdweb-dev/js#7450
File: packages/thirdweb/src/bridge/Webhook.ts:57-81
Timestamp: 2025-06-26T19:46:04.024Z
Learning: In the onramp webhook schema (`packages/thirdweb/src/bridge/Webhook.ts`), the `currencyAmount` field is intentionally typed as `z.number()` while other amount fields use `z.string()` because `currencyAmount` represents fiat currency amounts in decimals (like $10.50), whereas other amount fields represent token amounts in wei (very large integers that benefit from bigint representation). The different naming convention (`currencyAmount` vs `amount`) reflects this intentional distinction.

Applied to files:

  • packages/thirdweb/src/pay/convert/type.ts
📚 Learning: 2025-08-28T19:32:53.229Z
Learnt from: MananTank
PR: thirdweb-dev/js#7939
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/step-card.tsx:50-60
Timestamp: 2025-08-28T19:32:53.229Z
Learning: The Button component in packages/ui/src/components/button.tsx has type="button" as the default when no type prop is explicitly provided. This means explicitly adding type="button" to Button components is redundant unless a different type (like "submit") is specifically needed.

Applied to files:

  • packages/thirdweb/src/react/web/ui/components/buttons.tsx
🧬 Code graph analysis (17)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SelectChainButton.tsx (5)
packages/thirdweb/src/bridge/types/Chain.ts (1)
  • BridgeChain (42-42)
packages/thirdweb/src/react/web/ui/components/buttons.tsx (1)
  • Button (26-157)
packages/thirdweb/src/react/core/design-system/index.ts (3)
  • fontSize (164-172)
  • spacing (174-185)
  • iconSize (197-206)
packages/thirdweb/src/react/web/ui/components/Img.tsx (1)
  • Img (12-126)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/utils.ts (1)
  • cleanedChainName (1-3)
packages/thirdweb/src/stories/Bridge/Swap/SelectBuyToken.stories.tsx (4)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-buy-token.tsx (2)
  • SelectBuyTokenUI (105-240)
  • SelectBuyToken (41-103)
packages/thirdweb/src/bridge/types/Chain.ts (1)
  • BridgeChain (42-42)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx (1)
  • SwapWidgetContainer (65-84)
packages/thirdweb/src/stories/utils.tsx (1)
  • storyClient (15-17)
packages/thirdweb/src/react/web/ui/components/Img.tsx (3)
packages/thirdweb/src/react/web/ui/components/Skeleton.tsx (1)
  • Skeleton (10-28)
packages/thirdweb/src/react/web/ui/components/basic.tsx (1)
  • Container (77-178)
packages/thirdweb/src/react/core/design-system/index.ts (1)
  • radius (187-195)
packages/thirdweb/src/stories/Bridge/Swap/SelectChain.stories.tsx (4)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-chain.tsx (2)
  • SelectBridgeChain (26-37)
  • SelectBridgeChainUI (39-118)
packages/thirdweb/src/bridge/types/Chain.ts (1)
  • BridgeChain (42-42)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx (1)
  • SwapWidgetContainer (65-84)
packages/thirdweb/src/stories/utils.tsx (1)
  • storyClient (15-17)
packages/thirdweb/src/react/web/ui/Bridge/StepRunner.tsx (1)
packages/thirdweb/src/react/web/ui/components/text.tsx (1)
  • Text (18-34)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/types.ts (2)
packages/thirdweb/src/wallets/types.ts (1)
  • AppMetadata (3-20)
packages/thirdweb/src/bridge/types/Chain.ts (1)
  • Chain (5-40)
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx (2)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx (1)
  • SwapWidget (45-63)
packages/thirdweb/src/stories/utils.tsx (1)
  • storyClient (15-17)
packages/thirdweb/src/stories/BuyWidget.stories.tsx (1)
packages/thirdweb/src/stories/utils.tsx (1)
  • storyClient (15-17)
packages/thirdweb/src/react/web/ui/components/formElements.tsx (1)
packages/thirdweb/src/react/core/design-system/index.ts (1)
  • Theme (49-96)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx (15)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/types.ts (2)
  • ActiveWalletInfo (137-141)
  • SwapWidgetConnectOptions (25-135)
packages/thirdweb/src/react/core/design-system/index.ts (5)
  • Theme (49-96)
  • radius (187-195)
  • fontSize (164-172)
  • spacing (174-185)
  • iconSize (197-206)
packages/thirdweb/src/pay/convert/type.ts (2)
  • SupportedFiatCurrency (27-27)
  • getFiatSymbol (29-34)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-buy-token.tsx (1)
  • SelectBuyToken (41-103)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-sell-token.tsx (1)
  • SelectSellToken (48-67)
packages/thirdweb/src/exports/utils.ts (2)
  • toUnits (39-39)
  • toTokens (39-39)
packages/thirdweb/src/react/web/ui/components/basic.tsx (1)
  • Container (77-178)
packages/thirdweb/src/react/web/ui/components/buttons.tsx (1)
  • Button (26-157)
packages/thirdweb/src/react/web/ui/components/formElements.tsx (1)
  • Input (36-106)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-bridge-chains.ts (1)
  • useBridgeChains (5-12)
packages/thirdweb/src/react/web/ui/components/text.tsx (1)
  • Text (18-34)
packages/thirdweb/src/react/web/ui/components/Skeleton.tsx (1)
  • Skeleton (10-28)
packages/thirdweb/src/react/web/ui/components/Img.tsx (1)
  • Img (12-126)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/utils.ts (1)
  • cleanedChainName (1-3)
packages/thirdweb/src/react/web/ui/ConnectWallet/icons/ArrowUpDownIcon.tsx (1)
  • ArrowUpDownIcon (3-23)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts (1)
packages/thirdweb/src/exports/utils.ts (1)
  • isAddress (148-148)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx (3)
packages/thirdweb/src/react/web/ui/components/basic.tsx (1)
  • Container (77-178)
packages/thirdweb/src/react/core/design-system/index.ts (2)
  • iconSize (197-206)
  • spacing (174-185)
packages/thirdweb/src/react/web/ui/components/formElements.tsx (1)
  • Input (36-106)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-chain.tsx (10)
packages/thirdweb/src/bridge/types/Chain.ts (1)
  • BridgeChain (42-42)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-bridge-chains.ts (1)
  • useBridgeChains (5-12)
packages/thirdweb/src/react/web/ui/components/basic.tsx (3)
  • Container (77-178)
  • ModalHeader (35-65)
  • Line (67-72)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx (1)
  • SearchInput (6-41)
packages/thirdweb/src/react/core/design-system/index.ts (3)
  • spacing (174-185)
  • iconSize (197-206)
  • fontSize (164-172)
packages/thirdweb/src/react/web/ui/components/text.tsx (1)
  • Text (18-34)
packages/thirdweb/src/react/web/ui/components/Skeleton.tsx (1)
  • Skeleton (10-28)
packages/thirdweb/src/react/web/ui/components/buttons.tsx (1)
  • Button (26-157)
packages/thirdweb/src/react/web/ui/components/Img.tsx (1)
  • Img (12-126)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/utils.ts (1)
  • cleanedChainName (1-3)
packages/thirdweb/src/stories/Bridge/Swap/SelectSellToken.stories.tsx (4)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-sell-token.tsx (3)
  • SelectSellToken (48-67)
  • SelectSellTokenConnectedUI (190-362)
  • SelectSellTokenDisconnectedUI (69-120)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/types.ts (1)
  • ActiveWalletInfo (137-141)
packages/thirdweb/src/stories/utils.tsx (1)
  • storyClient (15-17)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx (1)
  • SwapWidgetContainer (65-84)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-sell-token.tsx (12)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/types.ts (1)
  • ActiveWalletInfo (137-141)
packages/thirdweb/src/react/web/ui/components/basic.tsx (3)
  • Container (77-178)
  • ModalHeader (35-65)
  • Line (67-72)
packages/thirdweb/src/react/core/design-system/index.ts (4)
  • radius (187-195)
  • iconSize (197-206)
  • spacing (174-185)
  • fontSize (164-172)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-bridge-chains.ts (1)
  • useBridgeChains (5-12)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts (2)
  • useTokenBalances (71-115)
  • TokenBalance (39-57)
packages/thirdweb/src/react/web/ui/components/Spinner.tsx (1)
  • Spinner (11-36)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SelectChainButton.tsx (1)
  • SelectChainButton (13-47)
packages/thirdweb/src/react/web/ui/components/formElements.tsx (1)
  • Input (36-106)
packages/thirdweb/src/react/web/ui/components/buttons.tsx (1)
  • Button (26-157)
packages/thirdweb/src/pay/convert/get-token.ts (1)
  • getToken (6-37)
packages/thirdweb/src/react/web/ui/components/Img.tsx (1)
  • Img (12-126)
packages/thirdweb/src/react/web/ui/components/Skeleton.tsx (1)
  • Skeleton (10-28)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx (15)
packages/thirdweb/src/react/core/design-system/index.ts (1)
  • Theme (49-96)
packages/thirdweb/src/pay/convert/type.ts (1)
  • SupportedFiatCurrency (27-27)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/types.ts (1)
  • SwapWidgetConnectOptions (25-135)
packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectEmbed.tsx (1)
  • EmbedContainer (441-466)
packages/thirdweb/src/react/web/ui/components/DynamicHeight.tsx (1)
  • DynamicHeight (8-33)
packages/thirdweb/src/react/core/hooks/useBridgePrepare.ts (2)
  • BridgePrepareResult (23-27)
  • BridgePrepareRequest (14-18)
packages/thirdweb/src/react/web/ui/ConnectWallet/locale/getConnectLocale.ts (1)
  • useConnectLocale (45-54)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-bridge-chains.ts (1)
  • useBridgeChains (5-12)
packages/thirdweb/src/react/web/ui/components/Spinner.tsx (1)
  • Spinner (11-36)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx (1)
  • SwapUI (50-96)
packages/thirdweb/src/react/web/ui/Bridge/QuoteLoader.tsx (1)
  • QuoteLoader (87-173)
packages/thirdweb/src/exports/utils.ts (1)
  • toTokens (39-39)
packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx (1)
  • PaymentDetails (57-398)
packages/thirdweb/src/react/web/ui/Bridge/StepRunner.tsx (1)
  • StepRunner (66-404)
packages/thirdweb/src/react/web/adapters/WindowAdapter.ts (1)
  • webWindowAdapter (23-23)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-buy-token.tsx (13)
packages/thirdweb/src/bridge/types/Chain.ts (1)
  • BridgeChain (42-42)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-bridge-chains.ts (1)
  • useBridgeChains (5-12)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts (1)
  • useTokens (7-37)
packages/thirdweb/src/react/web/ui/components/basic.tsx (3)
  • Container (77-178)
  • ModalHeader (35-65)
  • Line (67-72)
packages/thirdweb/src/react/web/ui/components/Spinner.tsx (1)
  • Spinner (11-36)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SelectChainButton.tsx (1)
  • SelectChainButton (13-47)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx (1)
  • SearchInput (6-41)
packages/thirdweb/src/react/core/design-system/index.ts (4)
  • radius (187-195)
  • spacing (174-185)
  • fontSize (164-172)
  • iconSize (197-206)
packages/thirdweb/src/react/web/ui/components/buttons.tsx (1)
  • Button (26-157)
packages/thirdweb/src/react/web/ui/components/text.tsx (1)
  • Text (18-34)
packages/thirdweb/src/pay/convert/get-token.ts (1)
  • getToken (6-37)
packages/thirdweb/src/react/web/ui/components/Img.tsx (1)
  • Img (12-126)
packages/thirdweb/src/react/web/ui/components/Skeleton.tsx (1)
  • Skeleton (10-28)
🪛 Gitleaks (8.27.2)
packages/thirdweb/src/stories/BuyWidget.stories.tsx

[high] 31-31: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

⏰ 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). (9)
  • GitHub Check: Size
  • 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: Build Packages
  • GitHub Check: Socket Security: Pull Request Alerts
  • GitHub Check: Analyze (javascript)

Comment on lines 29 to 34
export function getFiatSymbol(showBalanceInFiat: SupportedFiatCurrency) {
switch (showBalanceInFiat) {
case "USD":
return "$";
case "CAD":
return "$";
case "GBP":
return "£";
case "EUR":
return "€";
case "JPY":
return "¥";
case "AUD":
return "$";
case "NZD":
return "$";
default:
return "$";
if (currencySymbol[showBalanceInFiat]) {
return currencySymbol[showBalanceInFiat];
}
return "$";
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Type-safety bug: fallback is ill-typed and may be optimized away

currencySymbol is Record<SupportedFiatCurrency, string>. Since SupportedFiatCurrency includes string & {}, the index signature becomes Record<string, string>, making currencySymbol[showBalanceInFiat] always typed as string (truthy), so the $ fallback is effectively dead by type, risking misuse elsewhere.

-export function getFiatSymbol(showBalanceInFiat: SupportedFiatCurrency) {
-  if (currencySymbol[showBalanceInFiat]) {
-    return currencySymbol[showBalanceInFiat];
-  }
-  return "$";
-}
+export function getFiatSymbol(showBalanceInFiat: SupportedFiatCurrency): string {
+  const symbol =
+    currencySymbol[
+      showBalanceInFiat as (typeof CURRENCIES)[number]
+    ];
+  return symbol ?? "$";
+}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/thirdweb/src/pay/convert/type.ts around lines 29 to 34, the fallback
"$" is effectively dead because currencySymbol is typed as
Record<SupportedFiatCurrency, string> which (due to SupportedFiatCurrency
including string) makes the index always typed as string; fix by making the
lookup actually nullable/guarded and the mapping type narrower: change
currencySymbol's type to Partial<Record<SupportedFiatCurrency, string>> (or a
stricter literal-keyed type), then use an explicit undefined check or the
nullish coalescing operator to return currencySymbol[showBalanceInFiat] ?? "$"
(or use Object.prototype.hasOwnProperty.call(currencySymbol, showBalanceInFiat)
before returning) so the fallback can never be optimized away by the type
system.

Comment on lines +36 to +60
const currencySymbol: Record<SupportedFiatCurrency, string> = {
USD: "$",
EUR: "€",
GBP: "£",
JPY: "¥",
KRW: "₩",
CNY: "¥",
INR: "₹",
NOK: "kr",
SEK: "kr",
CHF: "CHF",
AUD: "$",
CAD: "$",
NZD: "$",
MXN: "$",
BRL: "R$",
CLP: "$",
CZK: "Kč",
DKK: "kr",
HKD: "$",
HUF: "Ft",
IDR: "Rp",
ILS: "₪",
ISK: "kr",
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Retype currencySymbol to cover only known codes

Scope the map to known CURRENCIES; keep it internal.

-const currencySymbol: Record<SupportedFiatCurrency, string> = {
+/**
+ * @internal
+ */
+const currencySymbol: Partial<Record<(typeof CURRENCIES)[number], string>> = {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const currencySymbol: Record<SupportedFiatCurrency, string> = {
USD: "$",
EUR: "€",
GBP: "£",
JPY: "¥",
KRW: "₩",
CNY: "¥",
INR: "₹",
NOK: "kr",
SEK: "kr",
CHF: "CHF",
AUD: "$",
CAD: "$",
NZD: "$",
MXN: "$",
BRL: "R$",
CLP: "$",
CZK: "Kč",
DKK: "kr",
HKD: "$",
HUF: "Ft",
IDR: "Rp",
ILS: "₪",
ISK: "kr",
};
/**
* @internal
*/
const currencySymbol: Partial<Record<(typeof CURRENCIES)[number], string>> = {
USD: "$",
EUR: "€",
GBP: "£",
JPY: "¥",
KRW: "₩",
CNY: "¥",
INR: "₹",
NOK: "kr",
SEK: "kr",
CHF: "CHF",
AUD: "$",
CAD: "$",
NZD: "$",
MXN: "$",
BRL: "R$",
CLP: "$",
CZK: "Kč",
DKK: "kr",
HKD: "$",
HUF: "Ft",
IDR: "Rp",
ILS: "₪",
ISK: "kr",
};

Comment on lines +41 to +46
export function SelectBuyToken(props: SelectBuyTokenProps) {
const activeChain = useActiveWalletChain();
const chainQuery = useBridgeChains(props.client);
const [search, setSearch] = useState("");
const [limit, setLimit] = useState(1000);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add TSDoc and explicit return types for exported components (SDK public API requirement)

Public symbols under packages/thirdweb must include TSDoc (with @example and a custom tag) and explicit return types.

-export function SelectBuyToken(props: SelectBuyTokenProps) {
+/**
+ * Select a token to buy on the chosen bridge chain.
+ * @example
+ * <SelectBuyToken onBack={() => {}} client={client} selectedToken={token} setSelectedToken={setToken} />
+ * @beta
+ */
+export function SelectBuyToken(props: SelectBuyTokenProps): JSX.Element {
   …
 }
 
-export function SelectBuyTokenUI(
+/**
+ * Presentational UI for SelectBuyToken when data/state is managed externally.
+ * @example
+ * <SelectBuyTokenUI {...props} />
+ * @beta
+ */
+export function SelectBuyTokenUI(
   props: SelectBuyTokenProps & {
     tokens: Token[];
     isPending: boolean;
     selectedChain: BridgeChain | undefined;
     setSelectedChain: (chain: BridgeChain) => void;
     search: string;
     setSearch: (search: string) => void;
     selectedToken: TokenWithPrices | undefined;
     setSelectedToken: (token: TokenWithPrices) => void;
     showMore: (() => void) | undefined;
   },
-) {
+): JSX.Element | null {

Also applies to: 105-117

🤖 Prompt for AI Agents
In packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-buy-token.tsx
around lines 41-46 (and also update the exported component occurrences at lines
105-117), the exported React component is missing TSDoc and an explicit return
type required by the SDK public API. Add a TSDoc block above the exported
function including a short description, an @example showing basic usage, and the
required custom tag (e.g., @thirdweb), then declare the function return type
explicitly as JSX.Element (or React.ReactElement) in its signature; apply the
same pattern to the other exported component(s) at lines 105-117. Ensure imports
already provide React types if needed.

Comment on lines +250 to +274
<Button
variant={props.isSelected ? "secondary" : "ghost-solid"}
fullWidth
style={{
justifyContent: "flex-start",
fontWeight: 500,
fontSize: fontSize.md,
border: "1px solid transparent",
padding: `${spacing.sm} ${spacing.sm}`,
textAlign: "left",
lineHeight: "1.5",
height: "70px",
}}
gap="sm"
onClick={async () => {
setIsLoading(true);
const tokenWithPrices = await getToken(
props.client,
props.token.address,
props.token.chainId,
);
setIsLoading(false);
props.onSelect(tokenWithPrices);
}}
>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix stuck-loading and unhandled errors on token fetch; also disable while loading

getToken can throw; isLoading never resets and the button stays interactive. Wrap in try/catch/finally, gate re-entrancy, and reflect state via disabled/aria.

-    <Button
+    <Button
+      disabled={isLoading}
+      aria-busy={isLoading}
+      aria-selected={props.isSelected}
       variant={props.isSelected ? "secondary" : "ghost-solid"}
       fullWidth
@@
-      onClick={async () => {
-        setIsLoading(true);
-        const tokenWithPrices = await getToken(
-          props.client,
-          props.token.address,
-          props.token.chainId,
-        );
-        setIsLoading(false);
-        props.onSelect(tokenWithPrices);
-      }}
+      onClick={async () => {
+        if (isLoading) return;
+        setIsLoading(true);
+        try {
+          const tokenWithPrices = await getToken(
+            props.client,
+            props.token.address,
+            props.token.chainId,
+          );
+          props.onSelect(tokenWithPrices);
+        } catch (e) {
+          console.error("Failed to load token", e);
+          // TODO: surface a user-visible error/toast
+        } finally {
+          setIsLoading(false);
+        }
+      }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Button
variant={props.isSelected ? "secondary" : "ghost-solid"}
fullWidth
style={{
justifyContent: "flex-start",
fontWeight: 500,
fontSize: fontSize.md,
border: "1px solid transparent",
padding: `${spacing.sm} ${spacing.sm}`,
textAlign: "left",
lineHeight: "1.5",
height: "70px",
}}
gap="sm"
onClick={async () => {
setIsLoading(true);
const tokenWithPrices = await getToken(
props.client,
props.token.address,
props.token.chainId,
);
setIsLoading(false);
props.onSelect(tokenWithPrices);
}}
>
<Button
disabled={isLoading}
aria-busy={isLoading}
aria-selected={props.isSelected}
variant={props.isSelected ? "secondary" : "ghost-solid"}
fullWidth
style={{
justifyContent: "flex-start",
fontWeight: 500,
fontSize: fontSize.md,
border: "1px solid transparent",
padding: `${spacing.sm} ${spacing.sm}`,
textAlign: "left",
lineHeight: "1.5",
height: "70px",
}}
gap="sm"
onClick={async () => {
if (isLoading) return;
setIsLoading(true);
try {
const tokenWithPrices = await getToken(
props.client,
props.token.address,
props.token.chainId,
);
props.onSelect(tokenWithPrices);
} catch (e) {
console.error("Failed to load token", e);
// TODO: surface a user-visible error/toast
} finally {
setIsLoading(false);
}
}}
>
🤖 Prompt for AI Agents
In packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-buy-token.tsx
around lines 250–274, the onClick handler can throw and leaves isLoading true
while the button remains interactive; wrap the async logic in a
re-entrancy-guarded try/catch/finally: return early if already loading,
setIsLoading(true) before awaiting getToken, catch and handle/log the error, and
setIsLoading(false) in finally so loading always clears; also pass
disabled={isLoading} and aria-busy={isLoading} to the Button to prevent
interaction and expose state to assistive tech.

Comment on lines +136 to +165
export function ChainButton(props: {
chain: BridgeChain;
client: ThirdwebClient;
onClick: () => void;
isSelected: boolean;
}) {
return (
<Button
variant={props.isSelected ? "secondary" : "ghost-solid"}
fullWidth
style={{
justifyContent: "flex-start",
fontWeight: 500,
fontSize: fontSize.md,
border: "1px solid transparent",
padding: `${spacing.sm} ${spacing.sm}`,
}}
gap="sm"
onClick={props.onClick}
>
<Img
src={props.chain.icon}
client={props.client}
width={iconSize.lg}
height={iconSize.lg}
/>
{cleanedChainName(props.chain.name)}
</Button>
);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Missing TSDoc for exported UI components.

Public exports (SelectBridgeChain, SelectBridgeChainUI, ChainButton) need TSDoc with an @beta/@internal tag and a minimal example.

🤖 Prompt for AI Agents
In packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-chain.tsx around
lines 136 to 165, the exported UI component ChainButton (and sibling exports
SelectBridgeChain and SelectBridgeChainUI) lack TSDoc; add a brief TSDoc block
above each exported component including a one-line description, a @beta or
@internal tag as appropriate, and a minimal usage example showing required props
(e.g., chain, client, isSelected, onClick). Keep the comments concise, use
consistent formatting with other files in the package, and ensure the examples
compile/type-check with current prop types.

Comment on lines +14 to +16
return useQuery<Token[]>({
queryKey: ["tokens", options],
enabled: !!options.chainId,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Stabilize/serialize queryKey

Avoid placing the full options object (and non-serializable client) in the key; include primitives only.

-  return useQuery<Token[]>({
-    queryKey: ["tokens", options],
+  return useQuery<Token[]>({
+    queryKey: [
+      "tokens",
+      options.client.clientId,
+      options.chainId ?? null,
+      (options.search ?? "").toLowerCase(),
+      options.offset,
+      options.limit,
+    ],
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return useQuery<Token[]>({
queryKey: ["tokens", options],
enabled: !!options.chainId,
return useQuery<Token[]>({
queryKey: [
"tokens",
options.client.clientId,
options.chainId ?? null,
(options.search ?? "").toLowerCase(),
options.offset,
options.limit,
],
enabled: !!options.chainId,
🤖 Prompt for AI Agents
In packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts around
lines 14–16, the queryKey currently includes the full options object (which may
contain non-serializable client instances) — replace it with a stable,
serializable key composed only of primitive values from options (e.g.,
options.chainId and any other relevant filter/search/page primitives) or a
deterministic string like JSON.stringify(pick(options,
['chainId','search','page'])) to ensure stability and avoid embedding
non-serializable objects in the key.

Comment on lines +39 to +57
export type TokenBalance = {
balance: string;
chain_id: number;
decimals: 1;
name: string;
icon_uri: string;
price_data: {
circulating_supply: number;
market_cap_usd: number;
percent_change_24h: number;
price_timestamp: string;
price_usd: number;
total_supply: number;
usd_value: number;
volume_24h_usd: number;
};
symbol: string;
token_address: string;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect literal type for decimals

decimals: 1 makes the field literally type 1. It must be number.

 export type TokenBalance = {
   balance: string;
   chain_id: number;
-  decimals: 1;
+  decimals: number;
   name: string;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export type TokenBalance = {
balance: string;
chain_id: number;
decimals: 1;
name: string;
icon_uri: string;
price_data: {
circulating_supply: number;
market_cap_usd: number;
percent_change_24h: number;
price_timestamp: string;
price_usd: number;
total_supply: number;
usd_value: number;
volume_24h_usd: number;
};
symbol: string;
token_address: string;
};
export type TokenBalance = {
balance: string;
chain_id: number;
decimals: number;
name: string;
icon_uri: string;
price_data: {
circulating_supply: number;
market_cap_usd: number;
percent_change_24h: number;
price_timestamp: string;
price_usd: number;
total_supply: number;
usd_value: number;
volume_24h_usd: number;
};
symbol: string;
token_address: string;
};
🤖 Prompt for AI Agents
In packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts around
lines 39 to 57, the TokenBalance type incorrectly declares decimals as the
literal type `1`; change the type to `number` (i.e., `decimals: number`) so
decimals can represent any numeric precision and update any related type
imports/usages if necessary to reflect the widened type.

Comment on lines +71 to +115
export function useTokenBalances(options: {
clientId: string;
page: number;
limit: number;
walletAddress: string;
chainId: number | undefined;
}) {
return useQuery({
queryKey: ["bridge/v1/wallets", options],
enabled: !!options.chainId,
queryFn: async () => {
if (!options.chainId) {
throw new Error("Chain ID is required");
}
const url = new URL(
`https://api.thirdweb.com/v1/wallets/${options.walletAddress}/tokens`,
);
url.searchParams.set("chainId", options.chainId.toString());
url.searchParams.set("limit", options.limit.toString());
url.searchParams.set("page", options.page.toString());
url.searchParams.set("metadata", "true");
url.searchParams.set("resolveMetadataLinks", "true");
url.searchParams.set("includeSpam", "false");
url.searchParams.set("includeNative", "true");
url.searchParams.set("sortBy", "usd_value");
url.searchParams.set("sortOrder", "desc");
url.searchParams.set("includeWithoutPrice", "false"); // filter out tokens with no price

const response = await fetch(url.toString(), {
headers: {
"x-client-id": options.clientId,
},
});

if (!response.ok) {
throw new Error(
`Failed to fetch token balances: ${response.statusText}`,
);
}

const json = (await response.json()) as TokenBalancesResponse;
return json.result;
},
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Harden balances query: key, enable, and abort

  • Include only primitives in queryKey.
  • Guard on walletAddress presence.
  • Plumb AbortSignal to fetch to support cancellations.
-export function useTokenBalances(options: {
+export function useTokenBalances(options: {
   clientId: string;
   page: number;
   limit: number;
   walletAddress: string;
   chainId: number | undefined;
 }) {
-  return useQuery({
-    queryKey: ["bridge/v1/wallets", options],
-    enabled: !!options.chainId,
-    queryFn: async () => {
+  return useQuery({
+    queryKey: [
+      "bridge/v1/wallets/tokens",
+      options.clientId,
+      options.walletAddress.toLowerCase(),
+      options.chainId ?? null,
+      options.page,
+      options.limit,
+    ],
+    enabled: !!options.chainId && !!options.walletAddress,
+    queryFn: async ({ signal }) => {
       if (!options.chainId) {
         throw new Error("Chain ID is required");
       }
       const url = new URL(
         `https://api.thirdweb.com/v1/wallets/${options.walletAddress}/tokens`,
       );
@@
-      const response = await fetch(url.toString(), {
+      const response = await fetch(url.toString(), {
+        signal,
         headers: {
           "x-client-id": options.clientId,
         },
       });
@@
-      const json = (await response.json()) as TokenBalancesResponse;
-      return json.result;
+      const json = (await response.json()) as TokenBalancesResponse;
+      return json.result;
     },
   });
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function useTokenBalances(options: {
clientId: string;
page: number;
limit: number;
walletAddress: string;
chainId: number | undefined;
}) {
return useQuery({
queryKey: ["bridge/v1/wallets", options],
enabled: !!options.chainId,
queryFn: async () => {
if (!options.chainId) {
throw new Error("Chain ID is required");
}
const url = new URL(
`https://api.thirdweb.com/v1/wallets/${options.walletAddress}/tokens`,
);
url.searchParams.set("chainId", options.chainId.toString());
url.searchParams.set("limit", options.limit.toString());
url.searchParams.set("page", options.page.toString());
url.searchParams.set("metadata", "true");
url.searchParams.set("resolveMetadataLinks", "true");
url.searchParams.set("includeSpam", "false");
url.searchParams.set("includeNative", "true");
url.searchParams.set("sortBy", "usd_value");
url.searchParams.set("sortOrder", "desc");
url.searchParams.set("includeWithoutPrice", "false"); // filter out tokens with no price
const response = await fetch(url.toString(), {
headers: {
"x-client-id": options.clientId,
},
});
if (!response.ok) {
throw new Error(
`Failed to fetch token balances: ${response.statusText}`,
);
}
const json = (await response.json()) as TokenBalancesResponse;
return json.result;
},
});
}
export function useTokenBalances(options: {
clientId: string;
page: number;
limit: number;
walletAddress: string;
chainId: number | undefined;
}) {
return useQuery({
queryKey: [
"bridge/v1/wallets/tokens",
options.clientId,
options.walletAddress.toLowerCase(),
options.chainId ?? null,
options.page,
options.limit,
],
enabled: !!options.chainId && !!options.walletAddress,
queryFn: async ({ signal }) => {
if (!options.chainId) {
throw new Error("Chain ID is required");
}
const url = new URL(
`https://api.thirdweb.com/v1/wallets/${options.walletAddress}/tokens`,
);
url.searchParams.set("chainId", options.chainId.toString());
url.searchParams.set("limit", options.limit.toString());
url.searchParams.set("page", options.page.toString());
url.searchParams.set("metadata", "true");
url.searchParams.set("resolveMetadataLinks", "true");
url.searchParams.set("includeSpam", "false");
url.searchParams.set("includeNative", "true");
url.searchParams.set("sortBy", "usd_value");
url.searchParams.set("sortOrder", "desc");
url.searchParams.set("includeWithoutPrice", "false"); // filter out tokens with no price
const response = await fetch(url.toString(), {
signal,
headers: {
"x-client-id": options.clientId,
},
});
if (!response.ok) {
throw new Error(
`Failed to fetch token balances: ${response.statusText}`,
);
}
const json = (await response.json()) as TokenBalancesResponse;
return json.result;
},
});
}
🤖 Prompt for AI Agents
In packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts around
lines 71 to 115, the query needs hardening: replace the complex object in
queryKey with only primitives (e.g. ["bridge/v1/wallets", clientId,
walletAddress, chainId, page, limit]), change enabled to require both chainId
and walletAddress (e.g. Boolean(options.chainId && options.walletAddress)),
guard early in queryFn to throw or return if walletAddress is missing, and
accept the react-query context signal (queryFn: async ({ signal }) => { ... })
and pass that AbortSignal into fetch options so the request can be cancelled.

@@ -2,6 +2,8 @@
import { useState } from "react";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Reset status on src changes to avoid stale “loaded” state

When src changes, status can remain “loaded”, suppressing skeleton. Reset to “pending” for non-empty src.

-import { useState } from "react";
+import { useEffect, useState } from "react";
@@
   const propSrc = props.src;
+  useEffect(() => {
+    if (propSrc) {
+      setStatus("pending");
+    }
+  }, [propSrc]);

Also applies to: 35-36

🤖 Prompt for AI Agents
In packages/thirdweb/src/react/web/ui/components/Img.tsx around line 2 (and also
apply to lines 35-36), the component keeps a stale "loaded" status when the src
prop changes; update the component to reset status to "pending" whenever the src
prop changes to a non-empty value. Implement a useEffect that watches src and,
if src is truthy and different from previous value, sets status to "pending" (do
the same reset where status is managed on lines 35-36), ensuring the skeleton
shows for the new image load.

Comment on lines +8 to +13
import {
type SelectSellToken,
SelectSellTokenConnectedUI,
SelectSellTokenDisconnectedUI,
} from "../../../react/web/ui/Bridge/swap-widget/select-sell-token.js";
import type { ActiveWalletInfo } from "../../../react/web/ui/Bridge/swap-widget/types.js";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Type-only import breaks Meta.

You’re using the type-imported SelectSellToken in a value position (typeof). Import the value.

-import {
-  type SelectSellToken,
-  SelectSellTokenConnectedUI,
-  SelectSellTokenDisconnectedUI,
-} from "../../../react/web/ui/Bridge/swap-widget/select-sell-token.js";
+import {
+  SelectSellToken,
+  SelectSellTokenConnectedUI,
+  SelectSellTokenDisconnectedUI,
+} from "../../../react/web/ui/Bridge/swap-widget/select-sell-token.js";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import {
type SelectSellToken,
SelectSellTokenConnectedUI,
SelectSellTokenDisconnectedUI,
} from "../../../react/web/ui/Bridge/swap-widget/select-sell-token.js";
import type { ActiveWalletInfo } from "../../../react/web/ui/Bridge/swap-widget/types.js";
import {
SelectSellToken,
SelectSellTokenConnectedUI,
SelectSellTokenDisconnectedUI,
} from "../../../react/web/ui/Bridge/swap-widget/select-sell-token.js";
import type { ActiveWalletInfo } from "../../../react/web/ui/Bridge/swap-widget/types.js";
🤖 Prompt for AI Agents
In packages/thirdweb/src/stories/Bridge/Swap/SelectSellToken.stories.tsx around
lines 8 to 13, the SelectSellToken is imported as a type-only import but later
used in a value position (typeof SelectSellToken) which breaks Meta<typeof
SelectSellToken>; change the import so SelectSellToken is imported as a runtime
value (remove the "type" keyword) from
"../../../react/web/ui/Bridge/swap-widget/select-sell-token.js" while keeping
the other imports intact so Meta<typeof SelectSellToken> resolves correctly.

}

const currencySymbol: Record<SupportedFiatCurrency, string> = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we actually use this? i think we can just use the built in currency formatter no?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
packages SDK Involves changes to the thirdweb SDK
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants