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

Move search into inserter tabs #61108

Merged
merged 24 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
96cfa63
Move search into inserter tabs
jeryj Apr 25, 2024
f485c1b
Make inserterSearch component
jeryj Apr 25, 2024
94afb1c
focus the search field using a useEffect
scruffian Apr 26, 2024
93f8f86
use request animation frame
scruffian Apr 26, 2024
d203d3e
add comment
scruffian Apr 26, 2024
8fda50f
remove unused code
scruffian Apr 26, 2024
dcd15b7
change selector for search
scruffian Apr 29, 2024
dab64f4
use useRefEffect instead of the requestAnimationFrame
scruffian Apr 29, 2024
d6caacb
Only inserter on mount
jeryj Apr 30, 2024
cf0e71c
keep the imperative ref and focus once the tabs are done
draganescu May 1, 2024
6e9b42f
revert changes to the inserter tabs and leave the tabs contents memoized
draganescu May 1, 2024
4b126ef
reset order
scruffian May 1, 2024
1de6dfd
remove unneeded change
scruffian May 1, 2024
429a0d7
reset order
scruffian May 1, 2024
eec8797
show message if no blocks and no patterns available, do not auto focu…
draganescu May 1, 2024
affc8af
fix test
scruffian May 1, 2024
489d6a1
fix firefox bug
scruffian May 1, 2024
5d7340c
auto focus the inserter when open so that we can tab into it
draganescu May 1, 2024
ca00872
Remove unused searchRef
jeryj May 1, 2024
0b1e2fb
Pin hint to bottom of block tab panel so it doesn't flash
jeryj May 1, 2024
3044f5f
Remove unnecessary tab filtering
jeryj May 1, 2024
521b732
restore no results message
scruffian May 1, 2024
fbd8901
Focus first active tab
jeryj May 1, 2024
020277c
hide the inserter tabs on the widget editor
scruffian May 1, 2024
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
Copy link
Contributor

Choose a reason for hiding this comment

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

These changes add the no results message when the panel is empty. Disappearing UI is not good when assistive tech is used as it causes a different tab stop order. Having the tabs always show - even if empty - is more predictable but it needs a no results state.

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import MobileTabNavigation from '../mobile-tab-navigation';
import { PatternCategoryPreviews } from './pattern-category-previews';
import { usePatternCategories } from './use-pattern-categories';
import CategoryTabs from '../category-tabs';
import InserterNoResults from '../no-results';

function BlockPatternsTab( {
onSelectCategory,
Expand All @@ -28,6 +29,10 @@ function BlockPatternsTab( {

const isMobile = useViewportMatch( 'medium', '<' );

if ( ! categories.length ) {
return <InserterNoResults />;
}

return (
<>
{ ! isMobile && (
Expand Down
Copy link
Contributor

Choose a reason for hiding this comment

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

These changes add the no results message when the panel is empty. Disappearing UI is not good when assistive tech is used as it causes a different tab stop order. Having the tabs always show - even if empty - is more predictable but it needs a no results state.

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import InserterPanel from './panel';
import useBlockTypesState from './hooks/use-block-types-state';
import InserterListbox from '../inserter-listbox';
import { orderBy } from '../../utils/sorting';
import InserterNoResults from './no-results';

const getBlockNamespace = ( item ) => item.name.split( '/' )[ 0 ];

Expand Down Expand Up @@ -102,6 +103,10 @@ export function BlockTypesTab( {
didRenderAllCategories ? collectionEntries : EMPTY_ARRAY
);

if ( ! items.length ) {
return <InserterNoResults />;
}

return (
<InserterListbox>
<div>
Expand Down
Copy link
Contributor

Choose a reason for hiding this comment

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

These changes add the no results message when the panel is empty. Disappearing UI is not good when assistive tech is used as it causes a different tab stop order. Having the tabs always show - even if empty - is more predictable but it needs a no results state.

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { useMediaCategories } from './hooks';
import { getBlockAndPreviewFromMedia } from './utils';
import MobileTabNavigation from '../mobile-tab-navigation';
import CategoryTabs from '../category-tabs';
import InserterNoResults from '../no-results';

const ALLOWED_MEDIA_TYPES = [ 'image', 'video', 'audio' ];

Expand Down Expand Up @@ -48,6 +49,10 @@ function MediaTab( {
[ mediaCategories ]
);

if ( ! categories.length ) {
return <InserterNoResults />;
}

return (
<>
{ ! isMobile && (
Expand Down
219 changes: 110 additions & 109 deletions packages/block-editor/src/components/inserter/menu.js
Copy link
Contributor

Choose a reason for hiding this comment

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

This change set does multiple things:

  • keeps the tabs always visible by removing showAsTabs and the code that creates it (e.g. removes showPatterns, mediaCategories, showMedia, showMediaPanel)
  • moves the search control into a reusable variable
  • moves the search block into the blocks and patterns tabs
  • removes the auto focus of the search control (removing the useImperativeHandle on the ref passed to InserterMenu by the parent libarary component) - see reasoning in PR description
  • sets the default tab to blocks

Copy link
Contributor

Choose a reason for hiding this comment

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

removes the auto focus of the search control (removing the useImperativeHandle on the ref passed to InserterMenu by the parent libarary component) - see reasoning in PR description

But it introduces breaking changes in the API, like @mattsherman mentioned in this issue.
After these changes, the ref doesn't expose the focusSearch method, which caused the product editor to break.

Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,24 @@ import {
useState,
useCallback,
useMemo,
useImperativeHandle,
useRef,
} from '@wordpress/element';
import { VisuallyHidden, SearchControl, Popover } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import { useDebouncedInput } from '@wordpress/compose';

/**
* Internal dependencies
*/
import { unlock } from '../../lock-unlock';
import Tips from './tips';
import InserterPreviewPanel from './preview-panel';
import BlockTypesTab from './block-types-tab';
import BlockPatternsTab from './block-patterns-tab';
import { PatternCategoryPreviewPanel } from './block-patterns-tab/pattern-category-preview-panel';
import { MediaTab, MediaCategoryPanel, useMediaCategories } from './media-tab';
import { MediaTab, MediaCategoryPanel } from './media-tab';
import InserterSearchResults from './search-results';
import useInsertionPoint from './hooks/use-insertion-point';
import InserterTabs from './tabs';
import { store as blockEditorStore } from '../../store';
import { useZoomOut } from '../../hooks/use-zoom-out';

const NOOP = () => {};
Expand All @@ -59,7 +55,7 @@ function InserterMenu(
const [ patternFilter, setPatternFilter ] = useState( 'all' );
const [ selectedMediaCategory, setSelectedMediaCategory ] =
useState( null );
const [ selectedTab, setSelectedTab ] = useState( null );
const [ selectedTab, setSelectedTab ] = useState( 'blocks' );

const [ destinationRootClientId, onInsertBlocks, onToggleInsertionPoint ] =
useInsertionPoint( {
Expand All @@ -69,18 +65,6 @@ function InserterMenu(
insertionIndex: __experimentalInsertionIndex,
shouldFocusBlock,
} );
const { showPatterns } = useSelect(
( select ) => {
const { hasAllowedPatterns } = unlock( select( blockEditorStore ) );
return {
showPatterns: hasAllowedPatterns( destinationRootClientId ),
};
},
[ destinationRootClientId ]
);

const mediaCategories = useMediaCategories( destinationRootClientId );
const showMedia = mediaCategories.length > 0;

const onInsert = useCallback(
( blocks, meta, shouldForceFocusBlock ) => {
Expand Down Expand Up @@ -135,29 +119,90 @@ function InserterMenu(
! delayedFilterValue &&
selectedPatternCategory;

const showMediaPanel =
selectedTab === 'media' &&
! delayedFilterValue &&
selectedMediaCategory;
const showMediaPanel = selectedTab === 'media' && selectedMediaCategory;

const blocksTab = useMemo(
() => (
const searchRef = useRef();

const inserterSearch = useMemo( () => {
if ( selectedTab === 'media' ) {
return null;
}
return (
<>
<div className="block-editor-inserter__block-list">
<BlockTypesTab
rootClientId={ destinationRootClientId }
onInsert={ onInsert }
<SearchControl
__nextHasNoMarginBottom
className="block-editor-inserter__search"
onChange={ ( value ) => {
if ( hoveredItem ) {
setHoveredItem( null );
}
setFilterValue( value );
} }
value={ filterValue }
label={ __( 'Search for blocks and patterns' ) }
placeholder={ __( 'Search' ) }
ref={ searchRef }
/>
{ !! delayedFilterValue && (
<InserterSearchResults
filterValue={ delayedFilterValue }
onSelect={ onSelect }
onHover={ onHover }
showMostUsedBlocks={ showMostUsedBlocks }
onHoverPattern={ onHoverPattern }
rootClientId={ rootClientId }
clientId={ clientId }
isAppender={ isAppender }
__experimentalInsertionIndex={
__experimentalInsertionIndex
}
showBlockDirectory
shouldFocusBlock={ shouldFocusBlock }
prioritizePatterns={ selectedTab === 'patterns' }
/>
</div>
{ showInserterHelpPanel && (
<div className="block-editor-inserter__tips">
<VisuallyHidden as="h2">
{ __( 'A tip for using the block editor' ) }
</VisuallyHidden>
<Tips />
</div>
) }
</>
);
}, [
selectedTab,
hoveredItem,
setHoveredItem,
setFilterValue,
filterValue,
delayedFilterValue,
onSelect,
onHover,
onHoverPattern,
shouldFocusBlock,
clientId,
rootClientId,
__experimentalInsertionIndex,
isAppender,
searchRef,
] );

const blocksTab = useMemo(
() => (
<>
{ inserterSearch }
{ ! delayedFilterValue && (
<>
<div className="block-editor-inserter__block-list">
<BlockTypesTab
rootClientId={ destinationRootClientId }
onInsert={ onInsert }
onHover={ onHover }
showMostUsedBlocks={ showMostUsedBlocks }
/>
</div>
{ showInserterHelpPanel && (
<div className="block-editor-inserter__tips">
<VisuallyHidden as="h2">
{ __( 'A tip for using the block editor' ) }
</VisuallyHidden>
<Tips />
</div>
) }
</>
) }
</>
),
Expand All @@ -167,28 +212,35 @@ function InserterMenu(
onHover,
showMostUsedBlocks,
showInserterHelpPanel,
inserterSearch,
delayedFilterValue,
]
);

const patternsTab = useMemo(
() => (
<BlockPatternsTab
rootClientId={ destinationRootClientId }
onInsert={ onInsertPattern }
onSelectCategory={ onClickPatternCategory }
selectedCategory={ selectedPatternCategory }
>
{ showPatternPanel && (
<PatternCategoryPreviewPanel
<>
{ inserterSearch }
{ ! delayedFilterValue && (
<BlockPatternsTab
rootClientId={ destinationRootClientId }
onInsert={ onInsertPattern }
onHover={ onHoverPattern }
category={ selectedPatternCategory }
patternFilter={ patternFilter }
showTitlesAsTooltip
/>
onSelectCategory={ onClickPatternCategory }
selectedCategory={ selectedPatternCategory }
>
{ showPatternPanel && (
<PatternCategoryPreviewPanel
rootClientId={ destinationRootClientId }
onInsert={ onInsertPattern }
onHover={ onHoverPattern }
category={ selectedPatternCategory }
patternFilter={ patternFilter }
showTitlesAsTooltip
/>
) }
</BlockPatternsTab>
) }
</BlockPatternsTab>
</>
),
[
destinationRootClientId,
Expand All @@ -198,6 +250,8 @@ function InserterMenu(
patternFilter,
selectedPatternCategory,
showPatternPanel,
inserterSearch,
delayedFilterValue,
]
);

Expand Down Expand Up @@ -236,15 +290,6 @@ function InserterMenu(
[ blocksTab, mediaTab, patternsTab ]
);

const searchRef = useRef();
useImperativeHandle( ref, () => ( {
focusSearch: () => {
searchRef.current.focus();
},
} ) );

const showAsTabs = ! delayedFilterValue && ( showPatterns || showMedia );

// When the pattern panel is showing, we want to use zoom out mode
useZoomOut( showPatternPanel );

Expand All @@ -261,57 +306,13 @@ function InserterMenu(
className={ classnames( 'block-editor-inserter__menu', {
'show-panel': showPatternPanel || showMediaPanel,
} ) }
ref={ ref }
>
<div
className={ classnames( 'block-editor-inserter__main-area', {
'show-as-tabs': showAsTabs,
} ) }
>
<SearchControl
__nextHasNoMarginBottom
className="block-editor-inserter__search"
onChange={ ( value ) => {
if ( hoveredItem ) {
setHoveredItem( null );
}
setFilterValue( value );
} }
value={ filterValue }
label={ __( 'Search for blocks and patterns' ) }
placeholder={ __( 'Search' ) }
ref={ searchRef }
<div className="block-editor-inserter__main-area">
<InserterTabs
onSelect={ handleSetSelectedTab }
tabsContents={ inserterTabsContents }
/>
{ !! delayedFilterValue && (
<div className="block-editor-inserter__no-tab-container">
<InserterSearchResults
filterValue={ delayedFilterValue }
onSelect={ onSelect }
onHover={ onHover }
onHoverPattern={ onHoverPattern }
rootClientId={ rootClientId }
clientId={ clientId }
isAppender={ isAppender }
__experimentalInsertionIndex={
__experimentalInsertionIndex
}
showBlockDirectory
shouldFocusBlock={ shouldFocusBlock }
/>
</div>
) }
{ showAsTabs && (
<InserterTabs
showPatterns={ showPatterns }
showMedia={ showMedia }
onSelect={ handleSetSelectedTab }
tabsContents={ inserterTabsContents }
/>
) }
{ ! delayedFilterValue && ! showAsTabs && (
<div className="block-editor-inserter__no-tab-container">
{ blocksTab }
</div>
) }
</div>
{ showInserterHelpPanel && hoveredItem && (
<Popover
Expand Down
13 changes: 2 additions & 11 deletions packages/block-editor/src/components/inserter/tabs.js
Copy link
Contributor

Choose a reason for hiding this comment

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

This change removes optionally hiding tabs if they're empty. This makes them always show.

Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,8 @@ const mediaTab = {
title: __( 'Media' ),
};

function InserterTabs( {
showPatterns = false,
showMedia = false,
onSelect,
tabsContents,
} ) {
const tabs = [
blocksTab,
showPatterns && patternsTab,
showMedia && mediaTab,
].filter( Boolean );
function InserterTabs( { onSelect, tabsContents } ) {
const tabs = [ blocksTab, patternsTab, mediaTab ].filter( Boolean );

return (
<div className="block-editor-inserter__tabs">
Expand Down
Loading
Loading