Skip to content

feat: add expandable section component#2809

Open
mmioana wants to merge 4 commits intodevelopfrom
feature/jum-801-portfolio-page-create-generic-expandable-assets-card
Open

feat: add expandable section component#2809
mmioana wants to merge 4 commits intodevelopfrom
feature/jum-801-portfolio-page-create-generic-expandable-assets-card

Conversation

@mmioana
Copy link
Copy Markdown
Contributor

@mmioana mmioana commented Apr 13, 2026

Which Jira task belongs to this PR?

Closes https://linear.app/lifi-linear/issue/JUM-801/portfolio-page-create-generic-expandable-assets-card-component

Testing steps

  1. Open storybook and filter for Expandable Section
  2. The content should be the token list as per this view https://www.figma.com/design/vk3DeaqHF1o7GNHRaV5Xni/Portfolio--Webpage-?node-id=1720-136487&m=dev

Note

The enclosing card is not added in this component, so we can easily re-use it in different views

Why did I implement it this way?

Checklist before requesting a review

  • I have performed a self-review of my code
  • This pull request is as small as possible and only tackles one problem
  • I have added tests that cover the functionality / test the bug
  • If this changed the API, I have updated the documentation
  • I have provided QA instructions for the feature / fix implemented in this PR (if applicable)
  • I have provided instructions for any environment / deployment changes that this PR needs when merged

Summary by CodeRabbit

  • New Features

    • Added an Expandable Section UI with configurable header, optional expand icon, toggle behavior, clickable detail rows, optional end divider, and Storybook demos.
  • Tests

    • Added behavior and snapshot tests covering expansion states, click behavior, detail-item cursor styling, styling variations, and multiple content scenarios; includes mock fixtures for token/portfolio displays.
  • Style

    • Added styled primitives for the section and standardized body typography font family.

@mmioana mmioana self-assigned this Apr 13, 2026
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 13, 2026

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

Project Deployment Actions Updated (UTC)
jumper-exchange Error Error Apr 28, 2026 2:54pm
jumper-exchange-storybook Ready Ready Preview, Comment Apr 28, 2026 2:54pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 13, 2026

Walkthrough

Adds a new generic ExpandableSection React component with styled MUI subcomponents, Storybook stories, Vitest tests, token balance fixtures, and sets fontFamily for body typography variants.

Changes

Cohort / File(s) Summary
Component Implementation
src/components/core/sections/ExpandableSection/ExpandableSection.tsx
New generic ExpandableSection<T> component: controlled/initial expansion, shouldExpand gating, showExpandIcon, clickable detail rows, onItemClick, data-testid, and sx/details styling props.
Styles
src/components/core/sections/ExpandableSection/ExpandableSection.style.ts
New styled exports: StyledAccordion, StyledAccordionSummary (with useDefaultCursor prop), StyledAccordionDetails, and StyledContent to standardize layout, cursor, and hover behavior.
Stories
src/components/core/sections/ExpandableSection/ExpandableSection.stories.tsx
Added Storybook module with Default, NonExpandable, HideExpandIcon, and NonClickableItems stories using token fixtures and a shared header/item renderer.
Tests
src/components/core/sections/ExpandableSection/ExpandableSection.snapshot.spec.tsx
Added Vitest behavior and snapshot tests verifying header toggle behavior, shouldExpand gating, item cursor styles, multiple snapshot states, and rendering with multiple children.
Fixtures
src/components/core/sections/ExpandableSection/fixtures.ts
Added static PortfolioBalance<WalletToken>[] fixtures covering single/multi-chain and varied magnitudes for story/test use.
Typography
src/theme/typography.ts
Applied fontFamily: fonts.body explicitly to all body typography variants.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • yordanove
  • laurentsenta

Poem

🐰 I nudge the header, a hop and gentle spring,
Panels unfold like petals—see the tokens sing,
Dividers click in rhythm, fonts snug and precise,
Stories, tests, and fixtures—carrots baked just right. 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'feat: add expandable section component' accurately describes the main change: introducing a new generic ExpandableSection component. It is concise, clear, and directly reflects the primary objective of the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/jum-801-portfolio-page-create-generic-expandable-assets-card

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

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 13, 2026

