feat(widget): add redesigned amount input cards#776
Conversation
🦋 Changeset detectedLatest commit: e066384 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
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 |
53fa01e to
9f97fb1
Compare
be8ef80 to
74478ac
Compare
9c39a0a to
6ae7bef
Compare
🔍 QA Review — EMB-452
🧠 What this ticket doesReplaces the legacy
📋 Ticket SummaryAdd Send/Receive amount input cards Acceptance Criteria:
🔎 Resolution Status — All 8 Items
🗒️ Minor Notes (non-blocking)
🧪 Test Coverage (post-fix)
🔗 Downstream ImpactRelated to: EMB-451 — "Add support for tabs passed from Simple and Advanced Jumper modes". No blocking gaps — the card pair's mode-aware QA Agent — 2026-06-22 · Re-review |
There was a problem hiding this comment.
Requesting changes on 8 items — each requires either a code fix or an explicit acceptance comment with justification before this review is considered complete.
| # | Severity | Type | Issue / File |
|---|---|---|---|
| 1 | 🟠 High | Test gap | No unit tests for any of the eight new components |
| 2 | 🟠 High | E2e regression | fromButton / toButton / reverseTokensButton e2e selectors broken and not updated |
| 3 | 🟠 High | Release process | No changeset for publishable @lifi/widget package (CLAUDE.md rule) |
| 4 | 🟡 Medium | Accessibility | SwapButton renders as a button with no accessible name |
| 5 | 🟡 Medium | Accessibility | Fiat toggle (ToggleButton) in ReceiveAmountCard has no accessible name when interactive |
| 6 | 🟡 Medium | Styling | Magic zIndex: 1110 in SwapButton.style.tsx — no named constant |
| 7 | 🟢 Low | Styling consistency | TokenPillButton.style.tsx uses theme.shape instead of theme.vars.shape |
| 8 | 🟢 Low | Dead code | inputMode['to'] state is set but never read in the new components |
1. [High] No unit tests for any of the eight new components
AmountInputCardPair, SendAmountCard, ReceiveAmountCard, PercentageChips, BalanceDisplay, FiatValueToggle, TokenPillButton, and SwapButton are all new exports with zero test files. Required coverage per component is detailed in the full QA report comment. Create co-located test files under packages/widget/src/components/AmountInputCard/, SwapButton/, and TokenPillButton/.
2. [High] E2e selectors broken — fromButton / toButton / reverseTokensButton
WidgetView.ts selectors that matched the legacy AmountInput UI (role-by-name From/To, data-testid="widget-reverse-tokens-button") no longer match any element in the new AmountInputCardPair layout. CI e2e suites (smoke.spec.ts, widget-smoke.spec.ts, settings.mode-variant.spec.ts) will break. Update selectors to match TokenPillButton and add data-testid="widget-swap-tokens-button" to SwapIconCard.
3. [High] Missing changeset for @lifi/widget
CLAUDE.md requires a .changeset/*.md for every publishable package change. changeset-bot has already flagged this. Run pnpm changeset, select @lifi/widget, choose minor, and add a summary.
4. [Medium] SwapButton missing aria-label
<SwapIconCard component="button"> contains only an aria-hidden icon. Add aria-label={t('button.swap')} to the button element in SwapButton.tsx.
5. [Medium] Fiat toggle ToggleButton in ReceiveAmountCard missing aria-label
When canToggle is true, the ToggleButton (ButtonBase) has no accessible name. Add aria-label={t('button.toggleFiatValue')} or equivalent in ReceiveAmountCard.tsx.
6. [Medium] Magic zIndex: 1110 in SwapButton.style.tsx
Hardcoded z-index value with no named constant or comment. Extract to a named constant or use theme.zIndex.appBar + 10 with documentation in SwapButton.style.tsx line 10.
7. [Low] theme.shape instead of theme.vars.shape in TokenPillButton.style.tsx
pillLayout uses theme.shape.borderRadiusSecondary inconsistently with the rest of the PR. Change to theme.vars.shape.borderRadiusSecondary for CSS variable consistency.
8. [Low] inputMode['to'] dead state in useInputModeStore
ReceiveAmountCard uses local useState for its fiat toggle, leaving the 'to' key in useInputModeStore orphaned. Either wire ReceiveAmountCard to the store or remove the 'to' path from the store type.
💡 Once you've addressed the items above, re-apply the "Agent Review Request" label to trigger an automated re-review.
Review feedback addressedPushed in
#1 Unit tests — not added (justification)The widget package has no component-test infrastructure: no |
✅ E2E Dev Smoke — passing
4 passed · 0 failed · 0 skipped · 21s |
E2E Examples — all passedAll examples passed in the latest run. |
E2E Playground resultsDetails
📥 Download full HTML report (open the run → Artifacts → |
Which Linear task is linked to this PR?
EMB-452
Why was it implemented this way?
This replaces the legacy amount input (
AmountInput+ inline price helper) with a redesigned Send/Receive card pair (AmountInputCardPair), rendered fromMainPagefor the standard swap/bridge flow (every non-custom mode, plus customdeposit). The custom-contract flow path is unchanged and still rendersSelectChainAndToken. The legacyAmountInputand its sub-components are removed.SendAmountCard): large editable input with adaptive font sizing, token pill selector, percentage chips, fiat/token input toggle, and wallet balance display. Supports price (fiat) input mode via the input-mode store. Percentage chips (25/50/75/Max) are shown only when a wallet is connected; Max deducts the recommended gas reserve on native tokens.ReceiveAmountCard): read-only amount from the best route, with a fiat/token toggle and token pill selector. The footer shows the route's price impact (computed viagetPriceImpact, identical toRouteDetails) with an info tooltip. The amount and footer values fall back to skeletons while routes are fetching.TokenPillButton): the selected state is a neutral chip-style pill matching the percentage pills; the empty "select" state is derived from the app's primaryButton, so its background/hover/disabled treatment stays in sync with the theme.SwapButton): vertical swap arrow between the cards that reverses the from/to chain + token (clearing the amount) and runs thetoAddressauto-populate / reset. Hidden when the mode isrefuel(no receive token).AvatarBadgedDefault): gains optionalavatarSize/badgeSizeprops so the token pill can size its chain avatar and badge.New components
AmountInputCard/—SendAmountCard,ReceiveAmountCard,AmountInputCardPair,PercentageChips,BalanceDisplay,FiatValueToggle, shared stylesSwapButton/— vertical swap arrow with overlapping-card designTokenPillButton/— pill-shaped token selector (chip-style when selected, primary-button call to action when empty)Removed
AmountInput/—AmountInput,AmountInputStartAdornment,PriceFormHelperTextand their stylesVisual showcase (Screenshots or Videos)
Screen.Recording.2026-06-22.at.10.36.40.mov
Checklist before requesting a review