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

Add tree view to the navigation block #35149

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
33 changes: 27 additions & 6 deletions packages/block-library/src/navigation/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,15 @@ import {
getColorClassName,
} from '@wordpress/block-editor';
import { useDispatch, withSelect, withDispatch } from '@wordpress/data';
import { PanelBody, ToggleControl, ToolbarGroup } from '@wordpress/components';
import {
PanelBody,
ToggleControl,
ToolbarGroup,
ToolbarButton,
} from '@wordpress/components';
import { compose } from '@wordpress/compose';
import { __ } from '@wordpress/i18n';
import { listView as treeIcon } from '@wordpress/icons';

/**
* Internal dependencies
Expand Down Expand Up @@ -113,6 +119,9 @@ function Navigation( {

// These props are used by the navigation editor to override specific
// navigation block settings.
defaultToTreeView = false,
hasTreeViewSetting = true,

hasSubmenuIndicatorSetting = true,
hasItemJustificationControls = true,
hasColorSettings = true,
Expand All @@ -126,15 +135,20 @@ function Navigation( {
false
);

const [ isTreeView, setIsTreeView ] = useState( defaultToTreeView );

const { selectBlock } = useDispatch( blockEditorStore );

const navRef = useRef();

const orientation = isTreeView ? 'vertical' : attributes.orientation;

const blockProps = useBlockProps( {
ref: navRef,
className: classnames( className, {
[ `items-justified-${ attributes.itemsJustification }` ]: attributes.itemsJustification,
'is-vertical': attributes.orientation === 'vertical',
'is-vertical': orientation === 'vertical',
'is-tree-view': isTreeView,
'is-responsive': attributes.isResponsive,
'has-text-color': !! textColor.color || !! textColor?.class,
[ getColorClassName(
Expand Down Expand Up @@ -173,17 +187,16 @@ function Navigation( {
className: 'wp-block-navigation__container',
},
{
orientation,
allowedBlocks: ALLOWED_BLOCKS,
__experimentalDefaultBlock: DEFAULT_BLOCK,
__experimentalDirectInsert: DIRECT_INSERT,
orientation: attributes.orientation,
renderAppender: CustomAppender || appender,

// Ensure block toolbar is not too far removed from item
// being edited when in vertical mode.
// see: https://github.com/WordPress/gutenberg/pull/34615.
__experimentalCaptureToolbars:
attributes.orientation !== 'vertical',
__experimentalCaptureToolbars: orientation !== 'vertical',
// Template lock set to false here so that the Nav
// Block on the experimental menus screen does not
// inherit templateLock={ 'all' }.
Expand Down Expand Up @@ -246,7 +259,7 @@ function Navigation( {
}

const justifyAllowedControls =
attributes.orientation === 'vertical'
orientation === 'vertical'
? [ 'left', 'center', 'right' ]
: [ 'left', 'center', 'right', 'space-between' ];

Expand All @@ -266,6 +279,14 @@ function Navigation( {
} }
/>
) }
{ hasTreeViewSetting && (
<ToolbarButton
name="tree-view"
icon={ treeIcon }
title={ __( 'Tree view' ) }
onClick={ () => setIsTreeView( ! isTreeView ) }
/>
) }
<ToolbarGroup>{ navigatorToolbarButton }</ToolbarGroup>
</BlockControls>
{ navigatorModal }
Expand Down
151 changes: 150 additions & 1 deletion packages/block-library/src/navigation/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
}

// Only show the flyout on hover if the parent menu item is selected.
.wp-block-navigation:not(.is-selected):not(.has-child-selected)
.wp-block-navigation:not(.is-selected):not(.has-child-selected):where(:not(.is-tree-view))
.has-child:hover {
> .wp-block-navigation__submenu-container {
opacity: 0;
Expand All @@ -51,6 +51,7 @@
}

// Styles for submenu flyout.
.wp-block-navigation:where(:not(.is-tree-view))
.has-child {
&.is-selected,
&.has-child-selected {
Expand Down Expand Up @@ -515,3 +516,151 @@ body.editor-styles-wrapper
margin-top: $grid-unit-20;
}
}

// Styles for tree-view style menu.
.wp-block-navigation.is-tree-view {
padding: 0;

// Increase specificity.
.wp-block-navigation-item {
display: block;

&.wp-block {
margin: #{$grid-unit-05 + 1px} $grid-unit-05 $grid-unit-05 $grid-unit-05;
}

// Show submenus on click.
> .wp-block-navigation__submenu-container {
// This unsets some styles inherited from the block, meant to only show submenus on click, not hover, when inside the editor.
opacity: 1;
visibility: visible;
display: none;
right: auto;
box-sizing: border-box;
}

// Fix focus outlines.
&.is-selected > .wp-block-navigation-item__content,
&.is-selected:hover > .wp-block-navigation-item__content {
box-shadow: 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
}

&.block-editor-block-list__block:not([contenteditable]):focus::after {
display: none;
}

.wp-block-navigation-item__content.wp-block-navigation-item__content.wp-block-navigation-item__content {
position: relative;
padding: 0.5em 1em;
margin-right: 0;
border-radius: $radius-block-ui;

&:hover {
box-shadow: 0 0 0 $border-width $gray-600;
}
}

.wp-block-navigation-item__label,
.wp-block-navigation-item__placeholder-text,
.wp-block-navigation-link__label,
.wp-block-navigation-link__placeholder-text {
padding: $grid-unit-05;
padding-left: $grid-unit-10;
}

.wp-block-navigation-item__label,
.wp-block-navigation-link__label {
// Without this Links with submenus display a pointer.
cursor: text;
}
}

// Basic Page List support.
ul.wp-block-page-list {
// Make it inert.
background: $gray-100;
border-radius: $radius-block-ui;
pointer-events: none;
margin-right: 0;

.wp-block-navigation-item {
color: $gray-700;
margin-bottom: 6px;
border-radius: $radius-block-ui;
padding: $grid-unit-05;
padding-left: $grid-unit-10;
}
}

// Submenu icon indicator.
.wp-block-navigation__submenu-icon {
position: absolute;
top: 50%;
margin-top: -7px;
left: 0;
padding: 0;
pointer-events: none;

svg {
// Point rightwards.
transform: rotate(-90deg);
transition: transform 0.2s ease;
@include reduce-motion("transition");
}
}

// Point downwards when open.
.wp-block-navigation-submenu.is-selected > .wp-block-navigation-item__content > .wp-block-navigation__submenu-icon svg,
.wp-block-navigation-submenu.has-child-selected > .wp-block-navigation-item__content > .wp-block-navigation__submenu-icon svg {
transform: rotate(0deg);
}

// Override inherited values to optimize menu items for the screen context.
.wp-block-navigation-submenu.has-child,
.wp-block-navigation-item.has-child {
cursor: default;
border-radius: $radius-block-ui;
}

// Override for deeply nested submenus.
.has-child .wp-block-navigation__container .wp-block-navigation__submenu-container {
left: auto;
}

// When editing a submenu with children, highlight the parent
// and adjust the spacing and submenu icon.
.wp-block-navigation-submenu.is-editing {
> .wp-block-navigation__submenu-container {
opacity: 1;
visibility: visible;
position: relative;
background: transparent;
top: auto;
left: auto;
padding-left: $grid-unit-20 + $grid-unit-05;
min-width: auto;
width: 100%;
border: none;
display: block;

&::before {
display: none;
}
}
}

// Appender styles
.block-list-appender {
// Make appender rows the same height as items and center the button vertically.
display: flex;
flex-direction: column;
justify-content: center;
height: $grid-unit-50;
margin: $grid-unit-10 0;
}

.block-editor-button-block-appender.block-list-appender__toggle {
margin: 0 0 0 $grid-unit-30;
padding: 0;
}
}
13 changes: 10 additions & 3 deletions packages/block-library/src/navigation/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,12 @@
a {
margin: 0;
}
}
}

// Styles for when tree view isn't active.
.wp-block-navigation:where(:not(.is-tree-view)) .has-child {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't like how an editor-only classname creeps into style.css, but I don't think there's an easy way around this – style.scss is loaded in the editor so it needs to acknowledge editor matters.

:where(.wp-block-navigation__submenu-container) {
// Submenu indentation when there's no background.
left: -1em;
top: 100%;
Expand Down Expand Up @@ -228,9 +233,11 @@
*/

// Menu items with no background.
.wp-block-navigation .wp-block-page-list,
.wp-block-navigation__container {
gap: 0.5em 2em;
.wp-block-navigation:where(:not(.is-tree-view)) {
.wp-block-page-list,
.wp-block-navigation__container {
gap: 0.5em 2em;
}
}

// Menu items with background.
Expand Down
Loading