From 87c1c997ef8ecb2d5aedc817c9ea1067417caa31 Mon Sep 17 00:00:00 2001 From: Kerry Liu Date: Fri, 15 Oct 2021 09:34:19 -0700 Subject: [PATCH 01/17] List View: add e2e utils for list view open and close --- packages/e2e-test-utils/README.md | 8 ++++++ packages/e2e-test-utils/src/index.js | 1 + packages/e2e-test-utils/src/list-view.js | 33 ++++++++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 packages/e2e-test-utils/src/list-view.js diff --git a/packages/e2e-test-utils/README.md b/packages/e2e-test-utils/README.md index 032b522b5105e..df8ca4bd42792 100644 --- a/packages/e2e-test-utils/README.md +++ b/packages/e2e-test-utils/README.md @@ -111,6 +111,10 @@ _Parameters_ Undocumented declaration. +### closeListView + +Closes list view + ### createEmbeddingMatcher Creates a function to determine if a request is embedding a certain URL. @@ -508,6 +512,10 @@ Clicks on the button in the header which opens Document Settings sidebar when it Opens the global block inserter. +### openListView + +Opens list view + ### openPreviewPage Opens the preview page of an edited post. diff --git a/packages/e2e-test-utils/src/index.js b/packages/e2e-test-utils/src/index.js index 1b3d6000aaaef..517f7e5b506ce 100644 --- a/packages/e2e-test-utils/src/index.js +++ b/packages/e2e-test-utils/src/index.js @@ -93,5 +93,6 @@ export { rest as __experimentalRest, batch as __experimentalBatch, } from './rest-api'; +export { openListView, closeListView } from './list-view'; export * from './mocks'; diff --git a/packages/e2e-test-utils/src/list-view.js b/packages/e2e-test-utils/src/list-view.js new file mode 100644 index 0000000000000..03121c5f84af7 --- /dev/null +++ b/packages/e2e-test-utils/src/list-view.js @@ -0,0 +1,33 @@ +async function toggleListView() { + await page.click( + '.edit-post-header-toolbar__list-view-toggle, .edit-site-header-toolbar__list-view-toggle' + ); +} + +async function isListViewOpen() { + return await page.evaluate( () => { + return !! document.querySelector( + '.edit-post-header-toolbar__list-view-toggle.is-pressed, .edit-site-header-toolbar__list-view-toggle.is-pressed' + ); + } ); +} + +/** + * Opens list view + */ +export async function openListView() { + const isOpen = await isListViewOpen(); + if ( ! isOpen ) { + await toggleListView(); + } +} + +/** + * Closes list view + */ +export async function closeListView() { + const isOpen = await isListViewOpen(); + if ( isOpen ) { + await toggleListView(); + } +} From 96ef0bef353dda605801f688290c8ee36a20ebcf Mon Sep 17 00:00:00 2001 From: Kerry Liu Date: Fri, 15 Oct 2021 09:47:31 -0700 Subject: [PATCH 02/17] remove onClick in branch --- .../src/components/list-view/block.js | 24 ++++++++++++------- .../src/components/list-view/branch.js | 7 +----- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/block-editor/src/components/list-view/block.js b/packages/block-editor/src/components/list-view/block.js index f9b7bc8bbc973..dbea2ee9bdab6 100644 --- a/packages/block-editor/src/components/list-view/block.js +++ b/packages/block-editor/src/components/list-view/block.js @@ -11,7 +11,7 @@ import { __experimentalTreeGridItem as TreeGridItem, } from '@wordpress/components'; import { moreVertical } from '@wordpress/icons'; -import { useState, useRef, useEffect } from '@wordpress/element'; +import { useState, useRef, useEffect, useCallback } from '@wordpress/element'; import { useDispatch } from '@wordpress/data'; /** @@ -33,7 +33,7 @@ export default function ListViewBlock( { isDragged, isBranchSelected, isLastOfSelectedBranch, - onClick, + selectBlock, onToggleExpanded, position, level, @@ -82,14 +82,22 @@ export default function ListViewBlock( { ? toggleBlockHighlight : () => {}; - const onMouseEnter = () => { + const onMouseEnter = useCallback( () => { setIsHovered( true ); highlightBlock( clientId, true ); - }; - const onMouseLeave = () => { + }, [ clientId, setIsHovered, highlightBlock ] ); + const onMouseLeave = useCallback( () => { setIsHovered( false ); highlightBlock( clientId, false ); - }; + }, [ clientId, setIsHovered, highlightBlock ] ); + + const selectEditorBlock = useCallback( + ( event ) => { + event.stopPropagation(); + selectBlock( clientId ); + }, + [ clientId, selectBlock ] + ); const classes = classnames( { 'is-selected': isSelected, @@ -125,7 +133,7 @@ export default function ListViewBlock( {
) } diff --git a/packages/block-editor/src/components/list-view/branch.js b/packages/block-editor/src/components/list-view/branch.js index ccc0010b96a05..0fb3d14bee971 100644 --- a/packages/block-editor/src/components/list-view/branch.js +++ b/packages/block-editor/src/components/list-view/branch.js @@ -84,11 +84,6 @@ export default function ListViewBranch( props ) { ? expandedState[ clientId ] ?? true : undefined; - const selectBlockWithClientId = ( event ) => { - event.stopPropagation(); - selectBlock( clientId ); - }; - const toggleExpanded = ( event ) => { event.stopPropagation(); if ( isExpanded === true ) { @@ -106,7 +101,7 @@ export default function ListViewBranch( props ) { Date: Fri, 15 Oct 2021 09:49:29 -0700 Subject: [PATCH 03/17] removed unused terminated levels --- packages/block-editor/src/components/list-view/branch.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/block-editor/src/components/list-view/branch.js b/packages/block-editor/src/components/list-view/branch.js index 0fb3d14bee971..e0ca78a0ad5b7 100644 --- a/packages/block-editor/src/components/list-view/branch.js +++ b/packages/block-editor/src/components/list-view/branch.js @@ -25,7 +25,6 @@ export default function ListViewBranch( props ) { showNestedBlocks, parentBlockClientId, level = 1, - terminatedLevels = [], path = [], isBranchSelected = false, isLastOfBranch = false, @@ -56,10 +55,6 @@ export default function ListViewBranch( props ) { { map( filteredBlocks, ( block, index ) => { const { clientId, innerBlocks } = block; const position = index + 1; - const isLastRowAtLevel = rowCount === position; - const updatedTerminatedLevels = isLastRowAtLevel - ? [ ...terminatedLevels, level ] - : terminatedLevels; const updatedPath = [ ...path, position ]; const hasNestedBlocks = showNestedBlocks && !! innerBlocks && !! innerBlocks.length; @@ -112,7 +107,6 @@ export default function ListViewBranch( props ) { rowCount={ rowCount } siblingBlockCount={ blockCount } showBlockMovers={ showBlockMovers } - terminatedLevels={ terminatedLevels } path={ updatedPath } isExpanded={ isExpanded } /> @@ -127,7 +121,6 @@ export default function ListViewBranch( props ) { showNestedBlocks={ showNestedBlocks } parentBlockClientId={ clientId } level={ level + 1 } - terminatedLevels={ updatedTerminatedLevels } path={ updatedPath } /> ) } @@ -140,7 +133,6 @@ export default function ListViewBranch( props ) { position={ rowCount } rowCount={ appenderPosition } level={ level } - terminatedLevels={ terminatedLevels } path={ [ ...path, appenderPosition ] } /> ) } From 153d4fb450c6f55fee0d4e72a3ae52bccd837eae Mon Sep 17 00:00:00 2001 From: Kerry Liu Date: Fri, 15 Oct 2021 09:54:18 -0700 Subject: [PATCH 04/17] use callback for toggle expand/collapse --- .../src/components/list-view/block.js | 17 +++++++++++++++-- .../src/components/list-view/branch.js | 12 ------------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/packages/block-editor/src/components/list-view/block.js b/packages/block-editor/src/components/list-view/block.js index dbea2ee9bdab6..ed494c61205e6 100644 --- a/packages/block-editor/src/components/list-view/block.js +++ b/packages/block-editor/src/components/list-view/block.js @@ -34,7 +34,6 @@ export default function ListViewBlock( { isBranchSelected, isLastOfSelectedBranch, selectBlock, - onToggleExpanded, position, level, rowCount, @@ -59,6 +58,8 @@ export default function ListViewBlock( { __experimentalFeatures: withExperimentalFeatures, __experimentalPersistentListViewFeatures: withExperimentalPersistentListViewFeatures, isTreeGridMounted, + expand, + collapse, } = useListViewContext(); const listViewBlockSettingsClassName = classnames( 'block-editor-list-view-block__menu-cell', @@ -99,6 +100,18 @@ export default function ListViewBlock( { [ clientId, selectBlock ] ); + const toggleExpanded = useCallback( + ( event ) => { + event.stopPropagation(); + if ( isExpanded === true ) { + collapse( clientId ); + } else if ( isExpanded === false ) { + expand( clientId ); + } + }, + [ clientId, expand, collapse, isExpanded ] + ); + const classes = classnames( { 'is-selected': isSelected, 'is-branch-selected': @@ -134,7 +147,7 @@ export default function ListViewBlock( { { - event.stopPropagation(); - if ( isExpanded === true ) { - collapse( clientId ); - } else if ( isExpanded === false ) { - expand( clientId ); - } - }; - // Make updates to the selected or dragged blocks synchronous, // but asynchronous for any other block. const isDragged = !! draggedClientIds?.includes( clientId ); @@ -97,7 +86,6 @@ export default function ListViewBranch( props ) { Date: Fri, 15 Oct 2021 10:05:53 -0700 Subject: [PATCH 05/17] update path to be a string to avoid ref changes --- .../src/components/list-view/branch.js | 15 ++++++++++++--- .../block-editor/src/components/list-view/leaf.js | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/list-view/branch.js b/packages/block-editor/src/components/list-view/branch.js index 7662fd1dbc303..8f6d71b3683bc 100644 --- a/packages/block-editor/src/components/list-view/branch.js +++ b/packages/block-editor/src/components/list-view/branch.js @@ -25,7 +25,7 @@ export default function ListViewBranch( props ) { showNestedBlocks, parentBlockClientId, level = 1, - path = [], + path = '', isBranchSelected = false, isLastOfBranch = false, } = props; @@ -53,7 +53,12 @@ export default function ListViewBranch( props ) { { map( filteredBlocks, ( block, index ) => { const { clientId, innerBlocks } = block; const position = index + 1; - const updatedPath = [ ...path, position ]; + // If the string value changes, it's used to trigger an animation change. + // This may be removed if we use a different animation library in the future. + const updatedPath = + path.length > 0 + ? `${ path }_${ position }` + : `${ position }`; const hasNestedBlocks = showNestedBlocks && !! innerBlocks && !! innerBlocks.length; const hasNestedAppender = itemHasAppender( clientId ); @@ -121,7 +126,11 @@ export default function ListViewBranch( props ) { position={ rowCount } rowCount={ appenderPosition } level={ level } - path={ [ ...path, appenderPosition ] } + path={ + path.length > 0 + ? `${ path }_${ appenderPosition }` + : `${ appenderPosition }` + } /> ) } diff --git a/packages/block-editor/src/components/list-view/leaf.js b/packages/block-editor/src/components/list-view/leaf.js index 8098d44647fc9..41bf4bc34cc66 100644 --- a/packages/block-editor/src/components/list-view/leaf.js +++ b/packages/block-editor/src/components/list-view/leaf.js @@ -30,7 +30,7 @@ export default function ListViewLeaf( { isSelected, adjustScrolling: false, enableAnimation: true, - triggerAnimationOnChange: path.join( '_' ), + triggerAnimationOnChange: path, } ); return ( From 79bb7045f40c94f0b1de1b852139f13a36601621 Mon Sep 17 00:00:00 2001 From: Kerry Liu Date: Sat, 16 Oct 2021 10:36:04 -0700 Subject: [PATCH 06/17] List View: experimental change to move selection querying to List View Block to avoid re-rendering all items on block focus --- .../src/components/list-view/block.js | 54 +++++++++++---- .../src/components/list-view/branch.js | 68 ++----------------- .../src/components/list-view/index.js | 8 +-- .../list-view/use-list-view-client-ids.js | 48 ++----------- 4 files changed, 55 insertions(+), 123 deletions(-) diff --git a/packages/block-editor/src/components/list-view/block.js b/packages/block-editor/src/components/list-view/block.js index ed494c61205e6..69f5d42ab8852 100644 --- a/packages/block-editor/src/components/list-view/block.js +++ b/packages/block-editor/src/components/list-view/block.js @@ -12,7 +12,7 @@ import { } from '@wordpress/components'; import { moreVertical } from '@wordpress/icons'; import { useState, useRef, useEffect, useCallback } from '@wordpress/element'; -import { useDispatch } from '@wordpress/data'; +import { useDispatch, useSelect } from '@wordpress/data'; /** * Internal dependencies @@ -26,13 +26,11 @@ import ListViewBlockContents from './block-contents'; import BlockSettingsDropdown from '../block-settings-menu/block-settings-dropdown'; import { useListViewContext } from './context'; import { store as blockEditorStore } from '../../store'; +import { isClientIdSelected } from './utils'; export default function ListViewBlock( { block, - isSelected, isDragged, - isBranchSelected, - isLastOfSelectedBranch, selectBlock, position, level, @@ -48,12 +46,6 @@ export default function ListViewBlock( { const { toggleBlockHighlight } = useDispatch( blockEditorStore ); - const hasSiblings = siblingBlockCount > 0; - const hasRenderedMovers = showBlockMovers && hasSiblings; - const moverCellClassName = classnames( - 'block-editor-list-view-block__mover-cell', - { 'is-visible': isHovered || isSelected } - ); const { __experimentalFeatures: withExperimentalFeatures, __experimentalPersistentListViewFeatures: withExperimentalPersistentListViewFeatures, @@ -61,6 +53,42 @@ export default function ListViewBlock( { expand, collapse, } = useListViewContext(); + + const { isBranchSelected, isSelected } = useSelect( + ( select ) => { + const { + getSelectedBlockClientId, + getSelectedBlockClientIds, + getBlockParents, + } = select( blockEditorStore ); + + const selectedClientIds = withExperimentalPersistentListViewFeatures + ? getSelectedBlockClientIds() + : [ getSelectedBlockClientId() ]; + const blockParents = getBlockParents( clientId ); + const _isSelected = isClientIdSelected( + clientId, + selectedClientIds + ); + return { + isSelected: _isSelected, + isBranchSelected: + _isSelected || + blockParents.some( ( id ) => { + return isClientIdSelected( id, selectedClientIds ); + } ), + }; + }, + [ withExperimentalPersistentListViewFeatures, clientId ] + ); + + const hasSiblings = siblingBlockCount > 0; + const hasRenderedMovers = showBlockMovers && hasSiblings; + const moverCellClassName = classnames( + 'block-editor-list-view-block__mover-cell', + { 'is-visible': isHovered || isSelected } + ); + const listViewBlockSettingsClassName = classnames( 'block-editor-list-view-block__menu-cell', { 'is-visible': isHovered || isSelected } @@ -116,9 +144,9 @@ export default function ListViewBlock( { 'is-selected': isSelected, 'is-branch-selected': withExperimentalPersistentListViewFeatures && isBranchSelected, - 'is-last-of-selected-branch': - withExperimentalPersistentListViewFeatures && - isLastOfSelectedBranch, + // 'is-last-of-selected-branch': + // withExperimentalPersistentListViewFeatures && + // isLastOfSelectedBranch, 'is-dragging': isDragged, } ); diff --git a/packages/block-editor/src/components/list-view/branch.js b/packages/block-editor/src/components/list-view/branch.js index 8f6d71b3683bc..191961a9ee3c1 100644 --- a/packages/block-editor/src/components/list-view/branch.js +++ b/packages/block-editor/src/components/list-view/branch.js @@ -6,47 +6,29 @@ import { map, compact } from 'lodash'; /** * WordPress dependencies */ -import { AsyncModeProvider } from '@wordpress/data'; +import { Fragment } from '@wordpress/element'; /** * Internal dependencies */ import ListViewBlock from './block'; -import ListViewAppender from './appender'; -import { isClientIdSelected } from './utils'; import { useListViewContext } from './context'; export default function ListViewBranch( props ) { const { blocks, selectBlock, - showAppender, showBlockMovers, showNestedBlocks, - parentBlockClientId, level = 1, path = '', - isBranchSelected = false, - isLastOfBranch = false, } = props; - const { - expandedState, - draggedClientIds, - selectedClientIds, - } = useListViewContext(); + const { expandedState, draggedClientIds } = useListViewContext(); - const isTreeRoot = ! parentBlockClientId; const filteredBlocks = compact( blocks ); - const itemHasAppender = ( parentClientId ) => - showAppender && - ! isTreeRoot && - isClientIdSelected( parentClientId, selectedClientIds ); - const hasAppender = itemHasAppender( parentBlockClientId ); // Add +1 to the rowCount to take the block appender into account. const blockCount = filteredBlocks.length; - const rowCount = hasAppender ? blockCount + 1 : blockCount; - const appenderPosition = rowCount; return ( <> @@ -61,24 +43,8 @@ export default function ListViewBranch( props ) { : `${ position }`; const hasNestedBlocks = showNestedBlocks && !! innerBlocks && !! innerBlocks.length; - const hasNestedAppender = itemHasAppender( clientId ); - const hasNestedBranch = hasNestedBlocks || hasNestedAppender; - - const isSelected = isClientIdSelected( - clientId, - selectedClientIds - ); - const isSelectedBranch = - isBranchSelected || ( isSelected && hasNestedBranch ); - - // Logic needed to target the last item of a selected branch which might be deeply nested. - // This is currently only needed for styling purposes. See: `.is-last-of-selected-branch`. - const isLastBlock = index === blockCount - 1; - const isLast = isSelected || ( isLastOfBranch && isLastBlock ); - const isLastOfSelectedBranch = - isLastOfBranch && ! hasNestedBranch && isLastBlock; - const isExpanded = hasNestedBranch + const isExpanded = hasNestedBlocks ? expandedState[ clientId ] ?? true : undefined; @@ -87,52 +53,32 @@ export default function ListViewBranch( props ) { const isDragged = !! draggedClientIds?.includes( clientId ); return ( - + - { hasNestedBranch && isExpanded && ! isDragged && ( + { hasNestedBlocks && isExpanded && ! isDragged && ( ) } - + ); } ) } - { hasAppender && ( - 0 - ? `${ path }_${ appenderPosition }` - : `${ appenderPosition }` - } - /> - ) } ); } diff --git a/packages/block-editor/src/components/list-view/index.js b/packages/block-editor/src/components/list-view/index.js index 9985727a7b451..df1a1f989290c 100644 --- a/packages/block-editor/src/components/list-view/index.js +++ b/packages/block-editor/src/components/list-view/index.js @@ -62,11 +62,7 @@ function ListView( }, ref ) { - const { - clientIdsTree, - selectedClientIds, - draggedClientIds, - } = useListViewClientIds( + const { clientIdsTree, draggedClientIds } = useListViewClientIds( blocks, showOnlyCurrentHierarchy, __experimentalPersistentListViewFeatures @@ -121,7 +117,6 @@ function ListView( __experimentalPersistentListViewFeatures, isTreeGridMounted: isMounted.current, draggedClientIds, - selectedClientIds, expandedState, expand, collapse, @@ -131,7 +126,6 @@ function ListView( __experimentalPersistentListViewFeatures, isMounted.current, draggedClientIds, - selectedClientIds, expandedState, expand, collapse, diff --git a/packages/block-editor/src/components/list-view/use-list-view-client-ids.js b/packages/block-editor/src/components/list-view/use-list-view-client-ids.js index 14b3129bb7409..4fda46d1e3e52 100644 --- a/packages/block-editor/src/components/list-view/use-list-view-client-ids.js +++ b/packages/block-editor/src/components/list-view/use-list-view-client-ids.js @@ -7,49 +7,20 @@ import { useSelect } from '@wordpress/data'; /** * Internal dependencies */ -import { isClientIdSelected } from './utils'; import { store as blockEditorStore } from '../../store'; -const useListViewClientIdsTree = ( - blocks, - selectedClientIds, - showOnlyCurrentHierarchy -) => +const useListViewClientIdsTree = ( blocks, showOnlyCurrentHierarchy ) => useSelect( ( select ) => { - const { - getBlockHierarchyRootClientId, - __unstableGetClientIdsTree, - __unstableGetClientIdWithClientIdsTree, - } = select( blockEditorStore ); - if ( blocks ) { return blocks; } - const isSingleBlockSelected = - selectedClientIds && ! Array.isArray( selectedClientIds ); - if ( ! showOnlyCurrentHierarchy || ! isSingleBlockSelected ) { - return __unstableGetClientIdsTree(); - } - - const rootBlock = __unstableGetClientIdWithClientIdsTree( - getBlockHierarchyRootClientId( selectedClientIds ) - ); - if ( ! rootBlock ) { - return __unstableGetClientIdsTree(); - } - - const hasHierarchy = - ! isClientIdSelected( rootBlock.clientId, selectedClientIds ) || - ( rootBlock.innerBlocks && rootBlock.innerBlocks.length !== 0 ); - if ( hasHierarchy ) { - return [ rootBlock ]; - } + const { __unstableGetClientIdsTree } = select( blockEditorStore ); return __unstableGetClientIdsTree(); }, - [ blocks, selectedClientIds, showOnlyCurrentHierarchy ] + [ blocks, showOnlyCurrentHierarchy ] ); export default function useListViewClientIds( @@ -57,23 +28,17 @@ export default function useListViewClientIds( showOnlyCurrentHierarchy, __experimentalPersistentListViewFeatures ) { - const { selectedClientIds, draggedClientIds } = useSelect( + const { draggedClientIds } = useSelect( ( select ) => { - const { - getSelectedBlockClientId, - getSelectedBlockClientIds, - getDraggedBlockClientIds, - } = select( blockEditorStore ); + const { getDraggedBlockClientIds } = select( blockEditorStore ); if ( __experimentalPersistentListViewFeatures ) { return { - selectedClientIds: getSelectedBlockClientIds(), draggedClientIds: getDraggedBlockClientIds(), }; } return { - selectedClientIds: getSelectedBlockClientId(), draggedClientIds: getDraggedBlockClientIds(), }; }, @@ -81,8 +46,7 @@ export default function useListViewClientIds( ); const clientIdsTree = useListViewClientIdsTree( blocks, - selectedClientIds, showOnlyCurrentHierarchy ); - return { clientIdsTree, selectedClientIds, draggedClientIds }; + return { clientIdsTree, draggedClientIds }; } From ff6d65656371d09d09a50070a154ac79428cf90c Mon Sep 17 00:00:00 2001 From: Kerry Liu Date: Mon, 18 Oct 2021 12:00:11 -0700 Subject: [PATCH 07/17] List View: simplify useListViewClientIds and remove showOnlyCurrentHierarchy prop --- .../components/block-navigation/dropdown.js | 1 - .../src/components/list-view/index.js | 9 +--- .../list-view/use-list-view-client-ids.js | 41 ++++--------------- 3 files changed, 9 insertions(+), 42 deletions(-) diff --git a/packages/block-editor/src/components/block-navigation/dropdown.js b/packages/block-editor/src/components/block-navigation/dropdown.js index 414706ddf7433..a67d0aa2a4e4f 100644 --- a/packages/block-editor/src/components/block-navigation/dropdown.js +++ b/packages/block-editor/src/components/block-navigation/dropdown.js @@ -67,7 +67,6 @@ function BlockNavigationDropdown(
diff --git a/packages/block-editor/src/components/list-view/index.js b/packages/block-editor/src/components/list-view/index.js index df1a1f989290c..5d4a9ae843f35 100644 --- a/packages/block-editor/src/components/list-view/index.js +++ b/packages/block-editor/src/components/list-view/index.js @@ -45,8 +45,6 @@ const expanded = ( state, action ) => { * @param {Object} props Components props. * @param {Array} props.blocks Custom subset of block client IDs to be used instead of the default hierarchy. * @param {Function} props.onSelect Block selection callback. - * @param {boolean} props.showNestedBlocks Flag to enable displaying nested blocks. - * @param {boolean} props.showOnlyCurrentHierarchy Flag to limit the list to the current hierarchy of blocks. * @param {boolean} props.__experimentalFeatures Flag to enable experimental features. * @param {boolean} props.__experimentalPersistentListViewFeatures Flag to enable features for the Persistent List View experiment. * @param {Object} ref Forwarded ref @@ -54,7 +52,6 @@ const expanded = ( state, action ) => { function ListView( { blocks, - showOnlyCurrentHierarchy, onSelect = noop, __experimentalFeatures, __experimentalPersistentListViewFeatures, @@ -62,11 +59,7 @@ function ListView( }, ref ) { - const { clientIdsTree, draggedClientIds } = useListViewClientIds( - blocks, - showOnlyCurrentHierarchy, - __experimentalPersistentListViewFeatures - ); + const { clientIdsTree, draggedClientIds } = useListViewClientIds( blocks ); const { selectBlock } = useDispatch( blockEditorStore ); const selectEditorBlock = useCallback( ( clientId ) => { diff --git a/packages/block-editor/src/components/list-view/use-list-view-client-ids.js b/packages/block-editor/src/components/list-view/use-list-view-client-ids.js index 4fda46d1e3e52..f6c79a722e864 100644 --- a/packages/block-editor/src/components/list-view/use-list-view-client-ids.js +++ b/packages/block-editor/src/components/list-view/use-list-view-client-ids.js @@ -9,44 +9,19 @@ import { useSelect } from '@wordpress/data'; */ import { store as blockEditorStore } from '../../store'; -const useListViewClientIdsTree = ( blocks, showOnlyCurrentHierarchy ) => - useSelect( +export default function useListViewClientIds( blocks ) { + return useSelect( ( select ) => { - if ( blocks ) { - return blocks; - } - - const { __unstableGetClientIdsTree } = select( blockEditorStore ); - - return __unstableGetClientIdsTree(); - }, - [ blocks, showOnlyCurrentHierarchy ] - ); - -export default function useListViewClientIds( - blocks, - showOnlyCurrentHierarchy, - __experimentalPersistentListViewFeatures -) { - const { draggedClientIds } = useSelect( - ( select ) => { - const { getDraggedBlockClientIds } = select( blockEditorStore ); - - if ( __experimentalPersistentListViewFeatures ) { - return { - draggedClientIds: getDraggedBlockClientIds(), - }; - } + const { + getDraggedBlockClientIds, + __unstableGetClientIdsTree, + } = select( blockEditorStore ); return { draggedClientIds: getDraggedBlockClientIds(), + clientIdsTree: blocks ? blocks : __unstableGetClientIdsTree(), }; }, - [ __experimentalPersistentListViewFeatures ] - ); - const clientIdsTree = useListViewClientIdsTree( - blocks, - showOnlyCurrentHierarchy + [ blocks ] ); - return { clientIdsTree, draggedClientIds }; } From 2e0ba25a4b21c7be4bc1daab75bd49ee8477babf Mon Sep 17 00:00:00 2001 From: Kerry Liu Date: Mon, 18 Oct 2021 12:19:52 -0700 Subject: [PATCH 08/17] List View: move nested AsyncModeProvider call to ListViewBlock --- .../src/components/list-view/block.js | 171 +++++++++--------- .../src/components/list-view/index.js | 18 +- 2 files changed, 99 insertions(+), 90 deletions(-) diff --git a/packages/block-editor/src/components/list-view/block.js b/packages/block-editor/src/components/list-view/block.js index 69f5d42ab8852..17e0e39523403 100644 --- a/packages/block-editor/src/components/list-view/block.js +++ b/packages/block-editor/src/components/list-view/block.js @@ -12,7 +12,7 @@ import { } from '@wordpress/components'; import { moreVertical } from '@wordpress/icons'; import { useState, useRef, useEffect, useCallback } from '@wordpress/element'; -import { useDispatch, useSelect } from '@wordpress/data'; +import { useDispatch, useSelect, AsyncModeProvider } from '@wordpress/data'; /** * Internal dependencies @@ -151,92 +151,95 @@ export default function ListViewBlock( { } ); return ( - - + - { ( { ref, tabIndex, onFocus } ) => ( -
- -
- ) } -
- { hasRenderedMovers && ( - <> - - - { ( { ref, tabIndex, onFocus } ) => ( - - ) } - - - { ( { ref, tabIndex, onFocus } ) => ( - - ) } - - - - ) } - - { withExperimentalFeatures && ( - + { ( { ref, tabIndex, onFocus } ) => ( - +
+ +
) }
- ) } -
+ { hasRenderedMovers && ( + <> + + + { ( { ref, tabIndex, onFocus } ) => ( + + ) } + + + { ( { ref, tabIndex, onFocus } ) => ( + + ) } + + + + ) } + + { withExperimentalFeatures && ( + + { ( { ref, tabIndex, onFocus } ) => ( + + ) } + + ) } + + ); } diff --git a/packages/block-editor/src/components/list-view/index.js b/packages/block-editor/src/components/list-view/index.js index 5d4a9ae843f35..7453470d8260c 100644 --- a/packages/block-editor/src/components/list-view/index.js +++ b/packages/block-editor/src/components/list-view/index.js @@ -97,12 +97,18 @@ function ListView( }, [ setExpandedState ] ); - const expandRow = ( row ) => { - expand( row?.dataset?.block ); - }; - const collapseRow = ( row ) => { - collapse( row?.dataset?.block ); - }; + const expandRow = useCallback( + ( row ) => { + expand( row?.dataset?.block ); + }, + [ expand ] + ); + const collapseRow = useCallback( + ( row ) => { + collapse( row?.dataset?.block ); + }, + [ collapse ] + ); const contextValue = useMemo( () => ( { From 7a88277b5a9a3a7491a65b341afcd7203ed80c56 Mon Sep 17 00:00:00 2001 From: Kerry Liu Date: Mon, 18 Oct 2021 13:59:00 -0700 Subject: [PATCH 09/17] List View: make available flags present in JSDoc --- packages/block-editor/src/components/list-view/index.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/block-editor/src/components/list-view/index.js b/packages/block-editor/src/components/list-view/index.js index 7453470d8260c..a69876775ab5a 100644 --- a/packages/block-editor/src/components/list-view/index.js +++ b/packages/block-editor/src/components/list-view/index.js @@ -45,6 +45,8 @@ const expanded = ( state, action ) => { * @param {Object} props Components props. * @param {Array} props.blocks Custom subset of block client IDs to be used instead of the default hierarchy. * @param {Function} props.onSelect Block selection callback. + * @param {boolean} props.showNestedBlocks Flag to enable displaying nested blocks. + * @param {boolean} props.showBlockMovers Flag to enable block movers * @param {boolean} props.__experimentalFeatures Flag to enable experimental features. * @param {boolean} props.__experimentalPersistentListViewFeatures Flag to enable features for the Persistent List View experiment. * @param {Object} ref Forwarded ref @@ -55,6 +57,8 @@ function ListView( onSelect = noop, __experimentalFeatures, __experimentalPersistentListViewFeatures, + showNestedBlocks, + showBlockMovers, ...props }, ref @@ -148,6 +152,8 @@ function ListView( From aa4475abf7d4d922ca9ed5dd582103d44c26a6bd Mon Sep 17 00:00:00 2001 From: Kerry Liu Date: Mon, 18 Oct 2021 14:13:25 -0700 Subject: [PATCH 10/17] List View: remove unneeded is-last-of-selected-branch logic --- packages/block-editor/src/components/list-view/block.js | 3 --- packages/block-editor/src/components/list-view/style.scss | 3 --- 2 files changed, 6 deletions(-) diff --git a/packages/block-editor/src/components/list-view/block.js b/packages/block-editor/src/components/list-view/block.js index 17e0e39523403..d662f7008bc4d 100644 --- a/packages/block-editor/src/components/list-view/block.js +++ b/packages/block-editor/src/components/list-view/block.js @@ -144,9 +144,6 @@ export default function ListViewBlock( { 'is-selected': isSelected, 'is-branch-selected': withExperimentalPersistentListViewFeatures && isBranchSelected, - // 'is-last-of-selected-branch': - // withExperimentalPersistentListViewFeatures && - // isLastOfSelectedBranch, 'is-dragging': isDragged, } ); diff --git a/packages/block-editor/src/components/list-view/style.scss b/packages/block-editor/src/components/list-view/style.scss index eb05d1426c376..d2e488244ab6d 100644 --- a/packages/block-editor/src/components/list-view/style.scss +++ b/packages/block-editor/src/components/list-view/style.scss @@ -57,9 +57,6 @@ &.is-branch-selected:not(.is-selected) .block-editor-list-view-block-contents { border-radius: 0; } - &.is-branch-selected.is-last-of-selected-branch .block-editor-list-view-block-contents { - border-radius: 0 0 2px 2px; - } &.is-dragging { display: none; From 5c40c7e62b5c0e12db6ccdae94fccf8a5f2115f2 Mon Sep 17 00:00:00 2001 From: Kerry Liu Date: Mon, 18 Oct 2021 14:15:52 -0700 Subject: [PATCH 11/17] List View: tidy comments in branch.js --- packages/block-editor/src/components/list-view/branch.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/list-view/branch.js b/packages/block-editor/src/components/list-view/branch.js index 191961a9ee3c1..222fbad712b59 100644 --- a/packages/block-editor/src/components/list-view/branch.js +++ b/packages/block-editor/src/components/list-view/branch.js @@ -27,7 +27,6 @@ export default function ListViewBranch( props ) { const { expandedState, draggedClientIds } = useListViewContext(); const filteredBlocks = compact( blocks ); - // Add +1 to the rowCount to take the block appender into account. const blockCount = filteredBlocks.length; return ( @@ -35,7 +34,7 @@ export default function ListViewBranch( props ) { { map( filteredBlocks, ( block, index ) => { const { clientId, innerBlocks } = block; const position = index + 1; - // If the string value changes, it's used to trigger an animation change. + // This string value is used to trigger an animation change. // This may be removed if we use a different animation library in the future. const updatedPath = path.length > 0 @@ -48,8 +47,6 @@ export default function ListViewBranch( props ) { ? expandedState[ clientId ] ?? true : undefined; - // Make updates to the selected or dragged blocks synchronous, - // but asynchronous for any other block. const isDragged = !! draggedClientIds?.includes( clientId ); return ( From f32d9eebb4dc081197962124796b99a7de9e5ffd Mon Sep 17 00:00:00 2001 From: Kerry Liu Date: Mon, 18 Oct 2021 15:16:09 -0700 Subject: [PATCH 12/17] Edit Widgets: use list view sidebar instead of dropdown --- .../src/components/header/index.js | 45 +++++++---- .../src/components/layout/interface.js | 60 ++++----------- .../src/components/secondary-sidebar/index.js | 34 +++++++++ .../secondary-sidebar/inserter-sidebar.js | 53 +++++++++++++ .../secondary-sidebar/list-view-sidebar.js | 74 +++++++++++++++++++ .../components/secondary-sidebar/style.scss | 25 +++++++ packages/edit-widgets/src/store/actions.js | 13 ++++ packages/edit-widgets/src/store/reducer.js | 33 ++++++++- packages/edit-widgets/src/store/selectors.js | 11 +++ packages/edit-widgets/src/style.scss | 1 + 10 files changed, 286 insertions(+), 63 deletions(-) create mode 100644 packages/edit-widgets/src/components/secondary-sidebar/index.js create mode 100644 packages/edit-widgets/src/components/secondary-sidebar/inserter-sidebar.js create mode 100644 packages/edit-widgets/src/components/secondary-sidebar/list-view-sidebar.js create mode 100644 packages/edit-widgets/src/components/secondary-sidebar/style.scss diff --git a/packages/edit-widgets/src/components/header/index.js b/packages/edit-widgets/src/components/header/index.js index 96d8e6634296a..bf0c5fd6caf5a 100644 --- a/packages/edit-widgets/src/components/header/index.js +++ b/packages/edit-widgets/src/components/header/index.js @@ -5,13 +5,12 @@ import { useSelect, useDispatch } from '@wordpress/data'; import { __, _x } from '@wordpress/i18n'; import { Button, ToolbarItem, VisuallyHidden } from '@wordpress/components'; import { - BlockNavigationDropdown, NavigableToolbar, store as blockEditorStore, } from '@wordpress/block-editor'; import { PinnedItems } from '@wordpress/interface'; -import { plus } from '@wordpress/icons'; -import { useRef } from '@wordpress/element'; +import { listView, plus } from '@wordpress/icons'; +import { useCallback, useRef } from '@wordpress/element'; import { useViewportMatch } from '@wordpress/compose'; /** @@ -35,16 +34,23 @@ function Header() { ), [ widgetAreaClientId ] ); - const isInserterOpened = useSelect( - ( select ) => select( editWidgetsStore ).isInserterOpened(), - [] - ); - const { setIsWidgetAreaOpen, setIsInserterOpened } = useDispatch( - editWidgetsStore - ); + const { isInserterOpen, isListViewOpen } = useSelect( ( select ) => { + const { isInserterOpened, isListViewOpened } = select( + editWidgetsStore + ); + return { + isInserterOpen: isInserterOpened(), + isListViewOpen: isListViewOpened(), + }; + }, [] ); + const { + setIsWidgetAreaOpen, + setIsInserterOpened, + setIsListViewOpened, + } = useDispatch( editWidgetsStore ); const { selectBlock } = useDispatch( blockEditorStore ); const handleClick = () => { - if ( isInserterOpened ) { + if ( isInserterOpen ) { // Focusing the inserter button closes the inserter popover inserterButton.current.focus(); } else { @@ -63,6 +69,11 @@ function Header() { } }; + const toggleListView = useCallback( + () => setIsListViewOpened( ! isListViewOpen ), + [ setIsListViewOpened, isListViewOpen ] + ); + return ( <>
@@ -89,7 +100,7 @@ function Header() { as={ Button } className="edit-widgets-header-toolbar__inserter-toggle" variant="primary" - isPressed={ isInserterOpened } + isPressed={ isInserterOpen } onMouseDown={ ( event ) => { event.preventDefault(); } } @@ -106,7 +117,15 @@ function Header() { <> - + ) } diff --git a/packages/edit-widgets/src/components/layout/interface.js b/packages/edit-widgets/src/components/layout/interface.js index 0969f0dabf9c1..5845321aebab8 100644 --- a/packages/edit-widgets/src/components/layout/interface.js +++ b/packages/edit-widgets/src/components/layout/interface.js @@ -1,16 +1,8 @@ /** * WordPress dependencies */ -import { Button } from '@wordpress/components'; -import { - __experimentalUseDialog as useDialog, - useViewportMatch, -} from '@wordpress/compose'; -import { close } from '@wordpress/icons'; -import { - __experimentalLibrary as Library, - BlockBreadcrumb, -} from '@wordpress/block-editor'; +import { useViewportMatch } from '@wordpress/compose'; +import { BlockBreadcrumb } from '@wordpress/block-editor'; import { useEffect } from '@wordpress/element'; import { useDispatch, useSelect } from '@wordpress/data'; import { @@ -26,8 +18,8 @@ import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; */ import Header from '../header'; import WidgetAreasBlockEditorContent from '../widget-areas-block-editor-content'; -import useWidgetLibraryInsertionPoint from '../../hooks/use-widget-library-insertion-point'; import { store as editWidgetsStore } from '../../store'; +import SecondarySidebar from '../secondary-sidebar'; const interfaceLabels = { /* translators: accessibility text for the widgets screen top bar landmark region. */ @@ -43,15 +35,16 @@ const interfaceLabels = { function Interface( { blockEditorSettings } ) { const isMobileViewport = useViewportMatch( 'medium', '<' ); const isHugeViewport = useViewportMatch( 'huge', '>=' ); - const { setIsInserterOpened, closeGeneralSidebar } = useDispatch( - editWidgetsStore - ); - const { rootClientId, insertionIndex } = useWidgetLibraryInsertionPoint(); - + const { + setIsInserterOpened, + setIsListViewOpened, + closeGeneralSidebar, + } = useDispatch( editWidgetsStore ); const { hasBlockBreadCrumbsEnabled, hasSidebarEnabled, isInserterOpened, + isListViewOpened, previousShortcut, nextShortcut, } = useSelect( @@ -60,6 +53,7 @@ function Interface( { blockEditorSettings } ) { interfaceStore ).getActiveComplementaryArea( editWidgetsStore.name ), isInserterOpened: !! select( editWidgetsStore ).isInserterOpened(), + isListViewOpened: !! select( editWidgetsStore ).isListViewOpened(), hasBlockBreadCrumbsEnabled: select( interfaceStore ).isFeatureActive( 'core/edit-widgets', 'showBlockBreadcrumbs' ), @@ -79,47 +73,21 @@ function Interface( { blockEditorSettings } ) { useEffect( () => { if ( hasSidebarEnabled && ! isHugeViewport ) { setIsInserterOpened( false ); + setIsListViewOpened( false ); } }, [ hasSidebarEnabled, isHugeViewport ] ); useEffect( () => { - if ( isInserterOpened && ! isHugeViewport ) { + if ( ( isInserterOpened || isListViewOpened ) && ! isHugeViewport ) { closeGeneralSidebar(); } - }, [ isInserterOpened, isHugeViewport ] ); - - const [ inserterDialogRef, inserterDialogProps ] = useDialog( { - onClose: () => setIsInserterOpened( false ), - } ); + }, [ isInserterOpened, isListViewOpened, isHugeViewport ] ); return ( } - secondarySidebar={ - isInserterOpened && ( -
-
-
-
- -
-
- ) - } + secondarySidebar={ } sidebar={ hasSidebarEnabled && ( diff --git a/packages/edit-widgets/src/components/secondary-sidebar/index.js b/packages/edit-widgets/src/components/secondary-sidebar/index.js new file mode 100644 index 0000000000000..74d84238a0663 --- /dev/null +++ b/packages/edit-widgets/src/components/secondary-sidebar/index.js @@ -0,0 +1,34 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +/** + * Internal dependencies + */ +import { store as editWidgetsStore } from '../../store'; + +/** + * Internal dependencies + */ +import InserterSidebar from './inserter-sidebar'; +import ListViewSidebar from './list-view-sidebar'; + +export default function SecondarySidebar() { + const { isInserterOpen, isListViewOpen } = useSelect( ( select ) => { + const { isInserterOpened, isListViewOpened } = select( + editWidgetsStore + ); + return { + isInserterOpen: isInserterOpened(), + isListViewOpen: isListViewOpened(), + }; + }, [] ); + + if ( isInserterOpen ) { + return ; + } + if ( isListViewOpen ) { + return ; + } + return null; +} diff --git a/packages/edit-widgets/src/components/secondary-sidebar/inserter-sidebar.js b/packages/edit-widgets/src/components/secondary-sidebar/inserter-sidebar.js new file mode 100644 index 0000000000000..5c60ef401ca5a --- /dev/null +++ b/packages/edit-widgets/src/components/secondary-sidebar/inserter-sidebar.js @@ -0,0 +1,53 @@ +/** + * WordPress dependencies + */ +import { Button } from '@wordpress/components'; +import { close } from '@wordpress/icons'; +import { __experimentalLibrary as Library } from '@wordpress/block-editor'; +import { + useViewportMatch, + __experimentalUseDialog as useDialog, +} from '@wordpress/compose'; +import { useCallback } from '@wordpress/element'; +import { useDispatch } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import useWidgetLibraryInsertionPoint from '../../hooks/use-widget-library-insertion-point'; +import { store as editWidgetsStore } from '../../store'; + +export default function InserterSidebar() { + const isMobileViewport = useViewportMatch( 'medium', '<' ); + const { rootClientId, insertionIndex } = useWidgetLibraryInsertionPoint(); + + const { setIsInserterOpened } = useDispatch( editWidgetsStore ); + + const closeInserter = useCallback( () => { + return () => setIsInserterOpened( false ); + }, [ setIsInserterOpened ] ); + + const [ inserterDialogRef, inserterDialogProps ] = useDialog( { + onClose: closeInserter, + } ); + + return ( +
+
+
+
+ +
+
+ ); +} diff --git a/packages/edit-widgets/src/components/secondary-sidebar/list-view-sidebar.js b/packages/edit-widgets/src/components/secondary-sidebar/list-view-sidebar.js new file mode 100644 index 0000000000000..0fe7a15c67941 --- /dev/null +++ b/packages/edit-widgets/src/components/secondary-sidebar/list-view-sidebar.js @@ -0,0 +1,74 @@ +/** + * WordPress dependencies + */ +import { + __experimentalListView as ListView, + store as blockEditorStore, +} from '@wordpress/block-editor'; +import { Button } from '@wordpress/components'; +import { + useFocusOnMount, + useFocusReturn, + useInstanceId, + useMergeRefs, +} from '@wordpress/compose'; +import { useDispatch } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; +import { closeSmall } from '@wordpress/icons'; +import { ESCAPE } from '@wordpress/keycodes'; + +/** + * Internal dependencies + */ +import { store as editWidgetsStore } from '../../store'; + +export default function ListViewSidebar() { + const { setIsListViewOpened } = useDispatch( editWidgetsStore ); + + const { clearSelectedBlock, selectBlock } = useDispatch( blockEditorStore ); + async function selectEditorBlock( clientId ) { + await clearSelectedBlock(); + selectBlock( clientId, -1 ); + } + + const focusOnMountRef = useFocusOnMount( 'firstElement' ); + const focusReturnRef = useFocusReturn(); + function closeOnEscape( event ) { + if ( event.keyCode === ESCAPE && ! event.defaultPrevented ) { + event.preventDefault(); + setIsListViewOpened( false ); + } + } + + const instanceId = useInstanceId( ListViewSidebar ); + const labelId = `edit-widgets-editor__list-view-panel-label-${ instanceId }`; + + return ( + // eslint-disable-next-line jsx-a11y/no-static-element-interactions +
+
+ { __( 'List view' ) } +
+
+ +
+
+ ); +} diff --git a/packages/edit-widgets/src/components/secondary-sidebar/style.scss b/packages/edit-widgets/src/components/secondary-sidebar/style.scss new file mode 100644 index 0000000000000..5acf945480a52 --- /dev/null +++ b/packages/edit-widgets/src/components/secondary-sidebar/style.scss @@ -0,0 +1,25 @@ +.edit-widgets-editor__list-view-panel { + height: 100%; + display: flex; + flex-direction: column; + // Same width as the Inserter. + // @see packages/block-editor/src/components/inserter/style.scss + min-width: 350px; +} + +.edit-widgets-editor__list-view-panel-content { + // Leave space for the close button + height: calc(100% - #{$button-size} - #{$grid-unit-10}); + overflow-y: auto; + padding: $grid-unit-10; +} + +.edit-widgets-editor__list-view-panel-header { + align-items: center; + border-bottom: $border-width solid $gray-300; + display: flex; + justify-content: space-between; + height: $grid-unit-60; + padding-left: $grid-unit-20; + padding-right: $grid-unit-05; +} diff --git a/packages/edit-widgets/src/store/actions.js b/packages/edit-widgets/src/store/actions.js index 93462625e0a9e..0701274885d71 100644 --- a/packages/edit-widgets/src/store/actions.js +++ b/packages/edit-widgets/src/store/actions.js @@ -361,6 +361,19 @@ export function setIsInserterOpened( value ) { }; } +/** + * Returns an action object used to open/close the list view. + * + * @param {boolean} isOpen A boolean representing whether the list view should be opened or closed. + * @return {Object} Action object. + */ +export function setIsListViewOpened( isOpen ) { + return { + type: 'SET_IS_LIST_VIEW_OPENED', + isOpen, + }; +} + /** * Returns an action object signalling that the user closed the sidebar. * diff --git a/packages/edit-widgets/src/store/reducer.js b/packages/edit-widgets/src/store/reducer.js index b0fe86db81072..ff942b955edcd 100644 --- a/packages/edit-widgets/src/store/reducer.js +++ b/packages/edit-widgets/src/store/reducer.js @@ -31,20 +31,45 @@ export function widgetAreasOpenState( state = {}, action ) { } /** - * Reducer tracking whether the inserter is open. + * Reducer to set the block inserter panel open or closed. * - * @param {boolean|Object} state - * @param {Object} action + * Note: this reducer interacts with the list view panel reducer + * to make sure that only one of the two panels is open at the same time. + * + * @param {Object} state Current state. + * @param {Object} action Dispatched action. */ -function blockInserterPanel( state = false, action ) { +export function blockInserterPanel( state = false, action ) { switch ( action.type ) { + case 'SET_IS_LIST_VIEW_OPENED': + return action.isOpen ? false : state; case 'SET_IS_INSERTER_OPENED': return action.value; } return state; } +/** + * Reducer to set the list view panel open or closed. + * + * Note: this reducer interacts with the inserter panel reducer + * to make sure that only one of the two panels is open at the same time. + * + * @param {Object} state Current state. + * @param {Object} action Dispatched action. + */ +export function listViewPanel( state = false, action ) { + switch ( action.type ) { + case 'SET_IS_INSERTER_OPENED': + return action.value ? false : state; + case 'SET_IS_LIST_VIEW_OPENED': + return action.isOpen; + } + return state; +} + export default combineReducers( { blockInserterPanel, + listViewPanel, widgetAreasOpenState, } ); diff --git a/packages/edit-widgets/src/store/selectors.js b/packages/edit-widgets/src/store/selectors.js index a45d5a223e45a..c672454fff165 100644 --- a/packages/edit-widgets/src/store/selectors.js +++ b/packages/edit-widgets/src/store/selectors.js @@ -277,3 +277,14 @@ export const canInsertBlockInWidgetArea = createRegistrySelector( ); } ); + +/** + * Returns true if the list view is opened. + * + * @param {Object} state Global application state. + * + * @return {boolean} Whether the list view is opened. + */ +export function isListViewOpened( state ) { + return state.listViewPanel; +} diff --git a/packages/edit-widgets/src/style.scss b/packages/edit-widgets/src/style.scss index 7d75dc6443bda..1a537c325b4e3 100644 --- a/packages/edit-widgets/src/style.scss +++ b/packages/edit-widgets/src/style.scss @@ -10,6 +10,7 @@ @import "./components/layout/style.scss"; @import "./components/welcome-guide/style.scss"; @import "./components/widget-areas-block-editor-content/style.scss"; +@import "./components/secondary-sidebar/style.scss"; // In order to use mix-blend-mode, this element needs to have an explicitly set background-color // We scope it to .wp-toolbar to be wp-admin only, to prevent bleed into other implementations From d073b8fce8fff6993b35af5d756370df40f50293 Mon Sep 17 00:00:00 2001 From: Kerry Liu Date: Tue, 19 Oct 2021 12:26:30 -0700 Subject: [PATCH 13/17] Edit Widgets: make sure global inserter closes on toggle --- packages/edit-widgets/src/components/header/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-widgets/src/components/header/index.js b/packages/edit-widgets/src/components/header/index.js index bf0c5fd6caf5a..5eaec7a099d7b 100644 --- a/packages/edit-widgets/src/components/header/index.js +++ b/packages/edit-widgets/src/components/header/index.js @@ -52,7 +52,7 @@ function Header() { const handleClick = () => { if ( isInserterOpen ) { // Focusing the inserter button closes the inserter popover - inserterButton.current.focus(); + setIsInserterOpened( false ); } else { if ( ! isLastSelectedWidgetAreaOpen ) { // Select the last selected block if hasn't already. From 85bca376a4184625fcb9f37e064fcc9a3dee46d2 Mon Sep 17 00:00:00 2001 From: Kerry Liu Date: Tue, 19 Oct 2021 15:21:40 -0700 Subject: [PATCH 14/17] Edit Widgets: fix E2Es and add simple list view test --- packages/e2e-test-utils/src/inserter.js | 14 ++++- packages/e2e-test-utils/src/list-view.js | 4 +- .../specs/widgets/editing-widgets.test.js | 51 +++++++++++-------- 3 files changed, 44 insertions(+), 25 deletions(-) diff --git a/packages/e2e-test-utils/src/inserter.js b/packages/e2e-test-utils/src/inserter.js index 1bcce329f07df..4e6b769e8ddac 100644 --- a/packages/e2e-test-utils/src/inserter.js +++ b/packages/e2e-test-utils/src/inserter.js @@ -43,7 +43,12 @@ async function isGlobalInserterOpen() { // "Add block" selector is required to make sure performance comparison // doesn't fail on older branches where we still had "Add block" as label. return !! document.querySelector( - '.edit-post-header [aria-label="Add block"].is-pressed, .edit-site-header [aria-label="Add block"].is-pressed, .edit-post-header [aria-label="Toggle block inserter"].is-pressed, .edit-site-header [aria-label="Toggle block inserter"].is-pressed' + '.edit-post-header [aria-label="Add block"].is-pressed,' + + '.edit-site-header [aria-label="Add block"].is-pressed,' + + '.edit-post-header [aria-label="Toggle block inserter"].is-pressed,' + + '.edit-site-header [aria-label="Toggle block inserter"].is-pressed,' + + '.edit-widgets-header [aria-label="Toggle block inserter"].is-pressed,' + + '.edit-widgets-header [aria-label="Add block"].is-pressed' ); } ); } @@ -54,7 +59,12 @@ export async function toggleGlobalBlockInserter() { // "Add block" selector is required to make sure performance comparison // doesn't fail on older branches where we still had "Add block" as label. await page.click( - '.edit-post-header [aria-label="Add block"], .edit-site-header [aria-label="Add block"], .edit-post-header [aria-label="Toggle block inserter"], .edit-site-header [aria-label="Toggle block inserter"]' + '.edit-post-header [aria-label="Add block"],' + + '.edit-site-header [aria-label="Add block"],' + + '.edit-post-header [aria-label="Toggle block inserter"],' + + '.edit-site-header [aria-label="Toggle block inserter"],' + + '.edit-widgets-header [aria-label="Add block"],' + + '.edit-widgets-header [aria-label="Toggle block inserter"]' ); } diff --git a/packages/e2e-test-utils/src/list-view.js b/packages/e2e-test-utils/src/list-view.js index 03121c5f84af7..4098145dfb440 100644 --- a/packages/e2e-test-utils/src/list-view.js +++ b/packages/e2e-test-utils/src/list-view.js @@ -1,13 +1,13 @@ async function toggleListView() { await page.click( - '.edit-post-header-toolbar__list-view-toggle, .edit-site-header-toolbar__list-view-toggle' + '.edit-post-header-toolbar__list-view-toggle, .edit-site-header-toolbar__list-view-toggle, .edit-widgets-header-toolbar__list-view-toggle' ); } async function isListViewOpen() { return await page.evaluate( () => { return !! document.querySelector( - '.edit-post-header-toolbar__list-view-toggle.is-pressed, .edit-site-header-toolbar__list-view-toggle.is-pressed' + '.edit-post-header-toolbar__list-view-toggle.is-pressed, .edit-site-header-toolbar__list-view-toggle.is-pressed, .edit-widgets-header-toolbar__list-view-toggle.is-pressed' ); } ); } diff --git a/packages/e2e-tests/specs/widgets/editing-widgets.test.js b/packages/e2e-tests/specs/widgets/editing-widgets.test.js index 19beaa55174ba..f5aceb0e717fe 100644 --- a/packages/e2e-tests/specs/widgets/editing-widgets.test.js +++ b/packages/e2e-tests/specs/widgets/editing-widgets.test.js @@ -11,6 +11,11 @@ import { deleteAllWidgets, pressKeyWithModifier, __experimentalRest as rest, + openListView, + closeListView, + openGlobalBlockInserter, + searchForBlock, + closeGlobalBlockInserter, } from '@wordpress/e2e-test-utils'; /** @@ -64,12 +69,7 @@ describe( 'Widgets screen', () => { } ); async function getBlockInGlobalInserter( blockName ) { - const addBlockButton = await find( { - role: 'button', - name: 'Toggle block inserter', - pressed: false, - } ); - await addBlockButton.click(); + await openGlobalBlockInserter(); const blockLibrary = await find( { role: 'region', @@ -94,17 +94,11 @@ describe( 'Widgets screen', () => { } ); await searchBox.type( blockName ); - const addBlock = await find( - { - role: 'option', - name: blockName, - }, - { - root: blockLibrary, - } - ); + await searchForBlock( blockName ); - return addBlock; + return await page.waitForXPath( + `//button//span[contains(text(), '${ blockName }')]` + ); } async function expectInsertionPointIndicatorToBeBelowLastBlock( @@ -118,10 +112,9 @@ describe( 'Widgets screen', () => { const lastBlock = childBlocks[ childBlocks.length - 2 ]; const lastBlockBoundingBox = await lastBlock.boundingBox(); - // TODO: Probably need a more accessible way to select this, maybe a test ID or data attribute. - const insertionPointIndicator = await find( { - selector: '.block-editor-block-list__insertion-point-indicator', - } ); + const insertionPointIndicator = await page.$( + '.block-editor-block-list__insertion-point-indicator' + ); const insertionPointIndicatorBoundingBox = await insertionPointIndicator.boundingBox(); expect( @@ -176,7 +169,8 @@ describe( 'Widgets screen', () => { await page.keyboard.type( 'First Paragraph' ); addParagraphBlock = await getBlockInGlobalInserter( 'Paragraph' ); - await addParagraphBlock.hover(); + await page.keyboard.press( 'Tab' ); + await page.keyboard.press( 'Tab' ); await expectInsertionPointIndicatorToBeBelowLastBlock( firstWidgetArea @@ -847,6 +841,19 @@ describe( 'Widgets screen', () => { expect( console ).toHaveErrored( twentyTwentyError ); } ); + + it( 'can toggle sidebar list view', async () => { + const widgetAreas = await findAll( { + role: 'document', + name: 'Block: Widget Area', + } ); + await openListView(); + const listItems = await page.$$( + '.edit-widgets-editor__list-view-panel .block-editor-list-view-leaf' + ); + expect( listItems.length >= widgetAreas.length ).toEqual( true ); + await closeListView(); + } ); } ); /** @@ -875,6 +882,8 @@ async function visitWidgetsScreen() { } async function saveWidgets() { + await closeListView(); + await closeGlobalBlockInserter(); const updateButton = await find( { role: 'button', name: 'Update', From 4e3a90606e9ad14d25b387aea6e7a41545e99e30 Mon Sep 17 00:00:00 2001 From: Kerry Liu Date: Wed, 20 Oct 2021 14:37:21 -0700 Subject: [PATCH 15/17] Edit Widgets: do not show actions in list view for widget areas --- .../src/components/list-view/block.js | 21 +++++++++++++++++-- .../src/components/list-view/index.js | 4 ++++ .../src/components/list-view/style.scss | 5 +++++ .../secondary-sidebar/list-view-sidebar.js | 1 + 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/list-view/block.js b/packages/block-editor/src/components/list-view/block.js index d662f7008bc4d..97be704702f6e 100644 --- a/packages/block-editor/src/components/list-view/block.js +++ b/packages/block-editor/src/components/list-view/block.js @@ -49,6 +49,7 @@ export default function ListViewBlock( { const { __experimentalFeatures: withExperimentalFeatures, __experimentalPersistentListViewFeatures: withExperimentalPersistentListViewFeatures, + __experimentalHideContainerBlockActions: hideContainerBlockActions, isTreeGridMounted, expand, collapse, @@ -140,11 +141,27 @@ export default function ListViewBlock( { [ clientId, expand, collapse, isExpanded ] ); + const showBlockActions = + withExperimentalFeatures && + //hide actions for blocks like core/widget-areas + ( ! hideContainerBlockActions || + ( hideContainerBlockActions && level > 1 ) ); + + const hideBlockActions = withExperimentalFeatures && ! showBlockActions; + + let colSpan; + if ( hasRenderedMovers ) { + colSpan = 2; + } else if ( hideBlockActions ) { + colSpan = 3; + } + const classes = classnames( { 'is-selected': isSelected, 'is-branch-selected': withExperimentalPersistentListViewFeatures && isBranchSelected, 'is-dragging': isDragged, + 'has-single-cell': hideBlockActions, } ); return ( @@ -165,7 +182,7 @@ export default function ListViewBlock( { > { ( { ref, tabIndex, onFocus } ) => ( @@ -217,7 +234,7 @@ export default function ListViewBlock( { ) } - { withExperimentalFeatures && ( + { showBlockActions && ( { ( { ref, tabIndex, onFocus } ) => ( { * @param {boolean} props.showBlockMovers Flag to enable block movers * @param {boolean} props.__experimentalFeatures Flag to enable experimental features. * @param {boolean} props.__experimentalPersistentListViewFeatures Flag to enable features for the Persistent List View experiment. + * @param {boolean} props.__experimentalHideContainerBlockActions Flag to hide actions of top level blocks (like core/widget-area) * @param {Object} ref Forwarded ref */ function ListView( @@ -57,6 +58,7 @@ function ListView( onSelect = noop, __experimentalFeatures, __experimentalPersistentListViewFeatures, + __experimentalHideContainerBlockActions, showNestedBlocks, showBlockMovers, ...props @@ -118,6 +120,7 @@ function ListView( () => ( { __experimentalFeatures, __experimentalPersistentListViewFeatures, + __experimentalHideContainerBlockActions, isTreeGridMounted: isMounted.current, draggedClientIds, expandedState, @@ -127,6 +130,7 @@ function ListView( [ __experimentalFeatures, __experimentalPersistentListViewFeatures, + __experimentalHideContainerBlockActions, isMounted.current, draggedClientIds, expandedState, diff --git a/packages/block-editor/src/components/list-view/style.scss b/packages/block-editor/src/components/list-view/style.scss index d2e488244ab6d..99ee92b3488f8 100644 --- a/packages/block-editor/src/components/list-view/style.scss +++ b/packages/block-editor/src/components/list-view/style.scss @@ -112,6 +112,11 @@ } } } + //fix focus styling width when one row has fewer cells + &.has-single-cell .block-editor-list-view-block-contents:focus::after { + right: 0; + } + .block-editor-list-view-block__menu:focus { box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color); z-index: 1; diff --git a/packages/edit-widgets/src/components/secondary-sidebar/list-view-sidebar.js b/packages/edit-widgets/src/components/secondary-sidebar/list-view-sidebar.js index 0fe7a15c67941..ef072989fb38d 100644 --- a/packages/edit-widgets/src/components/secondary-sidebar/list-view-sidebar.js +++ b/packages/edit-widgets/src/components/secondary-sidebar/list-view-sidebar.js @@ -65,6 +65,7 @@ export default function ListViewSidebar() { From efe9c33134c3b9d420ef31f086722f99c81f1232 Mon Sep 17 00:00:00 2001 From: Kerry Liu Date: Fri, 22 Oct 2021 09:18:18 -0700 Subject: [PATCH 16/17] add related changelogs to block-editor and edit-widgets --- packages/block-editor/CHANGELOG.md | 8 ++++++++ packages/block-editor/src/components/list-view/style.scss | 2 +- packages/edit-widgets/CHANGELOG.md | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/CHANGELOG.md b/packages/block-editor/CHANGELOG.md index 2773dbcc5dcbd..4a4d3007dc237 100644 --- a/packages/block-editor/CHANGELOG.md +++ b/packages/block-editor/CHANGELOG.md @@ -2,6 +2,14 @@ ## Unreleased +### Performance + +- Fix block focus time when List View is open. [#35706](https://github.com/WordPress/gutenberg/pull/35706) + +### Breaking change + +- ListView no longer supports the `showOnlyCurrentHierarchy` flag [#35706](https://github.com/WordPress/gutenberg/pull/35706). To display a subset of blocks, use the `blocks` parameter instead. + ## 7.0.0 (2021-07-29) ### Breaking Change diff --git a/packages/block-editor/src/components/list-view/style.scss b/packages/block-editor/src/components/list-view/style.scss index 99ee92b3488f8..a4d151092a568 100644 --- a/packages/block-editor/src/components/list-view/style.scss +++ b/packages/block-editor/src/components/list-view/style.scss @@ -112,7 +112,7 @@ } } } - //fix focus styling width when one row has fewer cells + // Fix focus styling width when one row has fewer cells. &.has-single-cell .block-editor-list-view-block-contents:focus::after { right: 0; } diff --git a/packages/edit-widgets/CHANGELOG.md b/packages/edit-widgets/CHANGELOG.md index ff8b4ad7b07ad..9ede641e2f1f5 100644 --- a/packages/edit-widgets/CHANGELOG.md +++ b/packages/edit-widgets/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Enhancement + +- Enable persistent List View in the widget editor [#35706](https://github.com/WordPress/gutenberg/pull/35706). + ## 3.0.0 (2021-07-29) ### Breaking Change From 28f60b53e8f0c399234dac6816db419bf560c352 Mon Sep 17 00:00:00 2001 From: Kerry Liu Date: Fri, 22 Oct 2021 09:32:59 -0700 Subject: [PATCH 17/17] add detail to the performance change --- packages/block-editor/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/CHANGELOG.md b/packages/block-editor/CHANGELOG.md index 4a4d3007dc237..8b280692ac135 100644 --- a/packages/block-editor/CHANGELOG.md +++ b/packages/block-editor/CHANGELOG.md @@ -4,11 +4,11 @@ ### Performance -- Fix block focus time when List View is open. [#35706](https://github.com/WordPress/gutenberg/pull/35706) +- Avoid re-rendering all List View items on block focus [#35706](https://github.com/WordPress/gutenberg/pull/35706). These changes speed up block focus time in large posts by 80% when List View is open. ### Breaking change -- ListView no longer supports the `showOnlyCurrentHierarchy` flag [#35706](https://github.com/WordPress/gutenberg/pull/35706). To display a subset of blocks, use the `blocks` parameter instead. +- List View no longer supports the `showOnlyCurrentHierarchy` flag [#35706](https://github.com/WordPress/gutenberg/pull/35706). To display a subset of blocks, use the `blocks` parameter instead. ## 7.0.0 (2021-07-29)