Skip to content

Commit 7ebc19a

Browse files
draganescugetdavetalldanciampojsnajdr
authored
Manual cherry pick for #65627 (#66119)
* Make zoom out vertical toolbar consistent (#65627) * enable vertical toolbar for non full width elements, anchor based on parent * Update packages/block-editor/src/components/block-popover/index.js Co-authored-by: Dave Smith <[email protected]> * Update packages/block-editor/src/components/block-popover/index.js Co-authored-by: Dave Smith <[email protected]> * make zoom out check a dependency of the memoization, improve code readability * comment typos * subscribe to state instead of calculating zoom out view state when calculating the anchor * get the section wrapper for anchoring instead of the parent * use a selector instead of computing on the fly the parent section * check if the block element exists yet before computing the anchor * check if the block element exists yet before computing the anchor * differentiate between section toolbar and block toolbar for correct positioning when both are visible * address some nits * make the select in anchor setting rerun when block selection changes * fix bug with anchor rect when zoom out not engaged * fix typo * Use root container element in post editor as popover anchor * improve comment * improve comment to max improvement possible Co-authored-by: Dave Smith <[email protected]> * mega nit commit Co-authored-by: Dave Smith <[email protected]> * Fix bug with Posts with no full width blocks * give up on section root, always seek canvas element to position vertical toolbar, also fix typo * introduce the concept of canvas via a 1st variable * Use `__unstableContentRef` for zoomed out toolbar positioning instead of dom classname --------- Co-authored-by: draganescu <[email protected]> Co-authored-by: getdave <[email protected]> Co-authored-by: talldan <[email protected]> Co-authored-by: ciampo <[email protected]> Co-authored-by: jsnajdr <[email protected]> Co-authored-by: MaggieCabrera <[email protected]> Co-authored-by: richtabor <[email protected]> Co-authored-by: stokesman <[email protected]> Co-authored-by: andrewserong <[email protected]> * bring over two private selectors from trunk the fix depends on --------- Co-authored-by: Dave Smith <[email protected]> Co-authored-by: getdave <[email protected]> Co-authored-by: talldan <[email protected]> Co-authored-by: ciampo <[email protected]> Co-authored-by: jsnajdr <[email protected]> Co-authored-by: MaggieCabrera <[email protected]> Co-authored-by: richtabor <[email protected]> Co-authored-by: stokesman <[email protected]> Co-authored-by: andrewserong <[email protected]>
1 parent d0dae48 commit 7ebc19a

File tree

4 files changed

+113
-6
lines changed

4 files changed

+113
-6
lines changed

packages/block-editor/src/components/block-popover/index.js

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import clsx from 'clsx';
88
*/
99
import { useMergeRefs } from '@wordpress/compose';
1010
import { Popover } from '@wordpress/components';
11+
import { useSelect } from '@wordpress/data';
1112
import {
1213
forwardRef,
1314
useMemo,
@@ -21,6 +22,8 @@ import {
2122
import { useBlockElement } from '../block-list/use-block-props/use-block-refs';
2223
import usePopoverScroll from './use-popover-scroll';
2324
import { rectUnion, getVisibleElementBounds } from '../../utils/dom';
25+
import { store as blockEditorStore } from '../../store';
26+
import { unlock } from '../../lock-unlock';
2427

2528
const MAX_POPOVER_RECOMPUTE_COUNTER = Number.MAX_SAFE_INTEGER;
2629

@@ -74,12 +77,38 @@ function BlockPopover(
7477
};
7578
}, [ selectedElement ] );
7679

80+
const { isZoomOut, parentSectionBlock, isSectionSelected } = useSelect(
81+
( select ) => {
82+
const {
83+
isZoomOut: isZoomOutSelector,
84+
getSectionRootClientId,
85+
getParentSectionBlock,
86+
getBlockOrder,
87+
} = unlock( select( blockEditorStore ) );
88+
89+
return {
90+
isZoomOut: isZoomOutSelector(),
91+
parentSectionBlock:
92+
getParentSectionBlock( clientId ) ?? clientId,
93+
isSectionSelected: getBlockOrder(
94+
getSectionRootClientId()
95+
).includes( clientId ),
96+
};
97+
},
98+
[ clientId ]
99+
);
100+
101+
// This element is used to position the zoom out view vertical toolbar
102+
// correctly, relative to the selected section.
103+
const parentSectionElement = useBlockElement( parentSectionBlock );
104+
77105
const popoverAnchor = useMemo( () => {
78106
if (
79107
// popoverDimensionsRecomputeCounter is by definition always equal or greater
80108
// than 0. This check is only there to satisfy the correctness of the
81109
// exhaustive-deps rule for the `useMemo` hook.
82110
popoverDimensionsRecomputeCounter < 0 ||
111+
( isZoomOut && ! parentSectionElement ) ||
83112
! selectedElement ||
84113
( bottomClientId && ! lastSelectedElement )
85114
) {
@@ -88,6 +117,35 @@ function BlockPopover(
88117

89118
return {
90119
getBoundingClientRect() {
120+
// The zoom out view has a vertical block toolbar that should always
121+
// be on the edge of the canvas, aligned to the top of the currently
122+
// selected section. This condition changes the anchor of the toolbar
123+
// to the section instead of the block to handle blocks that are
124+
// not full width and nested blocks to keep section height.
125+
if ( isZoomOut && isSectionSelected ) {
126+
// Compute the height based on the parent section of the
127+
// selected block, because the selected block may be
128+
// shorter than the section.
129+
const canvasElementRect = getVisibleElementBounds(
130+
__unstableContentRef.current
131+
);
132+
const parentSectionElementRect =
133+
getVisibleElementBounds( parentSectionElement );
134+
const anchorHeight =
135+
parentSectionElementRect.bottom -
136+
parentSectionElementRect.top;
137+
138+
// Always use the width of the section root element to make sure
139+
// the toolbar is always on the edge of the canvas.
140+
const anchorWidth = canvasElementRect.width;
141+
return new window.DOMRectReadOnly(
142+
canvasElementRect.left,
143+
parentSectionElementRect.top,
144+
anchorWidth,
145+
anchorHeight
146+
);
147+
}
148+
91149
return lastSelectedElement
92150
? rectUnion(
93151
getVisibleElementBounds( selectedElement ),
@@ -98,10 +156,14 @@ function BlockPopover(
98156
contextElement: selectedElement,
99157
};
100158
}, [
159+
popoverDimensionsRecomputeCounter,
160+
isZoomOut,
161+
parentSectionElement,
162+
selectedElement,
101163
bottomClientId,
102164
lastSelectedElement,
103-
selectedElement,
104-
popoverDimensionsRecomputeCounter,
165+
isSectionSelected,
166+
__unstableContentRef,
105167
] );
106168

107169
if ( ! selectedElement || ( bottomClientId && ! lastSelectedElement ) ) {

packages/block-editor/src/components/block-tools/use-show-block-tools.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { isUnmodifiedDefaultBlock } from '@wordpress/blocks';
88
* Internal dependencies
99
*/
1010
import { store as blockEditorStore } from '../../store';
11+
import { unlock } from '../../lock-unlock';
1112

1213
/**
1314
* Source of truth for which block tools are showing in the block editor.
@@ -25,7 +26,9 @@ export function useShowBlockTools() {
2526
hasMultiSelection,
2627
__unstableGetEditorMode,
2728
isTyping,
28-
} = select( blockEditorStore );
29+
getBlockOrder,
30+
getSectionRootClientId,
31+
} = unlock( select( blockEditorStore ) );
2932

3033
const clientId =
3134
getSelectedBlockClientId() || getFirstMultiSelectedBlockClientId();
@@ -48,11 +51,14 @@ export function useShowBlockTools() {
4851
editorMode === 'navigation';
4952

5053
const isZoomOut = editorMode === 'zoom-out';
54+
const isSectionSelected = getBlockOrder(
55+
getSectionRootClientId()
56+
).includes( clientId );
5157
const _showZoomOutToolbar =
58+
clientId &&
5259
isZoomOut &&
53-
block?.attributes?.align === 'full' &&
5460
! _showEmptyBlockSideInserter &&
55-
! maybeShowBreadcrumb;
61+
isSectionSelected;
5662
const _showBlockToolbarPopover =
5763
! _showZoomOutToolbar &&
5864
! getSettings().hasFixedToolbar &&

packages/block-editor/src/components/block-tools/zoom-out-popover.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import clsx from 'clsx';
55
/**
66
* Internal dependencies
77
*/
8-
import BlockPopover from '../block-popover';
8+
import { PrivateBlockPopover as BlockPopover } from '../block-popover';
99
import useBlockToolbarPopoverProps from './use-block-toolbar-popover-props';
1010
import useSelectedBlockToolProps from './use-selected-block-tool-props';
1111
import ZoomOutToolbar from './zoom-out-toolbar';
@@ -29,6 +29,7 @@ export default function ZoomOutPopover( { clientId, __unstableContentRef } ) {
2929

3030
return (
3131
<BlockPopover
32+
__unstableContentRef={ __unstableContentRef }
3233
clientId={ capturingClientId || clientId }
3334
bottomClientId={ lastClientId }
3435
className={ clsx( 'zoom-out-toolbar-popover', {

packages/block-editor/src/store/private-selectors.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
getBlockName,
1616
getTemplateLock,
1717
getClientIdsWithDescendants,
18+
isNavigationMode,
1819
} from './selectors';
1920
import {
2021
checkAllowListRecursive,
@@ -580,3 +581,40 @@ export function getZoomLevel( state ) {
580581
export function isZoomOut( state ) {
581582
return getZoomLevel( state ) < 100;
582583
}
584+
585+
/**
586+
* Retrieves the client ID of the parent section block.
587+
*
588+
* @param {Object} state Global application state.
589+
* @param {string} clientId Client Id of the block.
590+
*
591+
* @return {?string} Client ID of the ancestor block that is content locking the block.
592+
*/
593+
export const getParentSectionBlock = ( state, clientId ) => {
594+
let current = clientId;
595+
let result;
596+
while ( ! result && ( current = state.blocks.parents.get( current ) ) ) {
597+
if ( isSectionBlock( state, current ) ) {
598+
result = current;
599+
}
600+
}
601+
return result;
602+
};
603+
604+
/**
605+
* Retrieves the client ID is a content locking parent
606+
*
607+
* @param {Object} state Global application state.
608+
* @param {string} clientId Client Id of the block.
609+
*
610+
* @return {boolean} Whether the block is a content locking parent.
611+
*/
612+
export function isSectionBlock( state, clientId ) {
613+
const sectionRootClientId = getSectionRootClientId( state );
614+
const sectionClientIds = getBlockOrder( state, sectionRootClientId );
615+
return (
616+
getBlockName( state, clientId ) === 'core/block' ||
617+
getTemplateLock( state, clientId ) === 'contentOnly' ||
618+
( isNavigationMode( state ) && sectionClientIds.includes( clientId ) )
619+
);
620+
}

0 commit comments

Comments
 (0)