Skip to content

Commit

Permalink
Zoom Out: Only show the inserters when a block is selected or hovered (
Browse files Browse the repository at this point in the history
…#63668)

* Zoom Out: Only show the inserters when a block is selected or hovered

* Correct logic for rendering the zoom out inserters

We want to show the inserters on hover, even if there is no selection.

* Update shouldRenderInsertionPoint condition

* Make the inserters always present and just toggle visibility

* Update docs/reference-guides/data/data-core-block-editor.md

* Update packages/block-editor/src/components/block-tools/zoom-out-mode-inserter-button.js

* Update packages/block-editor/src/components/block-tools/zoom-out-mode-inserter-button.js

* Update packages/block-editor/src/components/block-tools/zoom-out-mode-inserter-button.js

* Update packages/block-editor/src/components/block-tools/zoom-out-mode-inserter-button.js

* Update packages/block-editor/src/store/reducer.js

* Update packages/block-editor/src/store/reducer.js

* Update packages/block-editor/src/store/selectors.js

* fix the property name

* Reduce number of select calls by lifting useSelect calls to ZoomOutModeInserters

---------

Co-authored-by: Jerry Jones <jones.jeremydavid@gmail.com>
Co-authored-by: scruffian <scruffian@git.wordpress.org>
Co-authored-by: jeryj <jeryj@git.wordpress.org>
  • Loading branch information
4 people authored Jul 19, 2024
1 parent 6b0b4e4 commit 6a466a0
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 33 deletions.
24 changes: 24 additions & 0 deletions docs/reference-guides/data/data-core-block-editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,18 @@ _Returns_

- `number`: Number of blocks in the post, or number of blocks with name equal to blockName.

### getHoveredBlockClientId

Returns the currently hovered block.

_Parameters_

- _state_ `Object`: Global application state.

_Returns_

- `Object`: Client Id of the hovered block.

### getInserterItems

Determines the items that appear in the inserter. Includes both static items (e.g. a regular block type) and dynamic items (e.g. a reusable block).
Expand Down Expand Up @@ -1257,6 +1269,18 @@ _Parameters_

Action that hides the insertion point.

### hoverBlock

Returns an action object used in signalling that the block with the specified client ID has been hovered.

_Parameters_

- _clientId_ `string`: Block client ID.

_Returns_

- `Object`: Action object.

### insertAfterBlock

Action that inserts a default block after a given block.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
useFocusHandler( clientId ),
useEventHandlers( { clientId, isSelected } ),
useNavModeExit( clientId ),
useIsHovered(),
useIsHovered( { clientId } ),
useIntersectionObserver(),
useMovingAnimation( { triggerAnimationOnChange: index, clientId } ),
useDisabled( { isDisabled: ! hasOverlay } ),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,37 @@
* WordPress dependencies
*/
import { useRefEffect } from '@wordpress/compose';
import { useDispatch } from '@wordpress/data';

function listener( event ) {
if ( event.defaultPrevented ) {
return;
}

const action = event.type === 'mouseover' ? 'add' : 'remove';

event.preventDefault();
event.currentTarget.classList[ action ]( 'is-hovered' );
}
/**
* Internal dependencies
*/
import { store as blockEditorStore } from '../../../store';

/*
* Adds `is-hovered` class when the block is hovered and in navigation or
* outline mode.
*/
export function useIsHovered() {
export function useIsHovered( { clientId } ) {
const { hoverBlock } = useDispatch( blockEditorStore );

function listener( event ) {
if ( event.defaultPrevented ) {
return;
}

const action = event.type === 'mouseover' ? 'add' : 'remove';

event.preventDefault();
event.currentTarget.classList[ action ]( 'is-hovered' );

if ( action === 'add' ) {
hoverBlock( clientId );
} else {
hoverBlock( null );
}
}

return useRefEffect( ( node ) => {
node.addEventListener( 'mouseout', listener );
node.addEventListener( 'mouseover', listener );
Expand All @@ -29,6 +43,7 @@ export function useIsHovered() {

// Remove class in case it lingers.
node.classList.remove( 'is-hovered' );
hoverBlock( null );
};
}, [] );
}
8 changes: 8 additions & 0 deletions packages/block-editor/src/components/block-tools/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,11 @@
border: none;
}
}

.block-editor-block-tools__zoom-out-mode-inserter-button {
visibility: hidden;

&.is-visible {
visibility: visible;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* External dependencies
*/
import clsx from 'clsx';

/**
* WordPress dependencies
*/
import { useState } from '@wordpress/element';
import { Button } from '@wordpress/components';
import { plus } from '@wordpress/icons';
import { _x } from '@wordpress/i18n';

function ZoomOutModeInserterButton( { isVisible, onClick } ) {
const [
zoomOutModeInserterButtonHovered,
setZoomOutModeInserterButtonHovered,
] = useState( false );

return (
<Button
variant="primary"
icon={ plus }
size="compact"
className={ clsx(
'block-editor-button-pattern-inserter__button',
'block-editor-block-tools__zoom-out-mode-inserter-button',
{
'is-visible': isVisible || zoomOutModeInserterButtonHovered,
}
) }
onClick={ onClick }
onMouseOver={ () => {
setZoomOutModeInserterButtonHovered( true );
} }
onMouseOut={ () => {
setZoomOutModeInserterButtonHovered( false );
} }
label={ _x(
'Add pattern',
'Generic label for pattern inserter button'
) }
/>
);
}

export default ZoomOutModeInserterButton;
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,33 @@
*/
import { useSelect } from '@wordpress/data';
import { useEffect, useRef, useState } from '@wordpress/element';
import { Button } from '@wordpress/components';
import { plus } from '@wordpress/icons';
import { _x } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import BlockPopoverInbetween from '../block-popover/inbetween';
import ZoomOutModeInserterButton from './zoom-out-mode-inserter-button';
import { store as blockEditorStore } from '../../store';
import { unlock } from '../../lock-unlock';

function ZoomOutModeInserters() {
const [ isReady, setIsReady ] = useState( false );
const {
hasSelection,
blockOrder,
sectionRootClientId,
insertionPoint,
setInserterIsOpened,
hasSelection,
sectionRootClientId,
selectedBlockClientId,
hoveredBlockClientId,
} = useSelect( ( select ) => {
const { getSettings, getBlockOrder, getSelectionStart } =
select( blockEditorStore );
const {
getSettings,
getBlockOrder,
getSelectionStart,
getSelectedBlockClientId,
getHoveredBlockClientId,
} = select( blockEditorStore );
const { sectionRootClientId: root } = unlock( getSettings() );
// To do: move ZoomOutModeInserters to core/editor.
// Or we perhaps we should move the insertion point state to the
Expand All @@ -40,6 +45,8 @@ function ZoomOutModeInserters() {
sectionRootClientId: root,
setInserterIsOpened:
getSettings().__experimentalSetIsInserterOpened,
selectedBlockClientId: getSelectedBlockClientId(),
hoveredBlockClientId: getHoveredBlockClientId(),
};
}, [] );

Expand All @@ -64,18 +71,39 @@ function ZoomOutModeInserters() {
};
}, [] );

if ( ! isReady || ! hasSelection ) {
if ( ! isReady ) {
return null;
}

return [ undefined, ...blockOrder ].map( ( clientId, index ) => {
const shouldRenderInserter = insertionPoint.insertionIndex !== index;

const shouldRenderInsertionPoint =
insertionPoint.insertionIndex === index;

if ( ! shouldRenderInserter && ! shouldRenderInsertionPoint ) {
return null;
}

const previousClientId = clientId;
const nextClientId = blockOrder[ index ];

const isSelected =
hasSelection &&
( selectedBlockClientId === previousClientId ||
selectedBlockClientId === nextClientId );

const isHovered =
hoveredBlockClientId === previousClientId ||
hoveredBlockClientId === nextClientId;

return (
<BlockPopoverInbetween
key={ index }
previousClientId={ clientId }
nextClientId={ blockOrder[ index ] }
previousClientId={ previousClientId }
nextClientId={ nextClientId }
>
{ insertionPoint.insertionIndex === index && (
{ shouldRenderInsertionPoint && (
<div
style={ {
borderRadius: '0',
Expand All @@ -87,12 +115,9 @@ function ZoomOutModeInserters() {
className="block-editor-block-list__insertion-point-indicator"
/>
) }
{ insertionPoint.insertionIndex !== index && (
<Button
variant="primary"
icon={ plus }
size="compact"
className="block-editor-button-pattern-inserter__button"
{ shouldRenderInserter && (
<ZoomOutModeInserterButton
isVisible={ isSelected || isHovered }
onClick={ () => {
setInserterIsOpened( {
rootClientId: sectionRootClientId,
Expand All @@ -101,10 +126,6 @@ function ZoomOutModeInserters() {
category: 'all',
} );
} }
label={ _x(
'Add pattern',
'Generic label for pattern inserter button'
) }
/>
) }
</BlockPopoverInbetween>
Expand Down
15 changes: 15 additions & 0 deletions packages/block-editor/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,21 @@ export function selectBlock( clientId, initialPosition = 0 ) {
};
}

/**
* Returns an action object used in signalling that the block with the
* specified client ID has been hovered.
*
* @param {string} clientId Block client ID.
*
* @return {Object} Action object.
*/
export function hoverBlock( clientId ) {
return {
type: 'HOVER_BLOCK',
clientId,
};
}

/**
* Yields action objects used in signalling that the block preceding the given
* clientId (or optionally, its first parent from bottom to top)
Expand Down
18 changes: 18 additions & 0 deletions packages/block-editor/src/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2068,6 +2068,23 @@ export function lastFocus( state = false, action ) {
return state;
}

/**
* Reducer setting currently hovered block.
*
* @param {boolean} state Current state.
* @param {Object} action Dispatched action.
*
* @return {boolean} Updated state.
*/
export function hoveredBlockClientId( state = false, action ) {
switch ( action.type ) {
case 'HOVER_BLOCK':
return action.clientId;
}

return state;
}

const combinedReducers = combineReducers( {
blocks,
isDragging,
Expand Down Expand Up @@ -2100,6 +2117,7 @@ const combinedReducers = combineReducers( {
blockRemovalRules,
openedBlockSettingsMenu,
registeredInserterMediaCategories,
hoveredBlockClientId,
} );

function withAutomaticChangeReset( reducer ) {
Expand Down
10 changes: 10 additions & 0 deletions packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2809,6 +2809,16 @@ export function isBlockVisible( state, clientId ) {
return state.blockVisibility?.[ clientId ] ?? true;
}

/**
* Returns the currently hovered block.
*
* @param {Object} state Global application state.
* @return {Object} Client Id of the hovered block.
*/
export function getHoveredBlockClientId( state ) {
return state.hoveredBlockClientId;
}

/**
* Returns the list of all hidden blocks.
*
Expand Down

0 comments on commit 6a466a0

Please sign in to comment.