Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Accordion component #2157

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Conversation

raquelarrojo
Copy link
Collaborator

@raquelarrojo raquelarrojo commented Feb 10, 2025

Checklist

  • Build process is done without errors. All tests pass in the /lib directory.
  • Self-reviewed the code before submitting.
  • Meets accessibility standards.
  • Added/updated documentation to /website as needed.
  • Added/updated tests as needed.

Description
Refactor Accordion component based on new design: https://www.figma.com/design/7CanVB5tlgwOeDIlvK8Dyf/Component-exploration-%26-Testing?node-id=1712-4101&m=dev
DxcAccordionGroup has been removed and now we have only one component: DxcAccordion. This component acts like the old accordion group, with accordion items inside.
Several changes:

  • disabled is now configurable on each accordion item, instead of in the accordion parent (old Accordion group).
  • Several ways of adding extra value added, like a badge or a status light. Everything is available in Figma's design.
  • subLabel added
  • independent added. This specifies when only one accordion can be expanded or several.
  • Types updated
  • Advanced and opinionated themes updated
  • Documentation updated
  • Functional and accessibility tests updated
  • Visual tests added
  • Theme generator previews updated

@raquelarrojo raquelarrojo marked this pull request as ready for review February 10, 2025 16:19
Accordions are used to group similar content and hide or show it depending on user needs or preferences.
Accordions give users more granular control over the interface and help digest content in stages, rather
than all at once.
Accordion are used to group related content into collapsible sections, allowing users to expand or hide
Copy link
Collaborator

Choose a reason for hiding this comment

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

I see a bit strange the start of the definition. Maybe we can fit something like to avoid using a singular name ("Accordion") with a plural verb ("are"). How do you see something like:

"The accordion component is a vertical stack of interactive headings used to group related content into collapsible sections, ..."

Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are we changing the file extension from ts to tsx?

Copy link
Collaborator

Choose a reason for hiding this comment

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

The page structure is different from other components with compound components inside. Take a look at the format in, for example:

icon?: string | SVG;
};

type ValidCombinations = BadgeBeforeProps | BadgeAfterProps | NoBadgeProps | AssistiveTextProps | IconProps;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I understand the reasoning behind this complex typing but it's a bit overwhelming, maybe over-engineering. Do you see maybe more value (for the user and us) in simplifying the typing and documenting all these restrictions?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Right now the user can't know all these restrictions by only reading our docs, which I think is not the ideal experience 😞

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, some of the possible combinations of those types may lead to unexpected behaviors:

  • never is used to try to make certain properties mutually exclusive, but this can lead to confusing behavior when combining props. For example, in AssistiveTextProps, assistiveText is allowed but statusLight is forbidden, while in BadgeBeforeProps, assistiveText and statusLight are both allowed. This overlap can complicate type inference and developer experience.
  • Two types handle the icon property (IconProps and NoBadgeProps) with subtle differences (one requires it, the other leaves it optional) that can lead to accepting unwanted combinations or causing errors if the intent behind each is not clearly understood.

/**
* When true, limits the user to single-open section at a time. When false, multiple sections can be opened simultaneously.
*/
independent?: true;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Remove the ? operator, it is already covered in the NonIndependentProps type (not defined or false are the same here).

subLabel="Jan, 09 2025"
icon="heart_plus"
disabled
badge={{ position: "after", element: <DxcBadge label="Enterprise" color="green" /> }}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This line is throwing a type error!

@@ -4,8 +4,10 @@ import DxcAccordion from "./Accordion";
describe("Accordion component tests", () => {
test("Renders with correct aria accessibility attributes", () => {
const { getByRole } = render(
<DxcAccordion label="Accordion" defaultIsExpanded>
<div>test-expanded</div>
<DxcAccordion defaultIndexActive={0}>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same error as in the accessibility tests. It happens in more than one place inside the file, I won't repeat the comment so as not to disturb the review!

)}
{badge?.position === "before" && !icon && (
<StatusContainer subLabel={subLabel}>
{disabled ? React.cloneElement(badge.element as ReactElement, { color: "grey" }) : badge.element}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we import cloneElement above as other regular import from "react" instead of using React?

const id = useId();
const colorsTheme = useContext(HalstackContext);
const { activeIndex, handlerActiveChange, index, independent } = useContext(AccordionContext) ?? {};
const isItemExpanded = independent
Copy link
Collaborator

Choose a reason for hiding this comment

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

I suggest storing this value with a useMemo to avoid unnecessary re-renders.

<DxcContainer width="100%" height="100%">
<DxcFlex gap="1.5rem">
<LeftSideContainer>
<DxcFlex gap="0.75rem">
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we can avoid having an extra container by simply adding to the DxcFlex the prop grow={1}.

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.

2 participants