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(content-separator): allow ContentSeparator in Menus #652

Merged
merged 18 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
256f6d7
feat(MenuSeperator): add MenuSeperator component
dominiccarrington Sep 24, 2024
32cac48
test(MenuSeperator): add tests
dominiccarrington Sep 24, 2024
138f05b
test(Menu): add snapshot test with seperators
dominiccarrington Sep 24, 2024
84b6e44
test(MenuSeperator): add stricter props test
dominiccarrington Sep 24, 2024
53e82c4
test(MenuSeperator): add keyboard and render tests
dominiccarrington Sep 24, 2024
ec981d9
fix(MenuSelectionGroup): fix styling
dominiccarrington Sep 24, 2024
008e33b
test(MenuSeperator): simplify test
dominiccarrington Sep 24, 2024
a1fcff0
fix(Menu.stories): remove unnecessary aria-labels
dominiccarrington Sep 24, 2024
620d816
test(MenuSeperator): add to other keyboard tests
dominiccarrington Sep 24, 2024
7eb2f66
feat(MenuSeperator): export component
dominiccarrington Sep 24, 2024
f0576c0
fix(MenuSelectionGroup): remove additional className and update snapshot
dominiccarrington Sep 24, 2024
a25266f
fix(MenuSeparator): fix misspelling of component
dominiccarrington Sep 24, 2024
941fc0c
test(MenuSeparator): fix spelling
dominiccarrington Sep 24, 2024
900b402
feat(ContentSeparator): convert MenuSeparator to use ContentSeparator…
dominiccarrington Sep 25, 2024
cbeeee3
test(Menu): add ContentSeparator to keyboard tests
dominiccarrington Sep 25, 2024
2174e5b
test(ContentSeparator): move menu tests
dominiccarrington Sep 25, 2024
0237268
chore(Menu): cleanup import
dominiccarrington Sep 25, 2024
6507bc3
fix(MenuSelectionGroup): remove font-size style
dominiccarrington Sep 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 26 additions & 61 deletions src/components/Menu/Menu.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import { action } from '@storybook/addon-actions';
import Flex from '../Flex';
import Avatar from '../Avatar';
import { PresenceType } from '../Avatar/Avatar.types';
import { ListHeader, ListItemBaseSection, Icon } from '..';
import { Icon, Text } from '..';
import './Menu.stories.style.scss';
import { MenuSeperator } from './Menu.utils';

export default {
title: 'Momentum UI/Menu',
Expand Down Expand Up @@ -82,38 +83,19 @@ Sections.parameters = {
onSelectionChange: menuOnSelectionChange,
onAction: menuOnAction,
children: [
<Section
key="0"
title={
<ListHeader outline={false}>
<ListItemBaseSection position="fill">Europe</ListItemBaseSection>
</ListHeader>
}
>
<Section key="0" title="Europe">
<Item key="00">Spain</Item>
<Item key="01">France</Item>
<Item key="02">Italy</Item>
</Section>,
<Section
key="1"
title={
<ListHeader outline={true} outlinePosition="top" outlineColor="secondary">
<ListItemBaseSection position="fill">Asia</ListItemBaseSection>
</ListHeader>
}
>
<MenuSeperator key="sep-0" />,
<Section key="1" title="Asia">
<Item key="10">India</Item>
<Item key="11">China</Item>
<Item key="12">Japan</Item>
</Section>,
<Section
key="2"
title={
<ListHeader outline={true} outlinePosition="top" outlineColor="secondary">
<ListItemBaseSection position="fill">America</ListItemBaseSection>
</ListHeader>
}
>
<MenuSeperator key="sep-1" />,
<Section key="2" title="America">
<Item key="13">USA</Item>
<Item key="14">Mexico</Item>
<Item key="15">Canada</Item>
Expand Down Expand Up @@ -154,14 +136,10 @@ SelectionGroups.parameters = {
console.log('selectionOnAction1', rest);
}}
title={
<ListHeader outline={false}>
<ListItemBaseSection position="start">
<Icon scale={16} name="speaker" strokeColor="none" />
</ListItemBaseSection>
<ListItemBaseSection position="fill">
Speaker (you can choose many)
</ListItemBaseSection>
</ListHeader>
<Flex direction="row" alignItems="center" xgap="0.25rem">
<Icon scale={16} name="speaker" strokeColor="none" />
<Text>Speaker (you can choose many)</Text>
</Flex>
}
>
<Item key="00">System default speaker</Item>
Expand All @@ -170,6 +148,7 @@ SelectionGroups.parameters = {
<Item key="03">MacBook Pro Speakers</Item>
<Item key="04">Webex Media Audio Device</Item>
</SelectionGroup>,
<MenuSeperator key="sep-0" />,
<SelectionGroup
key="1"
selectionMode="single"
Expand All @@ -182,16 +161,10 @@ SelectionGroups.parameters = {
console.log('selectionOnAction2', rest);
}}
title={
<>
<ListHeader outline={true} outlinePosition="top" outlineColor="secondary">
<ListItemBaseSection position="start">
<Icon scale={16} name="microphone" strokeColor="none" />
</ListItemBaseSection>
<ListItemBaseSection position="fill">
Microphone (you can choose one)
</ListItemBaseSection>
</ListHeader>
</>
<Flex direction="row" alignItems="center" xgap="0.25rem">
<Icon scale={16} name="microphone" strokeColor="none" />
<Text>Microphone (you can choose one)</Text>
</Flex>
}
>
<Item key="10">No Microphone</Item>
Expand All @@ -200,6 +173,7 @@ SelectionGroups.parameters = {
<Item key="13">MacBook Pro Microphone</Item>
<Item key="14">Webex Media Audio Device</Item>
</SelectionGroup>,
<MenuSeperator key="sep-1" />,
<SelectionGroup
key="2"
tickPosition="none"
Expand All @@ -218,16 +192,10 @@ SelectionGroups.parameters = {
console.log('selectionOnAction3', rest);
}}
title={
<>
<ListHeader outline={true} outlinePosition="top" outlineColor="secondary">
<ListItemBaseSection position="start">
<Icon scale={16} name="adjust-microphone" strokeColor="none" />
</ListItemBaseSection>
<ListItemBaseSection position="fill">
Webex smart audio (You can choose one)
</ListItemBaseSection>
</ListHeader>
</>
<Flex direction="row" alignItems="center" xgap="0.25rem">
<Icon scale={16} name="adjust-microphone" strokeColor="none" />
<Text>Webex smart audio (You can choose one)</Text>
</Flex>
}
>
{(item) => (
Expand All @@ -236,6 +204,7 @@ SelectionGroups.parameters = {
</Item>
)}
</SelectionGroup>,
<MenuSeperator key="sep-2" />,
<SelectionGroup
key="3"
tickPosition="none"
Expand All @@ -256,14 +225,10 @@ SelectionGroups.parameters = {
console.log('selectionOnAction4', rest);
}}
title={
<>
<ListHeader outline={true} outlinePosition="top" outlineColor="secondary">
<ListItemBaseSection position="start">
<Icon scale={16} name="accessibility" strokeColor="none" />
</ListItemBaseSection>
<ListItemBaseSection position="fill">Layout</ListItemBaseSection>
</ListHeader>
</>
<Flex direction="row" alignItems="center" xgap="0.25rem">
nataliadelmar marked this conversation as resolved.
Show resolved Hide resolved
<Icon scale={16} name="accessibility" strokeColor="none" />
<Text>Layout</Text>
</Flex>
}
>
{(item) => (
Expand Down
5 changes: 4 additions & 1 deletion src/components/Menu/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import MenuItem from '../MenuItem';
import { mergeProps } from '@react-aria/utils';
import MenuSection from '../MenuSection';
import MenuSelectionGroup from '../MenuSelectionGroup';
import ContentSeparator from '../ContentSeparator';

export const MenuContext = React.createContext<MenuContextValue>({});

Expand Down Expand Up @@ -70,7 +71,9 @@ const Menu = <T extends object>(props: Props<T>, providedRef: RefObject<HTMLDivE

const renderItem = useCallback(
<T extends object>(item: Node<T>, state: TreeState<T>) => {
if (item.type === 'section') {
if (item.type === 'seperator') {
return <ContentSeparator {...item.props} />;
} else if (item.type === 'section') {
if (item.props?.selectionGroup) {
return (
<MenuSelectionGroup
Expand Down
60 changes: 60 additions & 0 deletions src/components/Menu/Menu.unit.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import MenuSelectionGroup from '../MenuSelectionGroup';
import { MenuAppearanceContextValue } from './Menu.types';
import { MenuAppearanceContext, useMenuAppearanceContext } from './Menu';
import ListItemBaseSection from '../ListItemBaseSection';
import { MenuSeperator } from './Menu.utils';
import ContentSeparator from '../ContentSeparator';

describe('useMenuAppearanceContext', () => {
const fakeMenuAppearanceContextValue: MenuAppearanceContextValue = {
Expand Down Expand Up @@ -173,6 +175,20 @@ describe('<Menu />', () => {

expect(container).toMatchSnapshot();
});

it('should match snapshot with seperator between items', () => {
const props = {
...defaultProps,
children: [
<Item key="one">One</Item>,
<MenuSeperator key="sep" />,
<Item key="two">Two</Item>,
],
};

const container = mount(<Menu {...props} />);
expect(container).toMatchSnapshot();
});
});

describe('attributes', () => {
Expand Down Expand Up @@ -344,6 +360,38 @@ describe('<Menu />', () => {
expect(menuItems[0]).toHaveFocus();
});

it('should handle up/down arrow keys correctly - for vertical menus with seperators', async () => {
const user = userEvent.setup();

const props = {
...defaultProps,
children: [
<Item key="one">One</Item>,
<MenuSeperator key="sep" />,
<Item key="two">Two</Item>,
],
};

const { getAllByRole } = render(<Menu {...props} />);

await user.tab();

const menuItems = getAllByRole('menuitem');
expect(menuItems[0]).toHaveFocus();

await user.keyboard('{ArrowDown}');

expect(menuItems[1]).toHaveFocus();

await user.keyboard('{ArrowDown}');

expect(menuItems[0]).toHaveFocus();

await user.keyboard('{ArrowRight}');

expect(menuItems[0]).toHaveFocus();
});

it('should handle up/down arrow keys correctly - for vertical menu with section', async () => {
dominiccarrington marked this conversation as resolved.
Show resolved Hide resolved
const user = userEvent.setup();

Expand Down Expand Up @@ -584,5 +632,17 @@ describe('<Menu />', () => {
selectionGroup: true,
});
});

it('should render ContentSeperator if children has MenuSeperator', () => {
const wrapper = mount(
<Menu {...defaultProps}>
<Item key="01">One</Item>
<MenuSeperator key="sep" />
<Item key="02">Two</Item>
</Menu>
);

expect(wrapper.find(ContentSeparator).exists()).toBe(true);
});
});
});
Loading
Loading