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 global inserter to Nav editor screen #34619

Merged
merged 34 commits into from
Sep 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
8b4eadb
Scaffold out very basic interface
getdave Sep 14, 2021
91c11d2
Wire up store state and UI
getdave Sep 7, 2021
04a1008
Add inserter button to header toolbar
getdave Sep 7, 2021
080da88
Use correct classname
getdave Sep 7, 2021
ce85b36
Use optimal props on inserter toggle
getdave Sep 7, 2021
a248cf2
Allow global inserter to insert blocks at root level of Nav block
getdave Sep 7, 2021
ff8c787
Avoid displaying inserter if there are no blocks to insert
getdave Sep 7, 2021
cf3a33f
Hide previews as they don't provide much value here
getdave Sep 7, 2021
3338882
Refactor Inserter to dedicate component
getdave Sep 8, 2021
14f0e31
Remove hardcoded conditional
getdave Sep 8, 2021
a30ac83
Remove unwanted ref usage
getdave Sep 8, 2021
c867936
Add toggle button styles and remove close button on larger screens
getdave Sep 8, 2021
d721afb
Allow tools to show on mobile viewports
getdave Sep 8, 2021
88c5de6
Conditionalise render of sidebar
getdave Sep 14, 2021
21b9b0e
Only hide undo/redo on smaller viewports
getdave Sep 8, 2021
2c3793f
Simplify Navigation Block hook
getdave Sep 8, 2021
70354c8
Ensure global inserter always targets root nav block
getdave Sep 8, 2021
8d1d7c8
Ensure items always inserted at end if root nav block is selected
getdave Sep 9, 2021
497d830
Update to use correct exported variable name
getdave Sep 9, 2021
d28bdaf
Handle focus and tab trapping via hook
getdave Sep 9, 2021
020a9a2
Rename component to make it clear it's the inserter button
getdave Sep 10, 2021
2d68661
Simplify secondary sidebar
getdave Sep 14, 2021
119c6ce
Alter directory structure in order to improve portability of code
getdave Sep 10, 2021
7518cb5
Make insertion point logic explicit
getdave Sep 10, 2021
3002c38
Add docblocks to store
getdave Sep 10, 2021
197204c
Add selector state guard
getdave Sep 10, 2021
1136792
Implement Browse All on quick inserter.
getdave Sep 10, 2021
02124b0
Move constant outside component body
getdave Sep 14, 2021
1571d00
Add dep to useSelect
getdave Sep 14, 2021
ed0ba2a
Add another dep to useSelect
getdave Sep 14, 2021
7d98bcf
Remove ref
getdave Sep 14, 2021
09edddc
Sort out Prettier's mess
getdave Sep 14, 2021
b7da582
Rename Inserter Button to Inserter Toggle for clarity and consistency
getdave Sep 14, 2021
a63d3ce
Apply correct CSS naming convention
getdave Sep 14, 2021
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: 22 additions & 11 deletions packages/edit-navigation/src/components/header/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { decodeEntities } from '@wordpress/html-entities';
import SaveButton from './save-button';
import UndoButton from './undo-button';
import RedoButton from './redo-button';
import InserterToggle from './inserter-toggle';
import MenuSwitcher from '../menu-switcher';
import { useMenuEntityProp } from '../../hooks';

