Skip to content

Conversation

MananTank
Copy link
Member

@MananTank MananTank commented Oct 16, 2025


PR-Codex overview

This PR enhances the user experience by adding autofocus functionality to token search inputs across various components, ensuring that users can quickly start searching for tokens when the respective modals open.

Detailed summary

  • Added autoFocus to token search inputs in BuyWidget, SwapWidget, and BridgeWidget.
  • Modified Modal component to include autoFocusCrossIcon prop.
  • Updated SearchInput component to accept autoFocus prop.
  • Refactored stories for SwapWidget and BridgeWidgetScript to use a Variant component for consistent styling.

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

Summary by CodeRabbit

  • New Features

    • Token search input now auto-focuses on desktop when opening token selector modals in Buy, Swap, and Bridge widgets.
    • Modals gain a configurable option to control initial focus of the close (cross) button.
  • Bug Fixes / UX

    • Prevents the close icon from stealing focus by default when configured, improving keyboard and screen‑reader navigation.
  • Chores

    • Storybook examples updated to show consistent light/dark variants and adjusted layout metadata.

Copy link

linear bot commented Oct 16, 2025

Copy link

vercel bot commented Oct 16, 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 Oct 17, 2025 2:48pm
nebula Ready Ready Preview Comment Oct 17, 2025 2:48pm
thirdweb_playground Ready Ready Preview Comment Oct 17, 2025 2:48pm
thirdweb-www Ready Ready Preview Comment Oct 17, 2025 2:48pm
wallet-ui Ready Ready Preview Comment Oct 17, 2025 2:48pm

Copy link

changeset-bot bot commented Oct 16, 2025

🦋 Changeset detected

Latest commit: 5ff6063

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
thirdweb Patch
@thirdweb-dev/nebula Patch
@thirdweb-dev/wagmi-adapter Patch
wagmi-inapp Patch

Not sure what this means? Click here to learn what changesets are.

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

@github-actions github-actions bot added packages SDK Involves changes to the thirdweb SDK labels Oct 16, 2025
@MananTank MananTank marked this pull request as ready for review October 16, 2025 17:05
@MananTank MananTank requested review from a team as code owners October 16, 2025 17:05
Copy link
Member Author

MananTank commented Oct 16, 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.

This stack of pull requests is managed by Graphite. Learn more about stacking.

Copy link
Contributor

coderabbitai bot commented Oct 16, 2025

Walkthrough

Adds autoFocusCrossIcon prop to Modal, exposes autoFocus on SearchInput, enables desktop-only autofocus for token search inputs, updates token-selector modals to disable cross-icon autofocus, and refactors several stories to use internal Variant wrappers and remove centered layout metadata.

Changes

Cohort / File(s) Summary
Modal prop & Close button
packages/thirdweb/src/react/web/ui/components/Modal.tsx
Added autoFocusCrossIcon?: boolean to Modal props; Close IconButton autoFocus now respects this prop (defaults to previous behavior when undefined).
SearchInput prop
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx
Added optional autoFocus?: boolean prop and forwarded it to the underlying Input.
Token selector integrations
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-token-ui.tsx, packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx, packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx
SearchInput now receives autoFocus={!props.isMobile} (desktop-only autofocus). FundWallet and SwapUI pass autoFocusCrossIcon={false} to Modal.
Storybook: Variant wrappers & metadata
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx, packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx, packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx
Stories now render an internal Variant component that shows dark/light instances; removed parameters: { layout: "centered" } and adjusted imports to include newly exported types where applicable.
BuyWidget story layout tweak
packages/thirdweb/src/stories/BuyWidget.stories.tsx
Removed parameters: { layout: "centered" } from meta; updated internal Variant wrapper to align contents via inline style.
Changeset
.changeset/happy-trees-doubt.md
Added changeset documenting the autofocus behavior change for token search inputs on desktop.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant SelectTokenUI
    participant Modal
    participant SearchInput
    participant Input

    User->>SelectTokenUI: Open token selector (desktop)
    SelectTokenUI->>Modal: render Modal (autoFocusCrossIcon=false)
    Note right of Modal #ffd6a5: Close icon will not auto-focus
    Modal->>SearchInput: render SearchInput (autoFocus=true)
    SearchInput->>Input: set autoFocus=true
    Input->>User: focus placed on search field
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The PR includes changes beyond the stated objective of adding autofocus to token search inputs. Specifically, multiple story files (bridge-widget-script.stories.tsx, SwapWidget.Prefill.stories.tsx, SwapWidget.stories.tsx, and BuyWidget.stories.tsx) were refactored to introduce a new Variant wrapper component for rendering theme variants (dark/light), and layout parameters were removed from story metadata. While the autoFocusCrossIcon changes to Modal, FundWallet, and swap-ui are supportive infrastructure for the autofocus feature, the broad story refactoring appears to be a coordinated architectural change not mentioned in the linked issue MNY-269. Consider extracting the story refactoring changes (Variant component introduction, layout parameter removal, and meta updates across multiple story files) into a separate PR, or provide clear justification in the PR description explaining how these architectural story changes are necessary for implementing the autofocus feature. The core autofocus functionality itself (SearchInput prop, select-token-ui integration, and Modal focus management) is well-scoped.
Docstring Coverage ⚠️ Warning Docstring coverage is 4.35% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "[MNY-269] SDK: autofocus token search input when token selector modal opens in BuyWidget, SwapWidget and BridgeWidget" clearly and specifically summarizes the main objective of this changeset. It includes the issue identifier, describes the core feature (autofocus token search input), specifies the triggering condition (when token selector modal opens), and identifies the affected components. The title accurately reflects the primary changes documented in the raw summary and aligns with the repository's title format.
Linked Issues Check ✅ Passed The PR successfully implements the primary objective from linked issue MNY-269 by adding autofocus functionality to token search inputs across BuyWidget, SwapWidget, and BridgeWidget components. The SearchInput component now accepts an autoFocus prop, and select-token-ui uses autoFocus={!props.isMobile} to enable autofocus on desktop while disabling it on mobile. The supporting infrastructure changes (autoFocusCrossIcon prop in Modal component) enable proper focus management without interfering with search input autofocus behavior.
Description Check ✅ Passed The PR description includes a PR-Codex-generated overview that provides a comprehensive summary of the changes, including the detailed list of modified components (SearchInput, Modal, BuyWidget, SwapWidget, BridgeWidget, and story files). While the description does not fully populate all template sections (missing explicit "Notes for the reviewer" and "How to test" sections), it provides substantive information about the enhancements and specific technical modifications, which constitutes mostly complete documentation.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mny-269

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • TEAM-0000: Entity not found: Issue - Could not find referenced Issue.

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