✅ All snapshot tests passed

Copy link
Copy Markdown
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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/components/core/sections/ExpandableSection/ExpandableSection.snapshot.spec.tsx`:
- Around line 63-70: Add an interaction assertion to the 'matches snapshot when
expansion is disabled' test for ExpandableSection: after rendering with
shouldExpand={false} and renderHeader={defaultHeader}, simulate a user click on
the header (use the header text from defaultHeader or query by role) and assert
that the section does not expand—e.g., expect the details/children not to be
visible or expect the header's aria-expanded (or equivalent attribute/state) to
remain false—so clicking the header does not toggle expansion.

In
`@src/components/core/sections/ExpandableSection/ExpandableSection.stories.tsx`:
- Around line 65-70: The mapped elements returned from the array .map (the JSX
root StyledContent in the map) lack a stable key which causes React warnings;
update the mapping callback to supply a unique, stable key prop on StyledContent
(e.g., derive it from primaryBalance properties or from
getUniqueChains(balances) such as a concatenation of chain ids or
primaryBalance.id/address) so each child has a deterministic key across renders.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 72ebc5e5-5faf-46c8-92aa-f82589d55768

📥 Commits

Reviewing files that changed from the base of the PR and between 34ba2a0 and 1fcc19d.

⛔ Files ignored due to path filters (1)
  • src/components/core/sections/ExpandableSection/__snapshots__/ExpandableSection.snapshot.spec.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (6)
  • src/components/core/sections/ExpandableSection/ExpandableSection.snapshot.spec.tsx
  • src/components/core/sections/ExpandableSection/ExpandableSection.stories.tsx
  • src/components/core/sections/ExpandableSection/ExpandableSection.style.ts
  • src/components/core/sections/ExpandableSection/ExpandableSection.tsx
  • src/components/core/sections/ExpandableSection/fixtures.ts
  • src/theme/typography.ts

Comment on lines +65 to +70
].map((balances) => {
const hasMultipleChains = balances.length > 1;
const primaryBalance = balances[0]!;
const chainEntities = getUniqueChains(balances);
return (
<StyledContent
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
fd -i "ExpandableSection.stories.tsx" | xargs -r rg -n -C3 '\.map\(\(balances\)|<StyledContent|key='

Repository: jumperexchange/jumper-exchange

Length of output: 490


🏁 Script executed:

sed -n '60,85p' $(fd -i "ExpandableSection.stories.tsx")

Repository: jumperexchange/jumper-exchange

Length of output: 884


🏁 Script executed:

# Check if other stories use keys in map
fd -e stories.tsx | xargs rg -l "\.map\(" | head -5 | xargs rg -B2 -A4 "\.map\(\(" | grep -A4 "key=" | head -20

Repository: jumperexchange/jumper-exchange

Length of output: 1255


🏁 Script executed:

# Check ExpandableSection component to understand structure
fd -i "ExpandableSection.tsx" | grep -v stories | xargs cat 2>/dev/null | head -80

Repository: jumperexchange/jumper-exchange

Length of output: 2079


Add a stable key for mapped children.

Elements returned by this .map() are missing key props, which causes React warnings and unstable reconciliation.

Suggested patch
-    ].map((balances) => {
+    ].map((balances) => {
       const hasMultipleChains = balances.length > 1;
       const primaryBalance = balances[0]!;
       const chainEntities = getUniqueChains(balances);
       return (
         <StyledContent
+          key={`${primaryBalance.token.symbol}-${balances.length}`}
           hideCursor={false}
           direction="row"
📝 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
].map((balances) => {
const hasMultipleChains = balances.length > 1;
const primaryBalance = balances[0]!;
const chainEntities = getUniqueChains(balances);
return (
<StyledContent
].map((balances) => {
const hasMultipleChains = balances.length > 1;
const primaryBalance = balances[0]!;
const chainEntities = getUniqueChains(balances);
return (
<StyledContent
key={`${primaryBalance.token.symbol}-${balances.length}`}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/core/sections/ExpandableSection/ExpandableSection.stories.tsx`
around lines 65 - 70, The mapped elements returned from the array .map (the JSX
root StyledContent in the map) lack a stable key which causes React warnings;
update the mapping callback to supply a unique, stable key prop on StyledContent
(e.g., derive it from primaryBalance properties or from
getUniqueChains(balances) such as a concatenation of chain ids or
primaryBalance.id/address) so each child has a deterministic key across renders.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 13, 2026

