Skip to content

Commit

Permalink
Add Navigation component [Feature branch] (#24107)
Browse files Browse the repository at this point in the history
* Initial working tree display

* add styles

* add styles

* dark theme

* back button

* secondary

* BEM style classnames

* remove back button styles

* add menu: 'primary' data propery

* get even more working

* remove extra styles

* add README

* manifest
  • Loading branch information
psealock committed Aug 25, 2020
1 parent a0f36df commit 0834e0f
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 0 deletions.
6 changes: 6 additions & 0 deletions docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,12 @@
"markdown_source": "../packages/components/src/navigable-container/README.md",
"parent": "components"
},
{
"title": "Navigation",
"slug": "navigation",
"markdown_source": "../packages/components/src/navigation/README.md",
"parent": "components"
},
{
"title": "Notice",
"slug": "notice",
Expand Down
43 changes: 43 additions & 0 deletions packages/components/src/navigation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Navigation

Navigation is a component which renders a component which renders a heirarchy of menu items.

## Usage

```jsx
import { MenuItem } from '@wordpress/components';
import { withState } from '@wordpress/compose';

const data = [
{ title: 'My Navigation', slug: 'root', back: 'Back' },
{ title: 'Home', slug: 'home', parent: 'root', menu: 'primary' },
{ title: 'Option one', slug: 'option_one', parent: 'root', menu: 'primary' },
{ title: 'Option two', slug: 'option_two', parent: 'root', menu: 'primary' },
{ title: 'Option three', slug: 'option_three', parent: 'root', menu: 'secondary' },
{ title: 'Child one', slug: 'child_one', parent: 'option_three', menu: 'primary' },
{ title: 'Child two', slug: 'child_two', parent: 'option_three', menu: 'primary' },
{ title: 'Child three', slug: 'child_three', parent: 'option_three', menu: 'primary' },
];

const MyNavigation = () => {
return <Navigation data={ data } initial="home" />;
};
```

## Props

Navigation supports the following props.

### `data`

- Type: `array`
- Required: Yes

An array of config objects for each menu item.

### `initial`

- Type: `string`
- Required: Yes

The active slug.
76 changes: 76 additions & 0 deletions packages/components/src/navigation/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* WordPress dependencies
*/
import { useState } from '@wordpress/element';
import { Icon, arrowLeft } from '@wordpress/icons';

/**
* Internal dependencies
*/
import Button from '../button';
import Text from '../text';
import Item from './item';

const Navigation = ( { data, initial } ) => {
const initialActive = data.find( ( item ) => item.slug === initial );
const [ active, setActive ] = useState( initialActive );
const parent = data.find( ( item ) => item.slug === active.parent );
const items = data.filter( ( item ) => item.parent === active.parent );

const goBack = () => {
if ( ! parent.parent ) {
// We are at top level, will need to handle this case.
return;
}
const parentalSiblings = data.filter(
( item ) => item.parent === parent.parent
);
if ( parentalSiblings.length ) {
setActive( parentalSiblings[ 0 ] );
}
};

return (
<div className="components-navigation">
<Button
isSecondary
className="components-navigation__back"
onClick={ goBack }
>
<Icon icon={ arrowLeft } />
{ parent.back }
</Button>
<div className="components-navigation__title">
<Text variant="title.medium">{ parent.title }</Text>
</div>
<div className="components-navigation__menu-items">
{ items.map( ( item ) =>
item.menu !== 'secondary' ? (
<Item
key={ item.slug }
data={ data }
item={ item }
setActive={ setActive }
isActive={ item.slug === active.slug }
/>
) : null
) }
</div>
<div className="components-navigation__menu-items is-secondary">
{ items.map( ( item ) =>
item.menu === 'secondary' ? (
<Item
key={ item.slug }
data={ data }
item={ item }
setActive={ setActive }
isActive={ item.slug === active.slug }
/>
) : null
) }
</div>
</div>
);
};

export default Navigation;
36 changes: 36 additions & 0 deletions packages/components/src/navigation/item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import { Icon, chevronRight } from '@wordpress/icons';

/**
* Internal dependencies
*/
import Button from '../button';
import Text from '../text';

const Item = ( { data, item, setActive, isActive } ) => {
const children = data.filter( ( d ) => d.parent === item.slug );
const onSelect = () => {
const next = children.length ? children[ 0 ] : item;
setActive( next );
};
const classes = classnames( 'components-navigation__menu-item', {
'is-active': isActive,
} );
return (
<Button className={ classes } onClick={ onSelect } key={ item.slug }>
<Text variant="body.small">
<span>{ item.title }</span>
</Text>
{ children.length ? <Icon icon={ chevronRight } /> : null }
</Button>
);
};

export default Item;
90 changes: 90 additions & 0 deletions packages/components/src/navigation/stories/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* Internal dependencies
*/
import Navigation from '../';

export default {
title: 'Components/Navigation',
component: Navigation,
};

const data = [
{ title: 'WooCommerce', slug: 'root', back: 'Dashboard' },
{ title: 'Home', slug: 'home', parent: 'root', menu: 'primary' },
{
title: 'Analytics',
slug: 'analytics',
parent: 'root',
back: 'WooCommerce Home',
menu: 'primary',
},
{
title: 'Orders',
slug: 'orders',
parent: 'root',
back: 'WooCommerce Home',
menu: 'primary',
},
{
title: 'Overview',
slug: 'overview',
parent: 'analytics',
},
{
title: 'Products report',
slug: 'products',
parent: 'analytics',
},
{
title: 'All orders',
slug: 'all_orders',
parent: 'orders',
},
{
title: 'Payouts',
slug: 'payouts',
parent: 'orders',
},
{
title: 'Settings',
slug: 'settings',
parent: 'root',
back: 'WooCommerce Home',
menu: 'secondary',
},
{
title: 'Extensions',
slug: 'extensions',
parent: 'root',
back: 'WooCommerce Home',
menu: 'secondary',
},
{
title: 'General',
slug: 'general',
parent: 'settings',
},
{
title: 'Tax',
slug: 'tax',
parent: 'settings',
},
{
title: 'My extensions',
slug: 'my_extensions',
parent: 'extensions',
},
{
title: 'Marketplace',
slug: 'marketplace',
parent: 'extensions',
},
];

function Example() {
return <Navigation data={ data } initial="home" />;
}

export const _default = () => {
return <Example />;
};
30 changes: 30 additions & 0 deletions packages/components/src/navigation/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.components-navigation {
width: 272px;
padding: 35px 30px;
}

.components-navigation__back {
margin-bottom: 64px;
}

.components-navigation__title {
margin-bottom: 40px;
}

.components-navigation__menu-items {
display: flex;
flex-direction: column;

&.is-secondary {
margin-top: 24px;
}
}

.components-navigation__menu-item {
display: flex;
justify-content: space-between;

&.is-active span {
border-bottom: 2px solid var(--wp-admin-theme-color);
}
}
1 change: 1 addition & 0 deletions packages/components/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
@import "./menu-item/style.scss";
@import "./menu-items-choice/style.scss";
@import "./modal/style.scss";
@import "./navigation/style.scss";
@import "./notice/style.scss";
@import "./panel/style.scss";
@import "./placeholder/style.scss";
Expand Down

0 comments on commit 0834e0f

Please sign in to comment.