@MananTank MananTank changed the title [MNY-269] SDK: autofocus on token search input when token selector modal opens in BuyWidget, SwapWidget and BridgeWidget [MNY-269] SDK: autofocus token search input when token selector modal opens in BuyWidget, SwapWidget and BridgeWidget Oct 16, 2025
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: 0

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/react/web/ui/Bridge/swap-widget/SearchInput.tsx (1)

10-15: Add TSDoc for the new public prop.

The autoFocus prop is part of the public API but lacks documentation. As per coding guidelines, every public symbol requires comprehensive TSDoc.

Consider adding documentation:

 export function SearchInput(props: {
   value: string;
   onChange: (value: string) => void;
   placeholder: string;
+  /**
+   * Whether the input should be autofocused when rendered.
+   * @default false
+   */
   autoFocus: boolean;
 }) {

Based on coding guidelines.

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

32-44: Add documentation for the new prop.

The autoFocusCrossIcon prop modifies public API behavior but lacks documentation explaining its purpose and default value.

Consider adding TSDoc:

   crossContainerStyles?: React.CSSProperties;
+  /**
+   * Whether to autofocus the modal's close icon when opened.
+   * Set to false when another element (e.g., search input) should receive focus instead.
+   * @default true
+   */
   autoFocusCrossIcon?: boolean;
 }> = (props) => {
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (1)

69-81: Inconsistent use of Variant wrapper.

The Sell_Base_USDC story (lines 69-81) renders SwapWidget directly while all other stories use the Variant wrapper. This inconsistency breaks the uniform dual-theme preview pattern established in this file.

Apply this diff to use the Variant wrapper consistently:

 export function Sell_Base_USDC() {
   return (
-    <SwapWidget
+    <Variant
       client={storyClient}
       prefill={{
         sellToken: {
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx (1)

14-16: Inconsistent use of Variant wrapper.

The BasicUsage story renders SwapWidget directly while other stories use the Variant wrapper. This inconsistency breaks the uniform dual-theme preview pattern established in this file.

Apply this diff to use the Variant wrapper consistently:

 export function BasicUsage() {
-  return <SwapWidget client={storyClient} persistTokenSelections={false} />;
+  return <Variant client={storyClient} persistTokenSelections={false} />;
 }
🧹 Nitpick comments (2)
packages/thirdweb/src/react/web/ui/components/Modal.tsx (1)

147-155: Consider using nullish coalescing for cleaner default value handling.

The ternary expression can be simplified using the nullish coalescing operator.

Apply this diff:

                     <IconButton
                       aria-label="Close"
-                      autoFocus={
-                        props.autoFocusCrossIcon === undefined
-                          ? true
-                          : props.autoFocusCrossIcon
-                      }
+                      autoFocus={props.autoFocusCrossIcon ?? true}
                       type="button"
                     >
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (1)

118-132: Consider extracting the Variant wrapper to reduce duplication.

The Variant component is duplicated across multiple story files (SwapWidget.Prefill.stories.tsx, SwapWidget.stories.tsx, BuyWidget.stories.tsx, bridge-widget-script.stories.tsx). This duplication increases maintenance burden when the dual-theme preview pattern needs to change.

Consider extracting this wrapper to a shared utility file (e.g., packages/thirdweb/src/stories/utils.tsx) and importing it across all story files:

// packages/thirdweb/src/stories/utils.tsx
export function DualThemeVariant<T extends { theme?: "light" | "dark" | unknown }>(
  Component: React.ComponentType<T>,
) {
  return function Variant(props: T) {
    return (
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          gap: "40px",
          alignItems: "center",
        }}
      >
        <Component {...props} theme="dark" />
        <Component {...props} theme="light" />
      </div>
    );
  };
}

Then in story files:

import { DualThemeVariant } from "../../utils.js";

const Variant = DualThemeVariant(SwapWidget);
📜 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 c934102 and 31307bd.

📒 Files selected for processing (9)
  • packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-token-ui.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/components/Modal.tsx (2 hunks)
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (6 hunks)
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (7 hunks)
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx (6 hunks)
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{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/Modal.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-token-ui.tsx
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.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/Modal.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-token-ui.tsx
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.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/Modal.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-token-ui.tsx
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.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/BuyWidget.stories.tsx
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx
🧠 Learnings (3)
📚 Learning: 2025-09-24T11:08:43.783Z
Learnt from: MananTank
PR: thirdweb-dev/js#8106
File: packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx:34-41
Timestamp: 2025-09-24T11:08:43.783Z
Learning: In BridgeWidgetProps for packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx, the Swap onError callback signature requires a non-undefined SwapPreparedQuote parameter (unlike Buy's onError which allows undefined quote). This is intentional - SwapWidget's onError is only called when a quote is available.

Applied to files:

  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx
📚 Learning: 2025-09-24T11:09:45.142Z
Learnt from: MananTank
PR: thirdweb-dev/js#8106
File: packages/thirdweb/src/script-exports/readme.md:6-7
Timestamp: 2025-09-24T11:09:45.142Z
Learning: For thirdweb Bridge Widget script exports, the module is exported with globalName: "BridgeWidget" in tsup config, making the global API `BridgeWidget.render()` rather than `window.thirdweb.BridgeWidget.render()`.

Applied to files:

  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
📚 Learning: 2025-10-03T23:36:00.631Z
Learnt from: MananTank
PR: thirdweb-dev/js#8181
File: packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx:27-27
Timestamp: 2025-10-03T23:36:00.631Z
Learning: In packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx, the component intentionally uses a hardcoded English locale (connectLocaleEn) rather than reading from the provider, as BuyWidget is designed to be English-only and does not require internationalization support.

Applied to files:

  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
🧬 Code graph analysis (4)
packages/thirdweb/src/react/web/ui/components/Modal.tsx (1)
packages/thirdweb/src/react/web/ui/components/buttons.tsx (1)
  • IconButton (165-186)
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (1)
packages/thirdweb/src/script-exports/bridge-widget-script.tsx (2)
  • BridgeWidgetScript (62-72)
  • BridgeWidgetScriptProps (18-60)
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx (2)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx (2)
  • SwapWidgetProps (33-171)
  • SwapWidget (245-266)
packages/thirdweb/src/exports/react.ts (2)
  • SwapWidgetProps (151-151)
  • SwapWidget (150-150)
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (2)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx (2)
  • SwapWidget (245-266)
  • SwapWidgetProps (33-171)
packages/thirdweb/src/exports/react.ts (2)
  • SwapWidget (150-150)
  • SwapWidgetProps (151-151)
⏰ 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). (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (8)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx (1)

205-225: LGTM!

Setting autoFocusCrossIcon={false} correctly prevents the modal's close icon from stealing focus, allowing the search input within SelectToken to receive focus instead. This aligns with the PR objective to autofocus the token search input on desktop.

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

493-501: LGTM!

The desktop-only autofocus implementation (autoFocus={!props.isMobile}) correctly addresses the PR objective. Mobile devices are appropriately excluded, as autofocus with on-screen keyboards can be disruptive on smaller screens.

packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx (1)

213-237: LGTM!

Consistent with the same change in swap-ui.tsx, setting autoFocusCrossIcon={false} ensures the search input within the token selection modal receives focus instead of the close icon.

packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (1)

3-6: LGTM!

The type-only import of SwapWidgetProps follows TypeScript best practices and aligns with the coding guidelines.

packages/thirdweb/src/stories/BuyWidget.stories.tsx (1)

143-149: LGTM!

Adding alignItems: "center" to the Variant wrapper ensures consistent centering of widget previews in Storybook, which improves the visual presentation of dual-theme stories.

packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx (1)

3-6: LGTM!

The type-only import of SwapWidgetProps follows TypeScript best practices and aligns with the coding guidelines.

packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (2)

2-5: LGTM!

The type-only import of BridgeWidgetScriptProps follows TypeScript best practices and aligns with the coding guidelines.


13-70: LGTM!

All stories consistently use the Variant wrapper for dual-theme previews, which provides a uniform viewing experience across all BridgeWidgetScript stories.

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: 0

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/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (1)

69-81: Inconsistent usage of Variant wrapper.

The Sell_Base_USDC story directly renders SwapWidget while all other stories in this file use the Variant wrapper. This inconsistency makes the story behavior differ from others.

Apply this diff to align with other stories:

 export function Sell_Base_USDC() {
   return (
-    <SwapWidget
+    <Variant
       client={storyClient}
       prefill={{
         sellToken: {
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx (2)

14-16: Inconsistent usage of Variant wrapper.

The BasicUsage story directly renders SwapWidget while other stories in this file use the Variant wrapper. This inconsistency makes the story behavior differ from others (single instance vs. dual-theme instances).

Apply this diff if dual-theme rendering is intended:

 export function BasicUsage() {
-  return <SwapWidget client={storyClient} persistTokenSelections={false} />;
+  return <Variant client={storyClient} persistTokenSelections={false} />;
 }

28-37: Theme override bug: Variant ignores theme props.

The LightMode and CustomTheme stories pass theme-related props (theme="light" and custom theme object), but the Variant component hardcodes theme="dark" and theme="light" on lines 79-80, completely overriding the passed themes. These stories don't demonstrate what their names suggest.

Either:

  1. Remove Variant wrapper from theme-specific stories and render SwapWidget directly to preserve the custom themes, or
  2. Rename these stories to clarify they show both themes (e.g., CustomTheme_DualView) and adjust expectations.

Example fix for option 1:

 export function LightMode() {
-  return (
-    <Variant
-      client={storyClient}
-      currency="JPY"
-      theme="light"
-      persistTokenSelections={false}
-    />
-  );
+  return <SwapWidget client={storyClient} currency="JPY" theme="light" persistTokenSelections={false} />;
 }

 export function CustomTheme() {
-  return (
-    <Variant
-      client={storyClient}
-      currency="JPY"
-      persistTokenSelections={false}
-      theme={lightTheme({
-        colors: {
-          modalBg: "#FFFFF0",
-          tertiaryBg: "#DBE4C9",
-          borderColor: "#8AA624",
-          secondaryText: "#3E3F29",
-          accentText: "#E43636",
-        },
-      })}
-    />
-  );
+  return <SwapWidget 
+    client={storyClient} 
+    currency="JPY" 
+    persistTokenSelections={false} 
+    theme={lightTheme({
+      colors: {
+        modalBg: "#FFFFF0",
+        tertiaryBg: "#DBE4C9",
+        borderColor: "#8AA624",
+        secondaryText: "#3E3F29",
+        accentText: "#E43636",
+      },
+    })} 
+  />;
 }

Also applies to: 50-67

packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (1)

53-70: Theme override bug: Variant ignores custom theme.

The CustomTheme story passes a custom theme object with specific colors, but the Variant component hardcodes theme="dark" and theme="light" on lines 82-83, completely overriding the custom theme. The story doesn't demonstrate custom theming as its name suggests.

Either:

  1. Remove Variant wrapper and render BridgeWidgetScript directly to preserve the custom theme, or
  2. Rename the story to clarify it shows both themes regardless of input (e.g., CustomTheme_DualView).

Example fix for option 1:

 export function CustomTheme() {
-  return (
-    <Variant
-      clientId={storyClient.clientId}
-      buy={{ chainId: 8453, amount: "0.1" }}
-      theme={{
-        type: "light",
-        colors: {
-          modalBg: "#FFFFF0",
-          tertiaryBg: "#DBE4C9",
-          borderColor: "#8AA624",
-          secondaryText: "#3E3F29",
-          accentText: "#E43636",
-        },
-      }}
-    />
-  );
+  return <BridgeWidgetScript 
+    clientId={storyClient.clientId} 
+    buy={{ chainId: 8453, amount: "0.1" }} 
+    theme={{
+      type: "light",
+      colors: {
+        modalBg: "#FFFFF0",
+        tertiaryBg: "#DBE4C9",
+        borderColor: "#8AA624",
+        secondaryText: "#3E3F29",
+        accentText: "#E43636",
+      },
+    }} 
+  />;
 }
♻️ Duplicate comments (2)
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx (1)

69-83: Extract duplicated Variant component to shared utility.

The Variant component is duplicated across multiple story files (here, SwapWidget.Prefill.stories.tsx, and bridge-widget-script.stories.tsx). Extract this to a shared utility file to follow the DRY principle.

packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (1)

72-86: Extract duplicated Variant component to shared utility.

The Variant component is duplicated across three story files (SwapWidget.stories.tsx, SwapWidget.Prefill.stories.tsx, and here). Extract this to a shared utility file to follow the DRY principle.

🧹 Nitpick comments (1)
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (1)

118-132: Extract duplicated Variant component to shared utility.

The Variant component is duplicated across multiple story files (SwapWidget.stories.tsx, SwapWidget.Prefill.stories.tsx, and bridge-widget-script.stories.tsx). Extract this to a shared utility file like stories/utils.tsx to follow the DRY principle.

Example shared utility:

// In stories/utils.tsx or stories/components.tsx
export function DualThemeVariant<T>(props: T & { children: (props: T) => React.ReactNode }) {
  const { children, ...componentProps } = props;
  return (
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        gap: "40px",
        alignItems: "center",
      }}
    >
      {children({ ...componentProps, theme: "dark" } as T)}
      {children({ ...componentProps, theme: "light" } as T)}
    </div>
  );
}
📜 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 31307bd and b56ce1a.

📒 Files selected for processing (10)
  • .changeset/happy-trees-doubt.md (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-token-ui.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/components/Modal.tsx (2 hunks)
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (6 hunks)
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (7 hunks)
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx (6 hunks)
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-token-ui.tsx
  • packages/thirdweb/src/react/web/ui/components/Modal.tsx
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{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/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.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/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.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/SwapWidget.Prefill.stories.tsx
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.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/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

.changeset/*.md: Each change in packages/* must include a changeset for the appropriate package
Version bump rules: patch for non‑API changes; minor for new/modified public API

Files:

  • .changeset/happy-trees-doubt.md
🧠 Learnings (3)
📚 Learning: 2025-09-24T11:08:43.783Z
Learnt from: MananTank
PR: thirdweb-dev/js#8106
File: packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx:34-41
Timestamp: 2025-09-24T11:08:43.783Z
Learning: In BridgeWidgetProps for packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx, the Swap onError callback signature requires a non-undefined SwapPreparedQuote parameter (unlike Buy's onError which allows undefined quote). This is intentional - SwapWidget's onError is only called when a quote is available.

Applied to files:

  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx
📚 Learning: 2025-09-24T11:09:45.142Z
Learnt from: MananTank
PR: thirdweb-dev/js#8106
File: packages/thirdweb/src/script-exports/readme.md:6-7
Timestamp: 2025-09-24T11:09:45.142Z
Learning: For thirdweb Bridge Widget script exports, the module is exported with globalName: "BridgeWidget" in tsup config, making the global API `BridgeWidget.render()` rather than `window.thirdweb.BridgeWidget.render()`.

Applied to files:

  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
📚 Learning: 2025-10-03T23:36:00.631Z
Learnt from: MananTank
PR: thirdweb-dev/js#8181
File: packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx:27-27
Timestamp: 2025-10-03T23:36:00.631Z
Learning: In packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx, the component intentionally uses a hardcoded English locale (connectLocaleEn) rather than reading from the provider, as BuyWidget is designed to be English-only and does not require internationalization support.

Applied to files:

  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
🧬 Code graph analysis (3)
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (2)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx (2)
  • SwapWidget (245-266)
  • SwapWidgetProps (33-171)
packages/thirdweb/src/exports/react.ts (2)
  • SwapWidget (150-150)
  • SwapWidgetProps (151-151)
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (1)
packages/thirdweb/src/script-exports/bridge-widget-script.tsx (2)
  • BridgeWidgetScript (62-72)
  • BridgeWidgetScriptProps (18-60)
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx (2)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx (2)
  • SwapWidgetProps (33-171)
  • SwapWidget (245-266)
packages/thirdweb/src/exports/react.ts (2)
  • SwapWidgetProps (151-151)
  • SwapWidget (150-150)
⏰ 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). (4)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Unit Tests
  • GitHub Check: Size
  • GitHub Check: Lint Packages
🔇 Additional comments (1)
.changeset/happy-trees-doubt.md (1)

1-5: LGTM!

The changeset correctly documents the autofocus enhancement as a patch version bump, which is appropriate for this non-breaking behavioral improvement.

Copy link
Contributor

github-actions bot commented Oct 16, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 64.51 KB (0%) 1.3 s (0%) 195 ms (+252.29% 🔺) 1.5 s
thirdweb (cjs) 365.68 KB (0%) 7.4 s (0%) 593 ms (+17.42% 🔺) 8 s
thirdweb (minimal + tree-shaking) 5.73 KB (0%) 115 ms (0%) 103 ms (+3375.46% 🔺) 218 ms
thirdweb/chains (tree-shaking) 526 B (0%) 11 ms (0%) 81 ms (+5926% 🔺) 91 ms
thirdweb/react (minimal + tree-shaking) 19.13 KB (0%) 383 ms (0%) 83 ms (+2414% 🔺) 466 ms

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: 1

Caution

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

⚠️ Outside diff range comments (1)
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (1)

71-80: Inconsistent pattern with other stories.

The Sell_Base_USDC story still renders <SwapWidget> directly, while all other stories in this file use the <Variant> wrapper to test both dark and light themes side-by-side.

Apply this diff to align with the established pattern:

 export function Sell_Base_USDC() {
   return (
-    <SwapWidget
+    <Variant
       client={storyClient}
       prefill={{
         sellToken: {
           chainId: 8453,
           tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
         },
       }}
     />
   );
 }
🧹 Nitpick comments (2)
packages/thirdweb/src/stories/BuyWidget.stories.tsx (1)

141-155: Add explicit return type to Variant function.

The Variant function lacks an explicit return type, which is required by the coding guidelines for TypeScript files.

Apply this diff to add the return type:

-function Variant(props: BuyWidgetProps) {
+function Variant(props: BuyWidgetProps): React.JSX.Element {
   return (

As per coding guidelines.

packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (1)

118-132: Add explicit return type.

The Variant function should have an explicit return type per coding guidelines.

As per coding guidelines

Apply this diff:

-function Variant(props: SwapWidgetProps) {
+function Variant(props: SwapWidgetProps): React.ReactElement {
   return (
📜 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 b56ce1a and 872f37e.

📒 Files selected for processing (10)
  • .changeset/happy-trees-doubt.md (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-token-ui.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/components/Modal.tsx (2 hunks)
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (6 hunks)
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (7 hunks)
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx (6 hunks)
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx
  • packages/thirdweb/src/react/web/ui/components/Modal.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-token-ui.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx
  • .changeset/happy-trees-doubt.md
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{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/stories/BuyWidget.stories.tsx
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.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/stories/BuyWidget.stories.tsx
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.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/BuyWidget.stories.tsx
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.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/stories/BuyWidget.stories.tsx
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx
🧠 Learnings (3)
📚 Learning: 2025-09-24T11:09:45.142Z
Learnt from: MananTank
PR: thirdweb-dev/js#8106
File: packages/thirdweb/src/script-exports/readme.md:6-7
Timestamp: 2025-09-24T11:09:45.142Z
Learning: For thirdweb Bridge Widget script exports, the module is exported with globalName: "BridgeWidget" in tsup config, making the global API `BridgeWidget.render()` rather than `window.thirdweb.BridgeWidget.render()`.

Applied to files:

  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
📚 Learning: 2025-10-03T23:36:00.631Z
Learnt from: MananTank
PR: thirdweb-dev/js#8181
File: packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx:27-27
Timestamp: 2025-10-03T23:36:00.631Z
Learning: In packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx, the component intentionally uses a hardcoded English locale (connectLocaleEn) rather than reading from the provider, as BuyWidget is designed to be English-only and does not require internationalization support.

Applied to files:

  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
📚 Learning: 2025-09-24T11:08:43.783Z
Learnt from: MananTank
PR: thirdweb-dev/js#8106
File: packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx:34-41
Timestamp: 2025-09-24T11:08:43.783Z
Learning: In BridgeWidgetProps for packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx, the Swap onError callback signature requires a non-undefined SwapPreparedQuote parameter (unlike Buy's onError which allows undefined quote). This is intentional - SwapWidget's onError is only called when a quote is available.

Applied to files:

  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx
🧬 Code graph analysis (2)
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (1)
packages/thirdweb/src/script-exports/bridge-widget-script.tsx (2)
  • BridgeWidgetScript (69-79)
  • BridgeWidgetScriptProps (19-67)
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (2)
packages/thirdweb/src/exports/react.ts (2)
  • SwapWidget (152-152)
  • SwapWidgetProps (153-153)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx (2)
  • SwapWidget (248-269)
  • SwapWidgetProps (33-174)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Unit Tests
  • GitHub Check: Build Packages
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Lint Packages
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Size
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (4)
packages/thirdweb/src/stories/BuyWidget.stories.tsx (1)

143-149: LGTM! Layout change appropriately centers content.

The addition of alignItems: "center" properly centers the BuyWidget components horizontally within the flex container, replacing the removed global layout: "centered" parameter with local styling.

packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx (1)

208-208: LGTM!

The autoFocusCrossIcon={false} prop correctly disables autofocus on the modal's close button, allowing the token search input to receive focus instead. This aligns with the PR objective to enable immediate keyboard search when the token selector modal opens.

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

207-207: LGTM!

Consistent with the FundWallet implementation, this change correctly prevents the close button from stealing focus, enabling the token search input to autofocus when the modal opens.

packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (1)

3-6: LGTM!

The import expansion to include SwapWidgetProps type is appropriate for the new Variant component's type annotations.

Copy link

codecov bot commented Oct 16, 2025

Codecov Report

❌ Patch coverage is 50.00000% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 54.89%. Comparing base (3db3982) to head (5ff6063).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...ges/thirdweb/src/react/web/ui/components/Modal.tsx 71.42% 2 Missing ⚠️
...es/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx 0.00% 1 Missing ⚠️
...rc/react/web/ui/Bridge/swap-widget/SearchInput.tsx 0.00% 1 Missing ⚠️
...eact/web/ui/Bridge/swap-widget/select-token-ui.tsx 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8266      +/-   ##
==========================================
- Coverage   54.90%   54.89%   -0.01%     
==========================================
  Files         919      919              
  Lines       60613    60622       +9     
  Branches     4115     4126      +11     
==========================================
  Hits        33278    33278              
- Misses      27234    27242       +8     
- Partials      101      102       +1     
Flag Coverage Δ
packages 54.89% <50.00%> (-0.01%) ⬇️
Files with missing lines Coverage Δ
...es/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx 6.23% <0.00%> (-0.02%) ⬇️
...rc/react/web/ui/Bridge/swap-widget/SearchInput.tsx 13.51% <0.00%> (-0.38%) ⬇️
...eact/web/ui/Bridge/swap-widget/select-token-ui.tsx 4.70% <0.00%> (-0.01%) ⬇️
...ges/thirdweb/src/react/web/ui/components/Modal.tsx 92.12% <71.42%> (-0.97%) ⬇️

... and 4 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

graphite-app bot commented Oct 17, 2025

Merge activity

… opens in BuyWidget, SwapWidget and BridgeWidget (#8266)

<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR enhances user experience by adding autofocus functionality to token selection inputs in various components and refactoring the `BuyWidget` and `SwapWidget` to utilize a common `Variant` component for rendering with different themes.

### Detailed summary
- Added `autoFocus` to token search inputs in `BuyWidget`, `SwapWidget`, and `BridgeWidget`.
- Refactored `BuyWidget` to use a `Variant` component for theme rendering.
- Refactored `SwapWidget` to use a `Variant` component for theme rendering.
- Introduced `autoFocusCrossIcon` prop in `Modal` component.
- Updated `SearchInput` to accept `autoFocus` prop.

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

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Token search input now auto-focuses on desktop when opening token selector modals in Buy, Swap, and Bridge widgets.
  * Modal gained a configurable option to control initial focus of the close (cross) button.

* **Bug Fixes / UX**
  * Prevents unwanted focus on the modal close icon by default when configured, improving keyboard/voicing navigation.

* **Chores**
  * Storybook examples updated for consistent light/dark variants and layout metadata.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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: 0

Caution

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

⚠️ Outside diff range comments (1)
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (1)

69-81: Inconsistent rendering: Use Variant wrapper for dual-theme display.

The Sell_Base_USDC story still renders SwapWidget directly, while all other stories have been refactored to use the Variant wrapper. This inconsistency means this story won't display both light and dark themes like the others.

Apply this diff to align with the refactoring pattern:

 export function Sell_Base_USDC() {
   return (
-    <SwapWidget
+    <Variant
       client={storyClient}
       prefill={{
         sellToken: {
           chainId: 8453,
           tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
         },
       }}
     />
   );
 }
♻️ Duplicate comments (1)
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (1)

72-86: Restore story theming behavior: Variant ignores the theme prop.

The Variant component hardcodes theme="dark" and theme="light", completely discarding any theme supplied via props. This causes:

  • LightTheme story (line 26) to render both themes instead of only light
  • CustomTheme story (lines 58-67) to ignore the custom theme and render default themes

The stories no longer demonstrate what their names suggest.

Apply the fix from the previous review to respect the caller-provided theme:

 function Variant(props: BridgeWidgetScriptProps) {
+  const { theme, ...rest } = props;
+  const themesToRender =
+    theme === undefined ? (["dark", "light"] as const) : [theme];
+
   return (
     <div
       style={{
         display: "flex",
         flexDirection: "column",
         gap: "40px",
         alignItems: "center",
       }}
     >
-      <BridgeWidgetScript {...props} theme="dark" />
-      <BridgeWidgetScript {...props} theme="light" />
+      {themesToRender.map((t, idx) => (
+        <BridgeWidgetScript key={typeof t === "string" ? t : `custom-${idx}`} {...rest} theme={t} />
+      ))}
     </div>
   );
 }
🧹 Nitpick comments (2)
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (1)

118-132: Add explicit return type annotation.

The Variant component is missing an explicit return type annotation, which is required per the coding guidelines for TypeScript files.

Apply this diff to add the return type:

-function Variant(props: SwapWidgetProps) {
+function Variant(props: SwapWidgetProps): JSX.Element {
   return (

Optionally, consider adding a brief comment explaining the purpose of this internal helper:

/**
 * Internal helper that renders SwapWidget in both dark and light themes for story comparison.
 */
function Variant(props: SwapWidgetProps): JSX.Element {

As per coding guidelines.

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

44-44: Consider adding a brief inline comment.

While the prop name is descriptive, a brief comment would clarify its purpose for future maintainers (e.g., /** If false, disables autofocus on close button to allow other elements to receive initial focus */).

📜 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 872f37e and 5ff6063.

📒 Files selected for processing (10)
  • .changeset/happy-trees-doubt.md (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx (2 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-token-ui.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/components/Modal.tsx (2 hunks)
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (6 hunks)
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (7 hunks)
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx (6 hunks)
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .changeset/happy-trees-doubt.md
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SearchInput.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/select-token-ui.tsx
  • packages/thirdweb/src/stories/BuyWidget.stories.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.stories.tsx
  • packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{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/Modal.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.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/Modal.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.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/Modal.tsx
  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.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/SwapWidget.Prefill.stories.tsx
  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
🧠 Learnings (3)
📚 Learning: 2025-09-24T11:08:43.783Z
Learnt from: MananTank
PR: thirdweb-dev/js#8106
File: packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx:34-41
Timestamp: 2025-09-24T11:08:43.783Z
Learning: In BridgeWidgetProps for packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx, the Swap onError callback signature requires a non-undefined SwapPreparedQuote parameter (unlike Buy's onError which allows undefined quote). This is intentional - SwapWidget's onError is only called when a quote is available.

Applied to files:

  • packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx
📚 Learning: 2025-09-24T11:09:45.142Z
Learnt from: MananTank
PR: thirdweb-dev/js#8106
File: packages/thirdweb/src/script-exports/readme.md:6-7
Timestamp: 2025-09-24T11:09:45.142Z
Learning: For thirdweb Bridge Widget script exports, the module is exported with globalName: "BridgeWidget" in tsup config, making the global API `BridgeWidget.render()` rather than `window.thirdweb.BridgeWidget.render()`.

Applied to files:

  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
📚 Learning: 2025-10-03T23:36:00.631Z
Learnt from: MananTank
PR: thirdweb-dev/js#8181
File: packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx:27-27
Timestamp: 2025-10-03T23:36:00.631Z
Learning: In packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx, the component intentionally uses a hardcoded English locale (connectLocaleEn) rather than reading from the provider, as BuyWidget is designed to be English-only and does not require internationalization support.

Applied to files:

  • packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx
🧬 Code graph analysis (3)
packages/thirdweb/src/react/web/ui/components/Modal.tsx (1)
packages/thirdweb/src/react/web/ui/components/buttons.tsx (1)
  • IconButton (165-186)
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (2)
packages/thirdweb/src/exports/react.ts (2)
  • SwapWidget (152-152)
  • SwapWidgetProps (153-153)
packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx (2)
  • SwapWidget (248-269)
  • SwapWidgetProps (33-174)
packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (1)
packages/thirdweb/src/script-exports/bridge-widget-script.tsx (2)
  • BridgeWidgetScript (69-79)
  • BridgeWidgetScriptProps (19-67)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Lint Packages
  • GitHub Check: Build Packages
  • GitHub Check: Size
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Unit Tests
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (3)
packages/thirdweb/src/stories/Bridge/Swap/SwapWidget.Prefill.stories.tsx (1)

3-6: LGTM! Correct type import.

The addition of SwapWidgetProps type import is correct and properly uses the type modifier for type-only imports.

packages/thirdweb/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx (1)

2-5: LGTM: Type import supports proper typing of the Variant component.

The addition of BridgeWidgetScriptProps to the imports enables proper typing of the Variant helper function introduced below.

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

147-155: Logic is correct; consider nullish coalescing for brevity.

The conditional autofocus logic preserves backward compatibility by defaulting to true when autoFocusCrossIcon is undefined. Focus management is properly implemented: when the Modal's close button disables autofocus (autoFocusCrossIcon={false}), the SearchInput component in SelectToken compensates with autoFocus={!props.isMobile}, ensuring keyboard accessibility on desktop.

Optionally refactor to use the nullish coalescing operator for more idiomatic TypeScript:

                  <Dialog.Close asChild>
                    <IconButton
                      aria-label="Close"
-                     autoFocus={
-                       props.autoFocusCrossIcon === undefined
-                         ? true
-                         : props.autoFocusCrossIcon
-                     }
+                     autoFocus={props.autoFocusCrossIcon ?? true}
                      type="button"
                    >

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