Playwright test results

passed  55 passed
flaky  1 flaky
skipped  1 skipped

Details

stats  57 tests across 11 suites
duration  4 minutes, 28 seconds
commit  f518f15

Flaky tests

chromium › portfolioPage.spec.ts › Portfolio page › Verify elements and filters on portfolio page › verify value filter is cleared when clicking clear filter button (Qase ID: 57)

Skipped tests

chromium › themeManipulation.spec.ts › Switch between dark and light theme and check the background color › Partner theme should appear in theme menu and apply background color (Qase ID: 49)

📋 View Detailed Qase Report

@mmioana mmioana marked this pull request as draft April 13, 2026 17:04
@mmioana mmioana force-pushed the feature/jum-801-portfolio-page-create-generic-expandable-assets-card branch from 946bd3e to be07f91 Compare April 14, 2026 06:56
@mmioana mmioana marked this pull request as ready for review April 14, 2026 06:57
Copy link
Copy Markdown
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

🧹 Nitpick comments (1)
src/components/core/sections/ExpandableSection/ExpandableSection.stories.tsx (1)

77-101: Consider deduplicating shared TokenAmount props.

Both branches repeat the same visual props/sx; extracting shared props would reduce drift risk in future edits.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/core/sections/ExpandableSection/ExpandableSection.stories.tsx`
around lines 77 - 101, The TokenAmount usage is duplicated across the
hasMultipleChains branches; extract the common visual props (amountUSDVariant,
amountVariant, gap, sx: {textAlign:'right', marginLeft:'auto', minWidth:0}) into
a sharedProps object and spread it into a single TokenAmount component, then
conditionally pass the differing prop (balances when hasMultipleChains is true,
otherwise balance={primaryBalance}) so TokenAmount, hasMultipleChains, balances,
primaryBalance and defaultConfig are the referenced symbols to locate and
update.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/components/core/sections/ExpandableSection/ExpandableSection.stories.tsx`:
- Around line 46-49: The renderBalanceGroup function assumes balances is
non-empty by using balances[0]! (assigned to primaryBalance) which can throw if
fixtures change; add a defensive guard at the start of renderBalanceGroup (e.g.,
if balances.length === 0) and return an appropriate fallback (null, empty
fragment, or placeholder) before computing hasMultipleChains or calling
getUniqueChains; update any callers/tests to accept the fallback if needed so
primaryBalance and getUniqueChains are only invoked for non-empty BalanceGroup
inputs.

---

Nitpick comments:
In
`@src/components/core/sections/ExpandableSection/ExpandableSection.stories.tsx`:
- Around line 77-101: The TokenAmount usage is duplicated across the
hasMultipleChains branches; extract the common visual props (amountUSDVariant,
amountVariant, gap, sx: {textAlign:'right', marginLeft:'auto', minWidth:0}) into
a sharedProps object and spread it into a single TokenAmount component, then
conditionally pass the differing prop (balances when hasMultipleChains is true,
otherwise balance={primaryBalance}) so TokenAmount, hasMultipleChains, balances,
primaryBalance and defaultConfig are the referenced symbols to locate and
update.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4afce86c-47c5-4924-8023-ebfbb28d52f0

📥 Commits

Reviewing files that changed from the base of the PR and between a8d556e and be07f91.

