Skip to content

Conversation

@tractorss
Copy link
Contributor

@tractorss tractorss commented Dec 11, 2025

PR-Codex overview

This PR updates the Accordion and CustomAccordion components in the Kleros UI library. It introduces new props for better customization, modifies component structure, and enhances the accordion functionality by allowing custom expand buttons.

Detailed summary

  • Updated version in package.json from 3.6.0 to 3.7.0.
  • Renamed Accordion to AccordionComponent in accordion.stories.tsx.
  • Changed AccordionItem interface to AccordionItemProps and added new properties.
  • Enhanced AccordionProps with defaultExpanded and documentation comments.
  • Updated Accordion and CustomAccordion components to support custom expand buttons.
  • Improved AccordionItem to handle custom expand button rendering.
  • Added new stories for CustomAccordion showcasing various use cases with custom buttons.

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

Summary by CodeRabbit

  • New Features

    • Customizable expand/collapse control per item or globally; controlled expanded prop and aria-expanded for accessibility; improved header spacing and unified transition timing; responsive container width.
  • Refactor

    • Accordion/item props and types made public and API signatures clarified for clearer item shape and prop usage.
  • Tests

    • Storybook stories added demonstrating per-item and global custom expand buttons.
  • Chores

    • Package version bumped to 3.7.0.

✏️ Tip: You can customize this high-level summary in your review settings.

@netlify
Copy link

netlify bot commented Dec 11, 2025

Deploy Preview for kleros-v2-ui-storybook ready!

Name Link
🔨 Latest commit 9c4fff8
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-ui-storybook/deploys/693ba9e6246b7b0008395b43
😎 Deploy Preview https://deploy-preview-85--kleros-v2-ui-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 11, 2025

Walkthrough

Exports accordion item types, exposes a customizable per-item or global expandButton renderer and controlled expanded prop, moves components from React.FC to function declarations, adjusts header/body markup and transitions, and adds Storybook stories demonstrating new APIs.

Changes

