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/dropdown expandable menu #1129

Merged
merged 11 commits into from
Oct 11, 2023
Merged

Conversation

chris-cedrone-cengage
Copy link
Collaborator

@chris-cedrone-cengage chris-cedrone-cengage commented Sep 12, 2023

Issue: # 1014

What I did

-New sub-component of Dropdown that allows expanding menu items, with or without icons at the parent level.

Screenshots:

changing_lives_360

Checklist

  • changeset has been added
  • Pull request description is descriptive
  • I have made corresponding changes to the documentation
  • New and existing unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works

How to test

  • Open Expandable Items in Dropdown and ensure the show / collapse works on each item.
  • Verify that icon and text only variants both appear correctly to design specs.
  • If an Expandable Item contains icons and text only items, confirm the padding is consistent throughout each.
  • Make sure Inverse mode works.
  • If a menu item text length exceeds the set width of the Dropdown container, verify that the text wraps.

@changeset-bot
Copy link

changeset-bot bot commented Sep 12, 2023

🦋 Changeset detected

Latest commit: 55898ea

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@silvalaura silvalaura linked an issue Sep 12, 2023 that may be closed by this pull request
Copy link
Collaborator

@silvalaura silvalaura left a comment

Choose a reason for hiding this comment

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

One thing I'm noticing is keyboard navigation feels a little weird because, after I tab into the group, I can use my arrow keys to navigate through both closed "accordions." If I open one, then I lose the ability to navigate to them. Also if they are both open, the arrow keys loop through the open items.

@orion-cengage can you take a look to see how this navigation compares to your expectations? Maybe it's right, but just want another pair of eyes on it.

Also, what happens if the use provides icons for only some of the top level items?

Comment on lines 839 to 842
const testId = 'expandable group';
const testId2 = 'expandable item';
const testId3 = 'expandable button';
const testId4 = 'expandable panel';
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick, but it would be helpful if these variables had useful names for readability:

const expButtonId = 'expandable-button';
const expPanel1Id = 'expandable-panel-1';

You also use ``${testId4}-2} a few times, you could just add another variable for it

expect(queryByTestId(`${testId4}-2`)).not.toBeInTheDocument();
});

it('should have only allow one open menu item when isMulti is used', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's have separate tests for when isMulti is true and when isMulti is false (Since isMulti takes a boolean, I personally find it easier to follow the descriptions when we use the exact value you're passing to a prop)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Anything not declaring the isMulti prop is automatically true. Do we need a specific test for that?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I would say yes for full coverage.

icon?: React.ReactElement<IconProps>;
}>`
font-weight: 400;
padding: 8px 16px;
Copy link
Collaborator

Choose a reason for hiding this comment

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

spacing03 spacing05

// const i18n = React.useContext(I18nContext);

return (
<StyledAccordionPanel
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's add {...rest}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Did you mean {...other}? The other Dropdown components all use that spread operator.

Copy link
Collaborator

Choose a reason for hiding this comment

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

either works!

return (
<StyledAccordionPanel
hasIcon={context.hasIcon}
isExpandablePanel={isExpandablePanel}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we be using isExpandablePanel from the DropdownExpandableMenuItemContext or from props?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Refactored and no longer a prop in this component.

Comment on lines 66 to 70
if (props.hasIcon && props.isExpandablePanel) {
return `${props.theme.spaceScale.spacing03} ${props.theme.spaceScale.spacing05} ${props.theme.spaceScale.spacing03} 72px`;
}
//For DropdownExpandableMenu styling without an icon
else if (props.isExpandablePanel) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

You're checking props.isExpandablePanel twice, and removed the case for padding when it's not expandable. This needs to be updated as it's breaking other dropdowns:
image

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That actually wasn't removed and still behaves as it did before.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure what you mean 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Padding remains at 8px 0 when no DropdownItems exist as it did before.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Still looks broken to me. Check out the No Items story. This is what it looks like in the dev branch: https://storybook-preview-dev--upbeat-sinoussi-f675aa.netlify.app/?path=/story/dropdown--no-items

Comment on lines 53 to 88
DropdownAlignment,
DropdownDropDirection,
DropdownProps,
} from './components/Dropdown';
export {
DropdownContent,
DropdownContentProps,
} from './components/Dropdown/DropdownContent';
export {
DropdownDivider,
DropdownDividerProps,
} from './components/Dropdown/DropdownDivider';
export {
DropdownHeader,
DropdownHeaderProps,
} from './components/Dropdown/DropdownHeader';
export {
DropdownMenuGroup,
DropdownMenuGroupProps,
} from './components/Dropdown/DropdownMenuGroup';
export {
DropdownMenuItem,
DropdownMenuItemProps,
} from './components/Dropdown/DropdownMenuItem';
export {
DropdownMenuNavItem,
DropdownMenuNavItemProps,
} from './components/Dropdown/DropdownMenuNavItem';
export {
DropdownSplitButton,
DropdownSplitButtonProps,
} from './components/Dropdown/DropdownSplitButton';
export {
DropdownButton,
DropdownButtonProps,
} from './components/Dropdown/DropdownButton';
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's make sure all of these components are actually exported in packages/react-magma-dom/src/components/Dropdown/index.tsx if we want to do this (I see that some are not). I think it's okay to import them from their individual files like we were previously doing.

@@ -127,6 +131,19 @@ export const DropdownContent = React.forwardRef<
}
});

// For Expandable Dropdowns that don't require a max-height
let hasExpandable = false;
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 this variable name and comment are throwing me off a bit. Could we be more verbose and call it hasExpandableItems or something?? and then the comment can also be updated

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@@ -174,7 +174,6 @@ export const Dropdown = React.forwardRef<HTMLDivElement, DropdownProps>(

function handleKeyDown(event: React.KeyboardEvent) {
if (event.key === 'Escape') {
event.nativeEvent.stopImmediatePropagation();
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 removing this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Accidental removal


const StyledIconWrapper = styled(IconWrapper)`
justify-content: center;
/* align-items: center; */
Copy link
Collaborator