⛔ Files ignored due to path filters (11)
  • src/components/Cards/EarnCard/__snapshots__/EarnCard.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/Cards/HeroEarnCard/__snapshots__/HeroEarnCard.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/Cards/ProtocolCard/__snapshots__/ProtocolCard.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/Link/__snapshots__/ExternalLink.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/composite/WalletBalanceCard/__snapshots__/WalletBalanceCard.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/composite/cards/MultiViewCard/__snapshots__/MultiViewCard.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/composite/cards/ProcessingTransactionCard/__snapshots__/ProcessingTransactionCard.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/core/AvatarStack/__snapshots__/AvatarStack.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/core/charts/LineChart/__snapshots__/LineChart.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/core/form/Select/__snapshots__/Select.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/core/sections/ExpandableSection/__snapshots__/ExpandableSection.snapshot.spec.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (6)
  • src/components/core/sections/ExpandableSection/ExpandableSection.snapshot.spec.tsx
  • src/components/core/sections/ExpandableSection/ExpandableSection.stories.tsx
  • src/components/core/sections/ExpandableSection/ExpandableSection.style.ts
  • src/components/core/sections/ExpandableSection/ExpandableSection.tsx
  • src/components/core/sections/ExpandableSection/fixtures.ts
  • src/theme/typography.ts
✅ Files skipped from review due to trivial changes (2)
  • src/theme/typography.ts
  • src/components/core/sections/ExpandableSection/fixtures.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/components/core/sections/ExpandableSection/ExpandableSection.snapshot.spec.tsx
  • src/components/core/sections/ExpandableSection/ExpandableSection.style.ts
  • src/components/core/sections/ExpandableSection/ExpandableSection.tsx