Expand All @@ -26,7 +27,9 @@ export default function Header( {
navigationPost,
} ) {
const isMediumViewport = useViewportMatch( 'medium' );

const [ menuName ] = useMenuEntityProp( 'name', selectedMenuId );

let actionHeaderText;

if ( menuName ) {
Expand All @@ -44,23 +47,31 @@ export default function Header( {

return (
<div className="edit-navigation-header">
{ isMediumViewport && (
<div className="edit-navigation-header__toolbar-wrapper">
<div className="edit-navigation-header__toolbar-wrapper">
{ isMediumViewport && (
<h1 className="edit-navigation-header__title">
{ __( 'Navigation' ) }
</h1>
<NavigableToolbar
className="edit-navigation-header__toolbar"
aria-label={ __( 'Document tools' ) }
>
<UndoButton />
<RedoButton />
</NavigableToolbar>
</div>
) }
) }

<NavigableToolbar
className="edit-navigation-header__toolbar"
aria-label={ __( 'Document tools' ) }
>
<InserterToggle />
{ isMediumViewport && (
<>
<UndoButton />
<RedoButton />
</>
) }
</NavigableToolbar>
</div>

<h2 className="edit-navigation-header__subtitle">
{ isMenuSelected && decodeEntities( actionHeaderText ) }
</h2>

{ isMenuSelected && (
<div className="edit-navigation-header__actions">
<DropdownMenu
Expand Down
57 changes: 57 additions & 0 deletions packages/edit-navigation/src/components/header/inserter-toggle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* WordPress dependencies
*/
import { store as blockEditorStore } from '@wordpress/block-editor';
import { Button, ToolbarItem } from '@wordpress/components';
import { _x } from '@wordpress/i18n';
import { useSelect, useDispatch } from '@wordpress/data';
import { plus } from '@wordpress/icons';

/**
* Internal dependencies
*/
import { useNavigationEditorRootBlock } from '../../hooks';
import { store as editNavigationStore } from '../../store';

function InserterToggle() {
const { navBlockClientId } = useNavigationEditorRootBlock();

const { isInserterOpened, hasInserterItems } = useSelect(
( select ) => {
return {
hasInserterItems: select( blockEditorStore ).hasInserterItems(
navBlockClientId
),
isInserterOpened: select(
editNavigationStore
).isInserterOpened(),
};
},
[ navBlockClientId ]
);

const { setIsInserterOpened } = useDispatch( editNavigationStore );

return (
<ToolbarItem
as={ Button }
className="edit-navigation-header-inserter-toggle"
variant="primary"
isPressed={ isInserterOpened }
onMouseDown={ ( event ) => {
event.preventDefault();
} }
onClick={ () => setIsInserterOpened( ! isInserterOpened ) }
icon={ plus }
/* translators: button label text should, if possible, be under 16
characters. */
label={ _x(
'Toggle block inserter',
'Generic label for block inserter button'
) }
disabled={ ! hasInserterItems }
/>
);
}

export default InserterToggle;
31 changes: 31 additions & 0 deletions packages/edit-navigation/src/components/header/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,34 @@
display: none;
}
}


// INSERTER TOGGLE
.edit-navigation-header-inserter-toggle {

svg {
transition: transform cubic-bezier(0.165, 0.84, 0.44, 1) 0.2s;
@include reduce-motion("transition");
}

// Make the button appear like a "X" close button.
&.is-pressed {
svg {
transform: rotate(45deg);
}
}
}

// INSERTER PANEL
.edit-navigation-layout__inserter-panel-header {
padding-top: $grid-unit-10;
padding-right: $grid-unit-10;
display: flex;
justify-content: flex-end;

// Hide close button within panel on larger screens as this
// action is provided by the inserter toggle or ESC key.
@include break-medium() {
display: none;
}
}
95 changes: 95 additions & 0 deletions packages/edit-navigation/src/components/inserter-sidebar/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* WordPress dependencies
*/
import { Button } from '@wordpress/components';
import { close } from '@wordpress/icons';
import {
__experimentalLibrary as Library,
store as blockEditorStore,
} from '@wordpress/block-editor';
import {
useViewportMatch,
__experimentalUseDialog as useDialog,
} from '@wordpress/compose';
import { useDispatch, useSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import { store as editNavigationStore } from '../../store';
import { useNavigationEditorRootBlock } from '../../hooks';

const SHOW_PREVIEWS = false;

function InserterSidebar() {
const isMobileViewport = useViewportMatch( 'medium', '<' );

const {
navBlockClientId,
lastNavBlockItemIndex,
} = useNavigationEditorRootBlock();

const { hasInserterItems, selectedBlockClientId } = useSelect(
( select ) => {
return {
hasInserterItems: select( blockEditorStore ).hasInserterItems(
navBlockClientId
),
selectedBlockClientId: select(
blockEditorStore
).getSelectedBlock()?.clientId,
};
},
[ navBlockClientId ]
);

const { setIsInserterOpened } = useDispatch( editNavigationStore );

const [ inserterDialogRef, inserterDialogProps ] = useDialog( {
onClose: () => setIsInserterOpened( false ),
} );

// Only concerned with whether there are items to display. If not then
// we shouldn't render.
if ( ! hasInserterItems ) {
return null;
}

const shouldInsertInNavBlock =
! selectedBlockClientId || navBlockClientId === selectedBlockClientId;

return (
<div
ref={ inserterDialogRef }
{ ...inserterDialogProps }
className="edit-navigation-layout__inserter-panel"
>
<div className="edit-navigation-layout__inserter-panel-header">
<Button
icon={ close }
onClick={ () => setIsInserterOpened( false ) }
/>
</div>
<div className="edit-navigation-layout__inserter-panel-content">
<Library
// If the root Nav block is selected then any items inserted by the
// global inserter should append after the last nav item. Otherwise
// simply allow default Gutenberg behaviour.
rootClientId={
shouldInsertInNavBlock ? navBlockClientId : undefined
} // If set, insertion will be into the block with this ID.
__experimentalInsertionIndex={
// If set, insertion will be into this explicit position.
shouldInsertInNavBlock
? lastNavBlockItemIndex
: undefined
}
shouldFocusBlock={ isMobileViewport }
showInserterHelpPanel={ SHOW_PREVIEWS }
/>
</div>
</div>
);
}

export default InserterSidebar;
8 changes: 7 additions & 1 deletion packages/edit-navigation/src/components/layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import Sidebar from '../sidebar';
import Header from '../header';
import Notices from '../notices';
import Editor from '../editor';
import InserterSidebar from '../inserter-sidebar';
import UnsavedChangesWarning from './unsaved-changes-warning';
import { store as editNavigationStore } from '../../store';

Expand All @@ -44,6 +45,7 @@ const interfaceLabels = {
body: __( 'Navigation menu blocks' ),
/* translators: accessibility text for the navigation screen settings landmark region. */
sidebar: __( 'Navigation settings' ),
secondarySidebar: __( 'Block library' ),
};

export default function Layout( { blockEditorSettings } ) {
Expand All @@ -70,11 +72,12 @@ export default function Layout( { blockEditorSettings } ) {
navigationPost
);

const { hasSidebarEnabled } = useSelect(
const { hasSidebarEnabled, isInserterOpened } = useSelect(
( select ) => ( {
hasSidebarEnabled: !! select(
interfaceStore
).getActiveComplementaryArea( 'core/edit-navigation' ),
isInserterOpened: select( editNavigationStore ).isInserterOpened(),
} ),
[]
);
Expand Down Expand Up @@ -175,6 +178,9 @@ export default function Layout( { blockEditorSettings } ) {
<ComplementaryArea.Slot scope="core/edit-navigation" />
)
}
secondarySidebar={
isInserterOpened && <InserterSidebar />
}
/>
{ isMenuSelected && (
<Sidebar
Expand Down
1 change: 1 addition & 0 deletions packages/edit-navigation/src/hooks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export { default as useNavigationBlockEditor } from './use-navigation-block-edit
export { default as useMenuNotifications } from './use-menu-notifications';
export { default as useSelectedMenuId } from './use-selected-menu-id';
export { default as useMenuLocations } from './use-menu-locations';
export { default as useNavigationEditorRootBlock } from './use-navigation-editor-root-block';
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';
import { store as blockEditorStore } from '@wordpress/block-editor';

/**
* Internal dependencies
*/

const useNavigationEditorRootBlock = () => {
getdave marked this conversation as resolved.
Show resolved Hide resolved
return useSelect( ( select ) => {
const { getBlockOrder } = select( blockEditorStore );

const lockedNavigationBlock = getBlockOrder()[ 0 ];

return {
navBlockClientId: lockedNavigationBlock,
lastNavBlockItemIndex: getBlockOrder( lockedNavigationBlock )
.length,
};
}, [] );
};

export default useNavigationEditorRootBlock;
53 changes: 44 additions & 9 deletions packages/edit-navigation/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,68 @@ import {
registerCoreBlocks,
__experimentalRegisterExperimentalCoreBlocks,
} from '@wordpress/block-library';
import { render } from '@wordpress/element';
import { render, useMemo } from '@wordpress/element';
import { __experimentalFetchLinkSuggestions as fetchLinkSuggestions } from '@wordpress/core-data';
import { useDispatch } from '@wordpress/data';

/**
* Internal dependencies
*/
import { store as editNavigationStore } from './store';
import { addFilters } from './filters';
import Layout from './components/layout';

function NavEditor( { settings } ) {
const { setIsInserterOpened } = useDispatch( editNavigationStore );

// Allows the QuickInserter to toggle the sidebar inserter.
// This is marked as experimental to give time for the quick inserter to mature.
const __experimentalSetIsInserterOpened = setIsInserterOpened;

// Provide link suggestions handler to fetch search results for Link UI.
const __experimentalFetchLinkSuggestions = ( search, searchOptions ) =>
fetchLinkSuggestions( search, searchOptions, settings );

const editorSettings = useMemo( () => {
return {
...settings,
__experimentalFetchLinkSuggestions,
__experimentalSetIsInserterOpened,
};
}, [
settings,
__experimentalFetchLinkSuggestions,
__experimentalSetIsInserterOpened,
] );

return <Layout blockEditorSettings={ editorSettings } />;
}

/**
* Internal dependencies
* Setup and registration of editor.
*
* @param {Object} settings blockEditor settings.
*/
import Layout from './components/layout';
import './store';

export function initialize( id, settings ) {
function setUpEditor( settings ) {
addFilters( ! settings.blockNavMenus );
registerCoreBlocks();

if ( process.env.GUTENBERG_PHASE === 2 ) {
__experimentalRegisterExperimentalCoreBlocks();
}
}

settings.__experimentalFetchLinkSuggestions = ( search, searchOptions ) =>
fetchLinkSuggestions( search, searchOptions, settings );
/**
* Initalise and render editor into DOM.
*
* @param {string} id ID of HTML element into which the editor will be rendered.
* @param {Object} settings blockEditor settings.
*/
export function initialize( id, settings ) {
setUpEditor( settings );

render(
<Layout blockEditorSettings={ settings } />,
<NavEditor settings={ settings } />,
document.getElementById( id )
);
}
Loading