Choose a reason for hiding this comment

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

Remove comment

<StyledAccordion
{...other}
isInverse={context.isInverse}
role="expandable group"
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is not a valid aria role

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Changed to role="group"

const { children, disabled, testId, ...other } = props;

return (
<AccordionItem isDisabled={disabled} {...other} testId={testId}>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
<AccordionItem isDisabled={disabled} {...other} testId={testId}>
<AccordionItem {...other} isDisabled={disabled} testId={testId}>

Comment on lines 23 to 27
`
--------------------------------------------------------------------------------------------------------
Only one group level is supported, anything nested two levels or more isn't accounted for in the styling
--------------------------------------------------------------------------------------------------------
`
Copy link
Collaborator

Choose a reason for hiding this comment

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

For consistency with our other warnings,

Suggested change
`
--------------------------------------------------------------------------------------------------------
Only one group level is supported, anything nested two levels or more isn't accounted for in the styling
--------------------------------------------------------------------------------------------------------
`
`
React Magma Warning: Only one group level is supported for Expandable Dropdowns, anything nested two levels or more isn't accounted for in the styling
`

import { DropdownContext } from './Dropdown';

const StyledAccordion = styled(Accordion)<{
testId?: string;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This testId is not needed here

});

return (
<DropdownExpandableContext.Provider value={{ hasIcon, isExpandablePanel }}>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
<DropdownExpandableContext.Provider value={{ hasIcon, isExpandablePanel }}>
<DropdownExpandableMenuGroupContext.Provider value={{ hasIcon, isExpandablePanel }}>


const context = React.useContext(DropdownContext);

let hasIcon = false;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I tend to prefer long variable names that are very clear over short ones that are less descriptive. In this case, the MenuGroup wouldn't have icons-- the children menu button is what we are after. Maybe we can call this expandableMenuButtonHasIcon or something like that.

@@ -129,6 +146,8 @@ export const DropdownMenuItem = React.forwardRef<
const theme = React.useContext(ThemeContext);
const context = React.useContext(DropdownContext);

const expandableContext = React.useContext(DropdownExpandableContext);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
const expandableContext = React.useContext(DropdownExpandableContext);
const menuGroupContext = React.useContext(DropdownExpandableMenuGroupContext);

You may also check if it's expandable with const isExpandablePanel = !!menuGroupContext; instead of getting it from the context.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Seems that the context is necessary here.

… amendments per Laura's review, still working on tests
@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

Copy link
Collaborator

@silvalaura silvalaura left a comment

Choose a reason for hiding this comment

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

Keyboard navigation looks good. I did notice that if the disabled item is in the middle of the list (not first or last), it doesn't just get skipped, it actually prevents the rest of the items from being focused.

@@ -23,10 +23,12 @@ export interface AccordionButtonProps
/**
* @internal
*/
hasCustomArray?: boolean;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This name is really ambiguous. Can we think of something more specific and descriptive? Lets also add a comment for further clarity on how this prop should be used

@github-actions
Copy link
Contributor

github-actions bot commented Oct 5, 2023

@github-actions
Copy link
Contributor

github-actions bot commented Oct 5, 2023

Comment on lines 16 to 25
function menuItemPadding(props) {
//For DropdownExpandableMenu styling with an icon
if (props.expandableMenuButtonHasIcon && props.isExpandablePanel) {
return `${props.theme.spaceScale.spacing03} ${props.theme.spaceScale.spacing05} ${props.theme.spaceScale.spacing03} 72px`;
}
//For DropdownExpandableMenu styling without an icon
else if (props.isExpandablePanel) {
return `${props.theme.spaceScale.spacing03} ${props.theme.spaceScale.spacing05} ${props.theme.spaceScale.spacing03} ${props.theme.spaceScale.spacing08}`;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This can be simplified now:

function menuItemPadding(props) {
  if (props.isExpandablePanel) {
    if (props.expandableMenuButtonHasIcon) {
      return `${props.theme.spaceScale.spacing03} ${props.theme.spaceScale.spacing05} ${props.theme.spaceScale.spacing03} 72px`;
    }
    return `${props.theme.spaceScale.spacing03} ${props.theme.spaceScale.spacing05} ${props.theme.spaceScale.spacing03} ${props.theme.spaceScale.spacing08}`;
  }
}

Comment on lines +1064 to +1069
## Dropdown Expandable Menu List Item Props

**Any other props supplied will be provided to the wrapping `div` element.**

<DropdownExpandableMenuListItemProps />

Copy link
Collaborator

Choose a reason for hiding this comment

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

This looks right, but for whatever reason this props table is not showing up in the docs site:
image

Comment on lines 35 to 38
&:hover,
&:focus {
background: ${menuBackground};
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this still needed? It may already default to the correct styles from DropdownMenuItem

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Removed.

Comment on lines 65 to 68
isFixedWidth={context.isFixedWidth}
isInverse={context.isInverse}
ref={disabled ? null : ref}
role="menuitem"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same with some of these, are they necessary?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Removed redundancies

Comment on lines 24 to 28
disabled?: boolean;
expandableMenuButtonHasIcon?: boolean;
isExpandablePanel?: boolean;
isFixedWidth?: boolean;
isInverse?: boolean;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Some of these are not needed as they are not used by menuItemPadding

@github-actions
Copy link
Contributor

github-actions bot commented Oct 6, 2023

@github-actions
Copy link
Contributor

github-actions bot commented Oct 6, 2023

@silvalaura
Copy link
Collaborator

This is basically good to go, I think it can be marked as ready for review 😄

@chris-cedrone-cengage chris-cedrone-cengage marked this pull request as ready for review October 6, 2023 17:52
@chris-cedrone-cengage chris-cedrone-cengage requested a review from a team as a code owner October 6, 2023 17:52
Copy link
Collaborator

@silvalaura silvalaura left a comment

Choose a reason for hiding this comment

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

⭐⭐⭐

@chris-cedrone-cengage chris-cedrone-cengage added the needs design feedback Waiting for Design approval or feedback label Oct 6, 2023
@github-actions
Copy link
Contributor

github-actions bot commented Oct 6, 2023

@github-actions
Copy link
Contributor

github-actions bot commented Oct 6, 2023

@chris-cedrone-cengage chris-cedrone-cengage merged commit 77823fb into dev Oct 11, 2023
1 check passed
@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

silvalaura pushed a commit that referenced this pull request Oct 19, 2023
silvalaura pushed a commit that referenced this pull request Oct 23, 2023
silvalaura pushed a commit that referenced this pull request Jun 5, 2024
@silvalaura silvalaura deleted the feat/dropdownExpandableMenu branch July 25, 2024 17:44
silvalaura pushed a commit that referenced this pull request Aug 15, 2024
silvalaura pushed a commit that referenced this pull request Sep 18, 2024
silvalaura pushed a commit that referenced this pull request Sep 18, 2024
silvalaura pushed a commit that referenced this pull request Sep 18, 2024
silvalaura pushed a commit that referenced this pull request Sep 18, 2024
silvalaura pushed a commit that referenced this pull request Dec 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs design feedback Waiting for Design approval or feedback
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Dropdowns with Accordion
2 participants