Cohort / File(s) Summary
Accordion Item Enhancement
src/lib/accordion/accordion-item.tsx
Exports AccordionItemProps; adds public title, body, expanded, and expandButton props; memoizes the expand control via useMemo and uses it in the header; adds aria-expanded, gap-4 spacing, and consolidates the body reveal into an overflow-hidden container with a unified ease-in-out transition.
CustomAccordion API Updates
src/lib/accordion/custom.tsx
Adds CustomAccordionProps; types items as `Pick<AccordionItemProps,"title"
Accordion Core Updates
src/lib/accordion/index.tsx
Exports AccordionItemProps and updated AccordionProps (items: AccordionItemProps[]); updates DefaultTitle to accept AccordionItemProps; replaces React.FC with a function Accordion({ ... }): Readonly<AccordionProps> and updates root container styling to w-full max-w-[1000px].
Story Updates
src/stories/accordion.stories.tsx
Changes story metadata and imports to reference AccordionComponent instead of Accordion; renames exported story constant to Accordion.
New CustomAccordion Stories
src/stories/custom-accordion.stories.tsx
Adds new Storybook file with three stories (Accordion, GlobalExpandButton, ItemExpandButton) demonstrating per-item and global expandButton usage and typings.
Version Bump
package.json
Increments package version from 3.6.0 to 3.7.0.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Validate AccordionItemProps export and expandButton type signature.
  • Confirm controlled expanded prop behavior and default expansion handling.
  • Check useMemo dependencies for the memoized expand control.
  • Verify per-item vs global expandButton fallback propagation in CustomAccordion.
  • Review Storybook stories for correct typings and render behavior.

Possibly related PRs

  • Chore/bug fixes #78 — touches accordion defaultExpanded/default state initialization; overlaps with changes in custom.tsx and index.tsx.
  • Fix/bug fixes and updates #80 — prior changes to accordion-item.tsx affecting expand/collapse control and header markup.

Suggested reviewers

  • alcercu

Poem

🐰 I hopped on props and polished a view,
A button for each petal, or one for the brew.
I memoized sparkles and tuck'd in the slide,
Per-item or global — I toggle with pride! ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main feature addition of custom expand button functionality for the accordion component, which aligns with the core changes across all modified files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/expand-button-custom-accordion

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 76cb796 and 9c4fff8.

📒 Files selected for processing (1)
  • package.json (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: tractorss
Repo: kleros/ui-components-library PR: 80
File: src/lib/accordion/accordion-item.tsx:28-28
Timestamp: 2025-06-06T12:21:11.794Z
Learning: In the AccordionItem component in src/lib/accordion/accordion-item.tsx, the static id="expand-button" on the Button element is intentional and should not be changed to dynamic IDs, even though it creates duplicate IDs across multiple accordion items.
🔇 Additional comments (1)
package.json (1)

3-3: Version bump is appropriate for new features and API expansions.

The minor version bump (3.6.0 → 3.7.0) aligns with the introduction of the CustomAccordion component and the expansion of the accordion API (exposing AccordionItemProps, adding per-item expandButton customization). No dependency changes are required.

Please verify that the refactoring of components from React.FC to function declarations does not introduce breaking changes for consumers who may have type dependencies on React.FC. If there are breaking changes (e.g., if the component types or props change in incompatible ways), this should be a major version bump (4.0.0) instead of a minor one.


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

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

🧹 Nitpick comments (3)
src/lib/accordion/index.tsx (1)

46-48: Simplify the negated condition.

Per SonarCloud's hint, the negated condition can be inverted for better readability.

  const [expanded, setExpanded] = useState(
-    !isUndefined(defaultExpanded) ? defaultExpanded : -1,
+    isUndefined(defaultExpanded) ? -1 : defaultExpanded,
  );
src/lib/accordion/custom.tsx (1)

58-60: Simplify the negated condition.

Same as in index.tsx, invert the condition for clarity.

  const [expanded, setExpanded] = useState(
-    !isUndefined(defaultExpanded) ? defaultExpanded : -1,
+    isUndefined(defaultExpanded) ? -1 : defaultExpanded,
  );
src/lib/accordion/accordion-item.tsx (1)

60-77: Consider extracting nested ternary for readability.

Per SonarCloud's suggestion, the nested ternary could be refactored into a clearer structure.

  const ExpandButton = useMemo(() => {
+    if (expandButton) {
+      return expandButton({
+        expanded,
+        toggle: () => setExpanded(expanded ? -1 : index),
+      });
+    }
+    const IconComponent = expanded ? Minus : Plus;
+    return (
+      <IconComponent
+        className={cn("fill-klerosUIComponentsPrimaryText size-4 shrink-0")}
+      />
+    );
-    expandButton ? (
-      expandButton({
-        expanded,
-        toggle: () => setExpanded(expanded ? -1 : index),
-      })
-    ) : expanded ? (
-      <Minus
-        className={cn("fill-klerosUIComponentsPrimaryText size-4 shrink-0")}
-      />
-    ) : (
-      <Plus
-        className={cn("fill-klerosUIComponentsPrimaryText size-4 shrink-0")}
-      />
-    ),
-  [expanded, expandButton, index, setExpanded],
+  }, [expanded, expandButton, index, setExpanded]);
  );
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e0363a9 and 1bd9a4c.

📒 Files selected for processing (5)
  • src/lib/accordion/accordion-item.tsx (1 hunks)
  • src/lib/accordion/custom.tsx (2 hunks)
  • src/lib/accordion/index.tsx (2 hunks)
  • src/stories/accordion.stories.tsx (1 hunks)
  • src/stories/custom-accordion.stories.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: tractorss
Repo: kleros/ui-components-library PR: 80
File: src/lib/accordion/accordion-item.tsx:28-28
Timestamp: 2025-06-06T12:21:11.794Z
Learning: In the AccordionItem component in src/lib/accordion/accordion-item.tsx, the static id="expand-button" on the Button element is intentional and should not be changed to dynamic IDs, even though it creates duplicate IDs across multiple accordion items.
📚 Learning: 2025-06-06T12:21:11.794Z
Learnt from: tractorss
Repo: kleros/ui-components-library PR: 80
File: src/lib/accordion/accordion-item.tsx:28-28
Timestamp: 2025-06-06T12:21:11.794Z
Learning: In the AccordionItem component in src/lib/accordion/accordion-item.tsx, the static id="expand-button" on the Button element is intentional and should not be changed to dynamic IDs, even though it creates duplicate IDs across multiple accordion items.

Applied to files:

  • src/lib/accordion/custom.tsx
  • src/lib/accordion/index.tsx
  • src/lib/accordion/accordion-item.tsx
  • src/stories/accordion.stories.tsx
  • src/stories/custom-accordion.stories.tsx
🧬 Code graph analysis (5)
src/lib/accordion/custom.tsx (3)
src/lib/accordion/accordion-item.tsx (1)
  • AccordionItemProps (9-49)
src/lib/accordion/index.tsx (1)
  • AccordionItemProps (5-10)
src/utils/index.ts (2)
  • isUndefined (8-11)
  • cn (4-6)
src/lib/accordion/index.tsx (2)
src/lib/accordion/accordion-item.tsx (1)
  • AccordionItemProps (9-49)
src/utils/index.ts (2)
  • isUndefined (8-11)
  • cn (4-6)
src/lib/accordion/accordion-item.tsx (3)
src/lib/accordion/index.tsx (1)
  • AccordionItemProps (5-10)
src/hooks/useElementSize.ts (1)
  • useElementSize (10-40)
src/utils/index.ts (1)
  • cn (4-6)
src/stories/accordion.stories.tsx (3)
.storybook/preview.tsx (1)
  • IPreviewArgs (8-11)
src/stories/utils.tsx (1)
  • IPreviewArgs (1-6)
src/stories/custom-accordion.stories.tsx (1)
  • Accordion (20-59)
src/stories/custom-accordion.stories.tsx (1)
src/stories/accordion.stories.tsx (1)
  • Accordion (18-42)
🪛 GitHub Check: SonarCloud Code Analysis
src/lib/accordion/custom.tsx

[warning] 59-59: Unexpected negated condition.

See more on https://sonarcloud.io/project/issues?id=kleros_ui-components-library&issues=AZsNP1qXaKGY6TxDWubZ&open=AZsNP1qXaKGY6TxDWubZ&pullRequest=85

src/lib/accordion/index.tsx

[warning] 47-47: Unexpected negated condition.

See more on https://sonarcloud.io/project/issues?id=kleros_ui-components-library&issues=AZsNP1qDaKGY6TxDWubY&open=AZsNP1qDaKGY6TxDWubY&pullRequest=85

src/lib/accordion/accordion-item.tsx

[warning] 67-75: Extract this nested ternary operation into an independent statement.

See more on https://sonarcloud.io/project/issues?id=kleros_ui-components-library&issues=AZsNP1nkaKGY6TxDWubX&open=AZsNP1nkaKGY6TxDWubX&pullRequest=85

🔇 Additional comments (4)
src/stories/accordion.stories.tsx (1)

6-18: LGTM!

The import alias to AccordionComponent and story renaming to Accordion improve clarity and align with the updated public API structure.

src/lib/accordion/custom.tsx (1)

51-82: LGTM on the expandButton fallback pattern.

The item.expandButton ?? expandButton fallback logic cleanly allows per-item overrides while supporting a global default.

src/lib/accordion/accordion-item.tsx (2)

80-93: Good accessibility improvement with aria-expanded.

Adding aria-expanded={expanded} properly communicates the accordion state to assistive technologies.


9-49: Well-documented props interface.

The JSDoc comments on AccordionItemProps thoroughly explain the expandButton render prop pattern with a clear example.

coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 11, 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

♻️ Duplicate comments (1)
src/stories/custom-accordion.stories.tsx (1)

102-102: Fix typo in story doc comment (“ovverrided” → “overridden”).

The JSDoc above ItemExpandButton still reads “ovverrided”; please correct for clarity:

-/** Parent Expand Button can be ovverrided at Item level if required */
+/** Parent expand button can be overridden at item level if required */
🧹 Nitpick comments (4)
src/lib/accordion/index.tsx (2)

5-10: Avoid having two different AccordionItemProps types in separate modules.

This file defines AccordionItemProps (string title, Icon/icon), while src/lib/accordion/accordion-item.tsx exports another AccordionItemProps (ReactNode title, body, expandButton, expanded, etc.). Even though they live in different modules, the identical name but different shape is easy to mis-import and misunderstand.

Consider either:

  • Renaming this one to something like AccordionItemConfig (and re-exporting the other as the canonical AccordionItemProps), or
  • Re-exporting the implementation-facing AccordionItemProps from accordion-item.tsx here and using a narrower, clearly named type for the public items config if needed.

12-25: Align AccordionProps with the fact that you spread ...props onto the root <div>.

Accordion currently has props { items, defaultExpanded, className } but also does <div {...props}>. This means callers can pass extra attributes (e.g. id, data-*, onClick) that are forwarded at runtime but are not modeled in AccordionProps.

To keep types aligned with behavior, consider:

export interface AccordionProps
  extends React.HTMLAttributes<HTMLDivElement> {
  items: AccordionItemProps[];
  defaultExpanded?: number;
  className?: string;
}

or, if pass-through is not desired, drop {...props} entirely.

Also applies to: 40-45, 50-56

src/lib/accordion/accordion-item.tsx (1)

60-71: You can simplify ExpandButton and drop useMemo for clarity.

useMemo is wrapping a cheap render helper that already depends on expanded and expandButton, so it offers little benefit and adds indirection. You could inline this logic and keep it easier to follow:

-  const ExpandButton = useMemo(() => {
-    if (expandButton) {
-      return expandButton({
-        expanded,
-        toggle: () => setExpanded(expanded ? -1 : index),
-      });
-    }
-    const IconComponent = expanded ? Minus : Plus;
-    return (
-      <IconComponent className="fill-klerosUIComponentsPrimaryText size-4 shrink-0" />
-    );
-  }, [expanded, expandButton, index, setExpanded]);
+  const toggle = () => setExpanded(expanded ? -1 : index);
+
+  const ExpandButton = expandButton
+    ? expandButton({ expanded, toggle })
+    : expanded ? (
+        <Minus className="fill-klerosUIComponentsPrimaryText size-4 shrink-0" />
+      ) : (
+        <Plus className="fill-klerosUIComponentsPrimaryText size-4 shrink-0" />
+      );

This keeps the same behavior with less hook complexity.

Also applies to: 86-87

src/lib/accordion/custom.tsx (1)

5-6: Model passthrough DOM props in CustomAccordionProps or drop {...props}.

Similar to Accordion, CustomAccordion spreads ...props onto the root <div>, but CustomAccordionProps only defines items, className, defaultExpanded, and expandButton. Any extra attributes passed (e.g. id, data-*) work at runtime but are invisible to the type system.

Consider:

export interface CustomAccordionProps
  extends React.HTMLAttributes<HTMLDivElement> {
  items: Pick<AccordionItemProps, "title" | "body" | "expandButton">[];
  className?: string;
  defaultExpanded?: number;
  expandButton?: AccordionItemProps["expandButton"];
}

or, if you don’t want arbitrary attributes forwarded, remove {...props} from the <div>.

Also applies to: 14-24, 51-57, 62-67

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1bd9a4c and 76cb796.

📒 Files selected for processing (4)
  • src/lib/accordion/accordion-item.tsx (1 hunks)
  • src/lib/accordion/custom.tsx (2 hunks)
  • src/lib/accordion/index.tsx (2 hunks)
  • src/stories/custom-accordion.stories.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: tractorss
Repo: kleros/ui-components-library PR: 80
File: src/lib/accordion/accordion-item.tsx:28-28
Timestamp: 2025-06-06T12:21:11.794Z
Learning: In the AccordionItem component in src/lib/accordion/accordion-item.tsx, the static id="expand-button" on the Button element is intentional and should not be changed to dynamic IDs, even though it creates duplicate IDs across multiple accordion items.
📚 Learning: 2025-06-06T12:21:11.794Z
Learnt from: tractorss
Repo: kleros/ui-components-library PR: 80
File: src/lib/accordion/accordion-item.tsx:28-28
Timestamp: 2025-06-06T12:21:11.794Z
Learning: In the AccordionItem component in src/lib/accordion/accordion-item.tsx, the static id="expand-button" on the Button element is intentional and should not be changed to dynamic IDs, even though it creates duplicate IDs across multiple accordion items.

Applied to files:

  • src/lib/accordion/accordion-item.tsx
  • src/lib/accordion/custom.tsx
  • src/stories/custom-accordion.stories.tsx
  • src/lib/accordion/index.tsx
🧬 Code graph analysis (4)
src/lib/accordion/accordion-item.tsx (3)
src/lib/accordion/index.tsx (1)
  • AccordionItemProps (5-10)
src/hooks/useElementSize.ts (1)
  • useElementSize (10-40)
src/utils/index.ts (1)
  • cn (4-6)
src/lib/accordion/custom.tsx (3)
src/lib/accordion/accordion-item.tsx (1)
  • AccordionItemProps (9-49)
src/lib/accordion/index.tsx (1)
  • AccordionItemProps (5-10)
src/utils/index.ts (2)
  • isUndefined (8-11)
  • cn (4-6)
src/stories/custom-accordion.stories.tsx (1)
src/stories/accordion.stories.tsx (1)
  • Accordion (18-42)
src/lib/accordion/index.tsx (2)
src/lib/accordion/accordion-item.tsx (1)
  • AccordionItemProps (9-49)
src/utils/index.ts (2)
  • isUndefined (8-11)
  • cn (4-6)
🔇 Additional comments (4)
src/lib/accordion/index.tsx (1)

12-25: Accordion API and defaultExpanded behavior look good.

The updated docs on items/defaultExpanded, the isUndefined(defaultExpanded) ? -1 : defaultExpanded initialization, and the responsive w-full max-w-[1000px] container together make the Accordion API clearer and more robust while preserving single-item expansion semantics.

Also applies to: 27-32, 46-48, 51-54

src/lib/accordion/accordion-item.tsx (1)

9-49: AccordionItemProps + expandButton API are well-structured.

The public AccordionItemProps with title, body, expanded, and the documented expandButton callback (with { expanded, toggle }) matches the custom/global button stories and keeps the header/body/transition logic coherent. The added aria-expanded and preserved static "expand-button" id also keep behavior predictable and accessible. Based on learnings, keeping the static id is correct.

Also applies to: 73-97

src/lib/accordion/custom.tsx (1)

5-43: CustomAccordionProps and expandButton override behavior look solid.

Using items: Pick<AccordionItemProps, "title" | "body" | "expandButton">[] plus a parent-level expandButton?: AccordionItemProps["expandButton"] neatly models both per-item and global buttons, and item.expandButton ?? expandButton does the right precedence. The defaultExpanded handling matches the base Accordion, keeping the mental model consistent.

Also applies to: 51-60, 69-80

src/stories/custom-accordion.stories.tsx (1)

19-59: Stories accurately exercise per-item and global expandButton behavior.

The three stories cover: per-item buttons, a shared global button, and per-item overrides on top of a global default. All use the correct ({ expanded, toggle }) callback signature and wire onPress={toggle} on the Button, which matches the AccordionItemProps["expandButton"] API.

Also applies to: 61-100, 102-148

coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 11, 2025
@kemuru kemuru self-requested a review December 11, 2025 20:22
kemuru
kemuru previously approved these changes Dec 11, 2025
@tractorss tractorss dismissed stale reviews from kemuru and coderabbitai[bot] via 9c4fff8 December 12, 2025 05:36
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
15.9% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@tractorss tractorss merged commit 407e2f3 into main Dec 12, 2025
7 of 8 checks passed
@tractorss tractorss deleted the feat/expand-button-custom-accordion branch December 12, 2025 05:40
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