Sammajayi/connect a wallet fixes - #135
Conversation
- Fix missing Alert import crash on error/unsupported states - Remove unused address prop from ChainLinkRow (lint fix) - Restructure PrimaryIdentityCard layout (shield/text/copy) - Reduce GlowCard shadow opacity and radius - Update unlink SVG path to match lucide icon - Add flexWrap to ChainLinkRow for 320px viewport support - Reduce input/button sizes for small viewports - Center address in verified identity box with wide gap - Adjust heading spacing and checkmark position - Update Playwright test screenshots
bbfde2f to
ed45fce
Compare
There was a problem hiding this comment.
Pull request overview
This PR refines the Connect-a-wallet widget by aligning its UI more closely with the design reference, improving responsiveness on small viewports, and hardening edge/error states. It also updates supporting UI primitives and Playwright state tests to match the new copy and layout.
Changes:
- Updated Connect-a-wallet widget view/layout (header, info callout, responsive chain rows, revised copy) and improved small-viewport behavior.
- Added
link/unlinkicons and tunedGlowCardshadow styling to better match the design system. - Hardened Playwright state tests with a more reliable “wait until rendered” helper and added mobile/desktop layout screenshots.
Reviewed changes
Copilot reviewed 8 out of 17 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/widgets/connect-a-wallet-widget/states.spec.ts | Improves test stability via waitForText and adds mobile/desktop layout coverage. |
| packages/ui/src/components/Icon.tsx | Adds link / unlink SVG paths for the redesigned connect/disconnect buttons. |
| packages/ui/src/components/GlowCard.ts | Adjusts glow shadow intensity/radius to better fit updated visual style. |
| packages/connect-a-wallet-widget/src/components/shared.tsx | Allows chain row card wrapping and simplifies ActionButton sizing for responsiveness. |
| packages/connect-a-wallet-widget/src/components/PrimaryIdentityCard.tsx | Redesigns the primary identity card and adds copy-to-clipboard affordance. |
| packages/connect-a-wallet-widget/src/components/ConnectAWalletWidgetView.tsx | Restructures the widget layout (header/callout/footer) and changes form/ready-state rendering. |
| packages/connect-a-wallet-widget/src/components/ChainLinkRow.tsx | Redesigns per-chain rows with status indicator + icon buttons and wrapping layout. |
| packages/connect-a-wallet-widget/src/components/AddressLinkForm.tsx | Updates form copy/typography and input/button sizing. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
| ) | ||
| } | ||
|
|
||
| const showForm = state.status !== 'error' && !(state.status === 'ready' && state.secondaryAddress) |
| width={40} | ||
| height={40} | ||
| borderRadius="$2" | ||
| backgroundColor="rgba(0, 174, 255, 0.15)" |
| <YStack | ||
| onPress={handleCopy} | ||
| cursor="pointer" | ||
| padding="$1" | ||
| hoverStyle={{ opacity: 0.7 }} | ||
| flexShrink={0} | ||
| > | ||
| <Icon name={copied ? 'check' : 'copy'} size="md" color={copied ? 'success' : 'muted'} /> | ||
| </YStack> |
Adds a changeSecondaryAddress adapter action and "Change address" button so users can check a different address without reloading, replaces a hardcoded RGBA background with the $infoMuted token, and swaps the copy-address control for an accessible, focusable Button.
| alignItems: 'center' as const, | ||
| justifyContent: 'space-between' as const, | ||
| flexWrap: 'wrap' as const, | ||
| gap: '$2', |
There was a problem hiding this comment.
ChainRowCard looks unused now — ChainLinkRow.tsx builds its row layout inline with raw XStack/YStack instead of this. Since the commit is titled "lint fixes," might as well drop this export too, or it'll get flagged by an unused-export rule later.
There was a problem hiding this comment.
<Heading level={6} fontSize="$1">Connect or Disconnect Address</Heading>
This is the exact same string as the heading in AddressLinkForm.tsx, but it's showing at a different point in the flow (after the address has already been checked, next to "Change address"). Two headings with identical text at different steps could be confusing when navigating by heading (e.g. screen readers), and it reads oddly sitting above rows that are already linked/checked. Could we give this one distinct copy, e.g. "Linked address" or "Manage connections"?
There was a problem hiding this comment.
const [disconnectHovered, setDisconnectHovered] = useState(false)
...
onMouseEnter={() => setDisconnectHovered(true)}
onMouseLeave={() => setDisconnectHovered(false)}
Nit: this widget runs on RN Web too, so onMouseEnter/onMouseLeave won't fire on touch. The copy button in PrimaryIdentityCard (and Copilot's earlier suggestion) uses hoverStyle instead — could we do the same here and drop the extra useState?
hoverStyle={{ backgroundColor: '$error' }}
| return null | ||
| } | ||
|
|
||
| const handleCopy = async () => { |
There was a problem hiding this comment.
const handleCopy = async () => {
const success = await copyTextToClipboard(walletAddress)
if (success) {
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
}
Small robustness thing: if the widget unmounts within the 2s window, this'll call setCopied on an unmounted component. Worth clearing the timeout on unmount, e.g.:
const timeoutRef = useRef<ReturnType<typeof setTimeout>>()
useEffect(() => () => clearTimeout(timeoutRef.current), [])
const handleCopy = async () => {
const success = await copyTextToClipboard(walletAddress)
if (success) {
setCopied(true)
timeoutRef.current = setTimeout(() => setCopied(false), 2000)
}
}
|
@pheobeayo, thanks for your review, will check it out right away. |
Remove unused ChainRowCard export, disambiguate the duplicate "Connect or Disconnect Address" heading, swap hover-tracked useState for hoverStyle on the disconnect button (RN Web/touch compatible), and clear the copy-feedback timeout on unmount.
|
@pheobeayo, I have addressed all the reviews. Kindly check it out |
919cb1f to
fed0846
Compare
pheobeayo
left a comment
There was a problem hiding this comment.
Good — this round addresses three of the four items I flagged, but introduces one new visual bug in the process. Here's the follow-up review.
✅ Resolved cleanly:
- ChainRowCard dead code — removed from shared.tsx.
- Duplicate "Connect or Disconnect Address" heading — now reads "Linked address" in the ready-state section, distinct from the form heading.
- Copy-confirmation timeout — now tracked in a timeoutRef and cleared on unmount via useEffect. Clean fix, hooks are still called unconditionally before the !walletAddress early return, so no Rules of Hooks issue.
| <ActionButton | ||
| disabled | ||
| variant={isDisconnect ? 'outline' : 'primary'} | ||
| borderColor={isDisconnect ? '$error' : undefined} | ||
| paddingHorizontal="$3.5" | ||
| flexShrink={0} | ||
| > | ||
| <Spinner size="sm" /> | ||
| </ActionButton> | ||
| ) : isDisconnect ? ( | ||
| <ActionButton | ||
| onPress={handlePress} | ||
| disabled={isDisabled} | ||
| variant="outline" | ||
| borderColor="$error" | ||
| hoverStyle={{ backgroundColor: '$error' }} | ||
| paddingHorizontal="$2.5" | ||
| paddingVertical="$1.5" | ||
| flexShrink={0} | ||
| > |
There was a problem hiding this comment.
Good call switching to hoverStyle for the background — that's the right cross-platform pattern. But the icon and label are still hardcoded to color="error" / color="$error", and previously the manual disconnectHovered state also flipped these to white on hover so the text stayed readable against the now-red background. With that state removed, hovering this button now renders red text/icon on a red background — effectively invisible.
hoverStyle on the parent ActionButton won't cascade to the Icon/ButtonText children's color props on its own. A couple of ways to fix:
If the design system supports Tamagui's group-hover pattern (wrap in a group, use $group-hover theme tokens on the children), that'd keep this fully declarative.
Otherwise, the simplest fix is reintroducing a small bit of hover state just for the text/icon color (keeping hoverStyle for the background, since that part works fine as-is):
const [hovered, setHovered] = useState(false)
...
<ActionButton
...
hoverStyle={{ backgroundColor: '$error' }}
onHoverIn={() => setHovered(true)}
onHoverOut={() => setHovered(false)}
>
<Icon name="unlink" size="xs" color={hovered ? 'white' : 'error'} />
<ButtonText fontSize="$1" color={hovered ? '$white' : '$error'}>Disconnect</ButtonText>
</ActionButton>
(onHoverIn/onHoverOut are Tamagui's cross-platform hover events, so this keeps the RN Web compatibility win from this commit while restoring contrast.)
hoverStyle only flips the background to red; icon/label were still hardcoded to error color, making them invisible on hover. Reintroduce a small hover flag via onHoverIn/onHoverOut to swap text/icon to white on hover, per pheobeayo's review.
|
@pheobeayo I have fixed as requested |
pheobeayo
left a comment
There was a problem hiding this comment.
Nice work — all the review findings are addressed now. Confirmed:
ChainRowCard dead code removed from shared.tsx
Heading copy disambiguated ("Linked address" vs. the form's "Connect or Disconnect Address")
Copy-confirmation timeout cleaned up on unmount in PrimaryIdentityCard
Disconnect button hover fixed — onHoverIn/onHoverOut now flip the icon/text to white so they stay readable against the hoverStyle red background, and it stays RN Web-compatible
Tested against the Playwright state stories and the state machine, empty/error states, and the "always show exactly one of Connect/Disconnect" invariant all hold up. changeSecondaryAddress is a solid addition too — good catch fixing the dead-end flow.
Approving 🚀
|
@L03TJ3 Kindly check through and review! |
Description
Redesigned the connect-wallet widget UI following the design reference in #113 in reference to the main pr in #116, executed following the plan in #114 . Fixed crash on error/unsupported states, addressed overflow on small viewports, and updated component styling to match the design system.
PR about #116
How Has This Been Tested?
Checklist: