Skip to content

Commit

Permalink
feat(SideNavigation): Add defaultExpandedAll flag to allow expanding …
Browse files Browse the repository at this point in the history
…all sections (#564)
  • Loading branch information
jessieweiyi authored Mar 3, 2022
1 parent 12e4610 commit a526a26
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 16 deletions.
67 changes: 67 additions & 0 deletions src/components/SideNavigation/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,70 @@ export const WithSections = () => {
/>
);
};

export const WithSectionsDefaultExpandedAll = () => {
const navigationItems = [
{
type: SideNavigationItemType.LINK,
text: 'Page 1',
href: '/page1',
},
{
type: SideNavigationItemType.LINK,
text: 'Page 2',
href: '/page2',
},
{
type: SideNavigationItemType.SECTION,
text: 'Section 1',
items: [
{
type: SideNavigationItemType.LINK,
text: 'Page 4',
href: '/page4',
},
{
type: SideNavigationItemType.LINK,
text: 'Page 5',
href: '/page5',
},
{
type: SideNavigationItemType.LINK,
text: 'Page 6',
href: '/page6',
},
],
},
{
type: SideNavigationItemType.SECTION,
text: 'Section 2',
items: [
{
type: SideNavigationItemType.LINK,
text: 'Page 7',
href: '/page7',
},
{
type: SideNavigationItemType.LINK,
text: 'Page 8',
href: '/page8',
},
{
type: SideNavigationItemType.LINK,
text: 'Page 9',
href: '/page9',
},
],
},
];
return (
<SideNavigation
header={{
href: '/',
text: 'Service name',
}}
defaultExpandedAll={true}
items={navigationItems}
/>
);
};
45 changes: 45 additions & 0 deletions src/components/SideNavigation/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,51 @@ describe('SideNavigation', () => {
expect(getByText('Page 2').closest('a')).toHaveAttribute('href', '/page2');
});

it('should render all sub list items when the defaultExpandedAll is true', () => {
const navigationItems = [
{ type: SideNavigationItemType.LINK, text: 'Page 1', href: '/page1' },
{
type: SideNavigationItemType.SECTION,
text: 'Section 1',
items: [
{
type: SideNavigationItemType.LINK,
text: 'Page 2',
href: '/page2',
},
],
},
{
type: SideNavigationItemType.SECTION,
text: 'Section 2',
items: [
{
type: SideNavigationItemType.LINK,
text: 'Page 3',
href: '/page3',
},
],
},
];
const history = createMemoryHistory();
const { getByText } = render(
<Router history={history}>
<SideNavigation
header={{
href: '/',
text: 'Site header',
}}
defaultExpandedAll={true}
items={navigationItems}
/>
</Router>
);
expect(getByText('Site header').closest('a')).toHaveAttribute('href', '/');
expect(getByText('Page 1').closest('a')).toHaveAttribute('href', '/page1');
expect(getByText('Page 2').closest('a')).toHaveAttribute('href', '/page2');
expect(getByText('Page 3').closest('a')).toHaveAttribute('href', '/page3');
});

it('should not render sub list items when the section is not expanded', () => {
const navigationItems = [
{ type: SideNavigationItemType.LINK, text: 'Page 1', href: '/page1' },
Expand Down
44 changes: 28 additions & 16 deletions src/components/SideNavigation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,20 +94,33 @@ export interface SideNavigationItem {
/** Populate the initial expanded state of the section based on the settings */
const populateInitialExpandedState = (
items: SideNavigationItem[],
defaultExpandedAll: boolean,
initialState: { [itemText: string]: boolean } = {}
): { [itemText: string]: boolean } => {
items.forEach((item) => {
if (item.expanded && item.text !== undefined) {
if ((defaultExpandedAll || item.expanded) && item.text !== undefined) {
initialState[item.text] = true;
}

if (item.items && item.items.length > 0) {
populateInitialExpandedState(item.items, initialState);
populateInitialExpandedState(item.items, defaultExpandedAll, initialState);
}
});
return initialState;
};

const wrapInHref = (children: ReactNode, href?: string) => {
return href ? (
<div style={{ width: '100%' }}>
<Link href={href} underlineHover={false}>
{children}
</Link>
</div>
) : (
children
);
};

export interface SideNavigationProps extends RouteComponentProps {
/**
* Object responsible for the header at the top of the navigation component. It contains:
Expand All @@ -133,14 +146,25 @@ export interface SideNavigationProps extends RouteComponentProps {
* * Divider: Object that represents a horizontal divider between navigation content.
**/
items?: SideNavigationItem[];
/**
* Determines whether all sections should be expanded by default.
*/
defaultExpandedAll?: boolean;
}

/**
* The side navigation refers to a list of links that point to the pages within an application.
*/
export const SideNavigation: FunctionComponent<SideNavigationProps> = ({ header, items = [], location }) => {
export const SideNavigation: FunctionComponent<SideNavigationProps> = ({
header,
items = [],
defaultExpandedAll = false,
location,
}) => {
const classes = useStyles({});
const [expandedSections, setExpandedSections] = React.useState(populateInitialExpandedState(items));
const [expandedSections, setExpandedSections] = React.useState(
populateInitialExpandedState(items, defaultExpandedAll)
);

const expandToggle = (itemText: string) => {
setExpandedSections((prevExpandedSections) => ({
Expand All @@ -149,18 +173,6 @@ export const SideNavigation: FunctionComponent<SideNavigationProps> = ({ header,
}));
};

const wrapInHref = (children: ReactNode, href?: string) => {
return href ? (
<div style={{ width: '100%' }}>
<Link href={href} underlineHover={false}>
{children}
</Link>
</div>
) : (
children
);
};

const renderDivider = () => <Divider key={uuidv4()} className={classes.divider} />;

const renderItemLabel = (item: SideNavigationItem, cssClass?: string) => {
Expand Down

0 comments on commit a526a26

Please sign in to comment.