Comment on lines +46 to +49
const renderBalanceGroup = (balances: BalanceGroup) => {
const hasMultipleChains = balances.length > 1;
const primaryBalance = balances[0]!;
const chainEntities = getUniqueChains(balances);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Guard against empty balance groups before balances[0]!.

Line 48 assumes non-empty input and can throw if fixtures/data change. A small runtime guard makes the story resilient.

🛡️ Suggested hardening
 const renderBalanceGroup = (balances: BalanceGroup) => {
+  if (balances.length === 0) {
+    return null;
+  }
   const hasMultipleChains = balances.length > 1;
   const primaryBalance = balances[0]!;
   const chainEntities = getUniqueChains(balances);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/core/sections/ExpandableSection/ExpandableSection.stories.tsx`
around lines 46 - 49, The renderBalanceGroup function assumes balances is
non-empty by using balances[0]! (assigned to primaryBalance) which can throw if
fixtures change; add a defensive guard at the start of renderBalanceGroup (e.g.,
if balances.length === 0) and return an appropriate fallback (null, empty
fragment, or placeholder) before computing hasMultipleChains or calling
getUniqueChains; update any callers/tests to accept the fallback if needed so
primaryBalance and getUniqueChains are only invoked for non-empty BalanceGroup
inputs.

@yordanove
Copy link
Copy Markdown

yordanove commented Apr 21, 2026

🤖 Partneros QA Review

Summary: Adds a generic, typed ExpandableSection<T> MUI Accordion component for the portfolio page with Storybook stories, snapshot tests, and behaviour tests.

Risk Areas:

  • useDefaultCursor custom MUI prop may leak to DOM if shouldForwardProp is not set on StyledAccordionSummary — confirm it uses .attrs() or explicit forwarding guard
  • PR has unresolved merge conflicts against develop — needs rebase before merge

Missing Coverage:

  • isExpanded prop controlling initial open state has no dedicated behaviour test (only shouldExpand is tested)
  • data-hint-hover-active hover-suppression path has no integration test confirming the consuming parent sets the attribute

Playwright Tests: test/partneros-pr-2809
Test Cases: JUM-801

Copy link
Copy Markdown
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: 2

🧹 Nitpick comments (1)
src/components/core/sections/ExpandableSection/ExpandableSection.tsx (1)

18-45: Make isExpanded a controlled prop or clarify it as initial-value only.

Currently, isExpanded is renamed to initialIsExpanded on destructure (line 34) and used only once to initialize state (line 44). There's no useEffect to sync prop changes, so updates to isExpanded after mount are silently ignored. Either add a useEffect to make it controlled, add onExpanded callback to let parents listen to state changes, or rename the prop to defaultIsExpanded to clarify it's initial-value only.

Current implementation (lines 34, 44)
isExpanded: initialIsExpanded = false,
...
const [isExpanded, setIsExpanded] = useState<boolean>(initialIsExpanded);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/core/sections/ExpandableSection/ExpandableSection.tsx` around
lines 18 - 45, The prop named isExpanded is only used to initialize state
(initialIsExpanded) and is not synced, so make ExpandableSection properly
controlled by: accept an optional isExpanded prop and optional onExpanded
callback in ExpandableSectionProps, replace the current destructure (isExpanded:
initialIsExpanded) with isExpanded (allow undefined), keep internal state via
useState but add a useEffect that updates setIsExpanded(isExpanded) when the
incoming isExpanded prop is not undefined, and call onExpanded(newValue)
whenever setIsExpanded is invoked (e.g., in your toggle handler) so parents can
control or observe expansion; alternatively, if you prefer uncontrolled
behavior, rename the prop to defaultIsExpanded and remove syncing/notifications
— but implement one of these two approaches consistently for the
ExpandableSection component.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/core/sections/ExpandableSection/ExpandableSection.tsx`:
- Around line 82-90: The click handler is currently attached whenever
onItemClick exists regardless of isDetailsItemClickable; update the onClick prop
on the row (the element rendering ExpandableSection items) to only set a handler
when both onItemClick and isDetailsItemClickable are true (e.g.,
onClick={onItemClick && isDetailsItemClickable ? () => onItemClick(item) :
undefined}); also ensure the useDefaultCursor prop remains consistent with
isDetailsItemClickable so the cursor state matches clickability.
- Around line 81-93: The interactive row (StyledContent) currently only handles
mouse clicks via onItemClick; add keyboard semantics by setting role="button"
and tabIndex={onItemClick ? 0 : undefined}, and implement an onKeyDown handler
on StyledContent that calls onItemClick(item) when Enter or Space is pressed
(and prevents default for Space to avoid scrolling); keep the existing onClick
and preserve useDefaultCursor/isDetailsItemClickable behavior and renderItem
output so accessibility is added without changing visuals.

---

Nitpick comments:
In `@src/components/core/sections/ExpandableSection/ExpandableSection.tsx`:
- Around line 18-45: The prop named isExpanded is only used to initialize state
(initialIsExpanded) and is not synced, so make ExpandableSection properly
controlled by: accept an optional isExpanded prop and optional onExpanded
callback in ExpandableSectionProps, replace the current destructure (isExpanded:
initialIsExpanded) with isExpanded (allow undefined), keep internal state via
useState but add a useEffect that updates setIsExpanded(isExpanded) when the
incoming isExpanded prop is not undefined, and call onExpanded(newValue)
whenever setIsExpanded is invoked (e.g., in your toggle handler) so parents can
control or observe expansion; alternatively, if you prefer uncontrolled
behavior, rename the prop to defaultIsExpanded and remove syncing/notifications
— but implement one of these two approaches consistently for the
ExpandableSection component.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e38d969e-ef2e-4a16-b4ca-11e9e8c9691f

📥 Commits

Reviewing files that changed from the base of the PR and between be07f91 and f518f15.

⛔ Files ignored due to path filters (11)
  • src/components/Cards/EarnCard/__snapshots__/EarnCard.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/Cards/HeroEarnCard/__snapshots__/HeroEarnCard.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/Cards/ProtocolCard/__snapshots__/ProtocolCard.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/Link/__snapshots__/ExternalLink.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/composite/WalletBalanceCard/__snapshots__/WalletBalanceCard.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/composite/cards/MultiViewCard/__snapshots__/MultiViewCard.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/composite/cards/ProcessingTransactionCard/__snapshots__/ProcessingTransactionCard.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/core/AvatarStack/__snapshots__/AvatarStack.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/core/charts/LineChart/__snapshots__/LineChart.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/core/form/Select/__snapshots__/Select.snapshot.spec.tsx.snap is excluded by !**/*.snap
  • src/components/core/sections/ExpandableSection/__snapshots__/ExpandableSection.snapshot.spec.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (6)
  • src/components/core/sections/ExpandableSection/ExpandableSection.snapshot.spec.tsx
  • src/components/core/sections/ExpandableSection/ExpandableSection.stories.tsx
  • src/components/core/sections/ExpandableSection/ExpandableSection.style.ts
  • src/components/core/sections/ExpandableSection/ExpandableSection.tsx
  • src/components/core/sections/ExpandableSection/fixtures.ts
  • src/theme/typography.ts
✅ Files skipped from review due to trivial changes (3)
  • src/components/core/sections/ExpandableSection/fixtures.ts
  • src/theme/typography.ts
  • src/components/core/sections/ExpandableSection/ExpandableSection.stories.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/core/sections/ExpandableSection/ExpandableSection.snapshot.spec.tsx

Comment on lines +81 to +93
<StyledContent
useDefaultCursor={!isDetailsItemClickable}
direction="row"
spacing={2}
useFlexGap
justifyContent="space-between"
alignItems="center"
key={`ExpandableSectionItem-${index}`}
sx={detailsItemSx}
onClick={onItemClick ? () => onItemClick(item) : undefined}
>
{renderItem(item)}
</StyledContent>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Clickable rows are mouse-only; add keyboard interaction semantics.

StyledContent is interactive when onItemClick is set, but there is no keyboard activation path (Enter/Space), role, or tab stop.

Suggested fix
+          {items.map((item, index) => {
+            const isItemClickable = Boolean(onItemClick) && isDetailsItemClickable;
+            return (
             <StyledContent
               useDefaultCursor={!isDetailsItemClickable}
               direction="row"
               spacing={2}
               useFlexGap
               justifyContent="space-between"
               alignItems="center"
               key={`ExpandableSectionItem-${index}`}
               sx={detailsItemSx}
-              onClick={onItemClick ? () => onItemClick(item) : undefined}
+              onClick={isItemClickable ? () => onItemClick?.(item) : undefined}
+              role={isItemClickable ? 'button' : undefined}
+              tabIndex={isItemClickable ? 0 : undefined}
+              onKeyDown={
+                isItemClickable
+                  ? (event) => {
+                      if (event.key === 'Enter' || event.key === ' ') {
+                        event.preventDefault();
+                        onItemClick?.(item);
+                      }
+                    }
+                  : undefined
+              }
             >
               {renderItem(item)}
             </StyledContent>
+            );
+          })}
-          ))}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/core/sections/ExpandableSection/ExpandableSection.tsx` around
lines 81 - 93, The interactive row (StyledContent) currently only handles mouse
clicks via onItemClick; add keyboard semantics by setting role="button" and
tabIndex={onItemClick ? 0 : undefined}, and implement an onKeyDown handler on
StyledContent that calls onItemClick(item) when Enter or Space is pressed (and
prevents default for Space to avoid scrolling); keep the existing onClick and
preserve useDefaultCursor/isDetailsItemClickable behavior and renderItem output
so accessibility is added without changing visuals.

Comment on lines +82 to +90
useDefaultCursor={!isDetailsItemClickable}
direction="row"
spacing={2}
useFlexGap
justifyContent="space-between"
alignItems="center"
key={`ExpandableSectionItem-${index}`}
sx={detailsItemSx}
onClick={onItemClick ? () => onItemClick(item) : undefined}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

isDetailsItemClickable is not enforced in the click handler.

Line 90 still attaches onClick whenever onItemClick exists, so rows remain clickable even when isDetailsItemClickable={false}.

Suggested fix
-              onClick={onItemClick ? () => onItemClick(item) : undefined}
+              onClick={
+                onItemClick && isDetailsItemClickable
+                  ? () => onItemClick(item)
+                  : undefined
+              }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/core/sections/ExpandableSection/ExpandableSection.tsx` around
lines 82 - 90, The click handler is currently attached whenever onItemClick
exists regardless of isDetailsItemClickable; update the onClick prop on the row
(the element rendering ExpandableSection items) to only set a handler when both
onItemClick and isDetailsItemClickable are true (e.g., onClick={onItemClick &&
isDetailsItemClickable ? () => onItemClick(item) : undefined}); also ensure the
useDefaultCursor prop remains consistent with isDetailsItemClickable so the
cursor state matches clickability.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants