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

feat(component): add AccordionPanel component #933

Merged
merged 14 commits into from
Aug 17, 2022

Conversation

bc-athorne
Copy link
Contributor

@bc-athorne bc-athorne commented Aug 2, 2022

What?

Add AccordionPanel and Accordion components to BigDesign

Why?

CHI-1984 - This component is needed for current Feedonomics work by CMX team.

Screenshots/Screen Recordings

Component

Screen.Recording.2022-08-10.at.11.59.31.AM.mov

Docs

Screen Shot 2022-08-02 at 1 49 15 PM
Screen Shot 2022-08-16 at 2 15 47 PM
Screen Shot 2022-08-16 at 2 15 56 PM
Screen Shot 2022-08-16 at 2 16 02 PM
Screen Shot 2022-08-16 at 2 16 28 PM
Screen Shot 2022-08-10 at 12 10 14 PM

Testing/Proof

All unit tests are passing.

@bc-athorne

This comment was marked as resolved.

@bc-athorne bc-athorne marked this pull request as ready for review August 2, 2022 20:41
@bc-athorne bc-athorne requested review from a team as code owners August 2, 2022 20:41
@bc-athorne bc-athorne requested review from bc-andreadao and a team August 2, 2022 20:41
Copy link
Contributor

@MariaJose MariaJose left a comment

Choose a reason for hiding this comment

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

Lgtm 👏🏼 ! Just few comments

@MariaJose
Copy link
Contributor

MariaJose commented Aug 2, 2022

I'm not sure why this test is failing in CircleCI. It logs the correct value and passes in my local environment.

Screen Shot 2022-08-02 at 3 37 37 PM

Local env:

test('if defaultExpanded is set to true, accordion is expanded', async () => {
  render(
    <AccordionPanel defaultExpanded={true} header="Panel Header" isExpanded onClick={handleClick}>
      <Text>This is a child component</Text>
    </AccordionPanel>,
  );

  const panel = await screen.findByRole('button');

  console.log(panel.getAttribute('aria-expanded'));

  expect(panel.getAttribute('aria-expanded')).toBe('true');
});
Screen Shot 2022-08-02 at 3 39 37 PM

It failed for me locally as well :eyes. But I add this and the test passed :

const [isExpanded, setisExpanded] = useState(defaultExpanded ?? false);

I think that we might not need this since a default value should not be changed?, unless missing something 🤔 :

useEffect(() => {
   if (defaultExpanded) {
     setisExpanded(defaultExpanded);
   }
 }, [defaultExpanded]);

Copy link
Contributor

@chanceaclark chanceaclark left a comment

Choose a reason for hiding this comment

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

Hey @bc-athorne! Congrats opening up your first contribution to BigDesign! I do have a few comments we should address, including some API updates we should make. Let me know if you have any questions!

FYI I'm just requesting changes to make sure we address some of the API concerns before we merge.

Copy link

@BC-Turner BC-Turner left a comment

Choose a reason for hiding this comment

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

Couple comments:

  1. When collapsing the component, it looks like the 2nd child overlaps the focused state of the first. Is there a way to bring that focused state forward so we don't lose part of the stroke?

Screen Shot 2022-08-03 at 9 13 53 AM

  1. For the implementation example, let's use either text or radio buttons for both panels and have either icons on both or none. I think we don't want users mixing panels of different content and keeping consistent with either having an icon on all or no icons. Just to avoid confusion.

Otherwise it looks great!

Copy link
Member

@rtalvarez rtalvarez left a comment

Choose a reason for hiding this comment

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

Sorry kinda late to the party here, but this is looking great so far

Copy link
Contributor

@jorgemoya jorgemoya left a comment

Choose a reason for hiding this comment

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

Looking good! Thanks for working on this Amanda. Left some comments, let me know what you think.


import { StyledAccordion, StyledAccordionButton, StyledBox, StyledGridItem } from './styled';

export interface AccordionPanelProps extends HTMLAttributes<HTMLDivElement> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this actually extend from PanelProps? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you provide some clarification on why you suggest this?

Copy link
Contributor

Choose a reason for hiding this comment

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

Side bar from Jorges comment, do we even need consumers to pass in HTMLDivElement attributes? If we leave this out right now, we can always add back in when consumers need it. We can't remove it without a breaking change if we add it in now.

@bc-athorne

This comment was marked as resolved.

Copy link

@BC-Turner BC-Turner left a comment

Choose a reason for hiding this comment

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

Looks awesome! Great job, Amanda!

Copy link
Contributor

@chanceaclark chanceaclark left a comment

Choose a reason for hiding this comment

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

I have a few more comments for ya @bc-athorne but thanks for making those updates!

packages/docs/pages/accordion-panel.tsx Outdated Show resolved Hide resolved
packages/docs/pages/accordion-panel.tsx Outdated Show resolved Hide resolved
Copy link
Contributor

@MariaJose MariaJose left a comment

Choose a reason for hiding this comment

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

Looking good! 👏🏼 , just left a few comments

rtalvarez
rtalvarez previously approved these changes Aug 11, 2022
Copy link
Member

@rtalvarez rtalvarez left a comment

Choose a reason for hiding this comment

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

🐑

Copy link
Contributor

@MariaJose MariaJose left a comment

Choose a reason for hiding this comment

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

Lgtm 👍🏼 !

header: string;
iconLeft?: React.ReactNode;
isExpanded: boolean;
onClick?: () => void;
Copy link
Contributor

@MariaJose MariaJose Aug 11, 2022

Choose a reason for hiding this comment

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

I think we could remove onClick ?

Copy link
Contributor

Choose a reason for hiding this comment

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

And isExpanded

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we want to remove isExpanded? I thought this was needed if we wanted this to be uncontrolled / controlled. Although, I'm not 100% clear on that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Handling the state inside the component makes it a controlled component, which you are doing with this hook: https://github.com/bigcommerce/big-design/pull/933/files#diff-5fc0e597eae1361cf0fba2493f91154fba01f35b851baace00572488ec7ec010R22

If we want consumers to control the state, we'd elevate that outside of the component and let consumers pass it in.

Copy link
Member

@rtalvarez rtalvarez Aug 11, 2022

Choose a reason for hiding this comment

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

I don't think this is entirely accurate -- this component is purposefully meant to be a controlled component, hence the ability for consumers to provide isExpanded and onClick, and we are definitely elevating these as far as I can see (through the panel items). We should keep isExpanded and onClick IMO

We should, however, export the useAccordion hook (I now realize its not being exported, maybe this is the source of the disconnect?), so consumers can opt for controlled or uncontrolled accordions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry for the confusion 🤦‍♀️. I moved useAccordion outside of the component.

Copy link
Contributor

Choose a reason for hiding this comment

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

The problem I see if that those props are not even being used, so we either need to use them or lose them.

Copy link
Member

Choose a reason for hiding this comment

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

We could drop onClick, but isExpanded is literally a required prop, it will get used. Not sure I follow

Copy link
Contributor

@chanceaclark chanceaclark Aug 11, 2022

Choose a reason for hiding this comment

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

What I mean is when you pull down the component, the passed in props.isExpanded and props.onClick are technically not being used/consumed within the component. onClick only works because we are spreading it into <Box {...props}> and the handler is being called when you expand/collapse the accordion. The passed props.isExpanded though is not being consumed anywhere, the state is being respected only through the state returned from useAccordion.

Note: we technically can't have an uncontrolled component here unless we use the native HTML details/summary elements. State will have to be managed by our component.

Copy link
Member

Choose a reason for hiding this comment

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

Was chatting with Chance this morning in the office, and cleared up some of the misunderstandings in this thread. The issues, as they stand right now, are:

  • The component is not honoring the provided isExpanded / onClick props. To correctly visualize this, we can think of a consumer that programatically mutates this prop. Since it's not going through onClick, it will not work
  • Because of the above, the useAccordion hook kinda operates on the item level, but the exported element is the group level. This also means we only need to export 1 component (the group one)
  • The Hooks folder is not being exported, so we need to move the useAccordion hook to the component folder and probably export it from there
  • Some of the names could be tweaked to make more sense, stylistic changes, etc

We can sync offline and discuss these issues, IMO we'll need to address them before we move forward


import { StyledAccordion, StyledAccordionButton, StyledBox, StyledGridItem } from './styled';

export interface AccordionPanelProps extends HTMLAttributes<HTMLDivElement> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Side bar from Jorges comment, do we even need consumers to pass in HTMLDivElement attributes? If we leave this out right now, we can always add back in when consumers need it. We can't remove it without a breaking change if we add it in now.

import { StyledAccordionButton, StyledAccordionContent } from './styled';

export interface AccordionPanelProps extends HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
Copy link
Contributor

Choose a reason for hiding this comment

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

have we tested nested children? Not sure if memo would interfere here with the diffing algo..

@rtalvarez rtalvarez dismissed their stale review August 12, 2022 14:07

Need some changes -- discuss offline

@bc-athorne bc-athorne changed the title feat(component): add AccordionGroup component feat(component): add AccordionPanel component Aug 16, 2022
Copy link
Contributor

@chanceaclark chanceaclark left a comment

Choose a reason for hiding this comment

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

One small little fix, otherwise looks good from my end.

Comment on lines 16 to 21
({ panels } = useAccordionPanel([
{
header: 'Panel Header',
children: <Text>This is a child component</Text>,
},
]));
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we should just assign this to a local const instead of using this type of JavaScript sorcery.

Suggested change
({ panels } = useAccordionPanel([
{
header: 'Panel Header',
children: <Text>This is a child component</Text>,
},
]));
const { panels } = useAccordionPanel([
{
header: 'Panel Header',
children: <Text>This is a child component</Text>,
},
]);

Same below...

Copy link
Member

@rtalvarez rtalvarez left a comment

Choose a reason for hiding this comment

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

Thanks for all the changes 🙏

@bc-athorne bc-athorne merged commit e22ffa2 into bigcommerce:master Aug 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

10 participants