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

Manual cherry pick for #65627 #66119

Merged
merged 2 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
66 changes: 64 additions & 2 deletions packages/block-editor/src/components/block-popover/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import clsx from 'clsx';
*/
import { useMergeRefs } from '@wordpress/compose';
import { Popover } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import {
forwardRef,
useMemo,
Expand All @@ -21,6 +22,8 @@ import {
import { useBlockElement } from '../block-list/use-block-props/use-block-refs';
import usePopoverScroll from './use-popover-scroll';
import { rectUnion, getVisibleElementBounds } from '../../utils/dom';
import { store as blockEditorStore } from '../../store';
import { unlock } from '../../lock-unlock';

const MAX_POPOVER_RECOMPUTE_COUNTER = Number.MAX_SAFE_INTEGER;

Expand Down Expand Up @@ -74,12 +77,38 @@ function BlockPopover(
};
}, [ selectedElement ] );

const { isZoomOut, parentSectionBlock, isSectionSelected } = useSelect(
( select ) => {
const {
isZoomOut: isZoomOutSelector,
getSectionRootClientId,
getParentSectionBlock,
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we're missing whatever PR included getParentSectionBlock.

index.js:92 Uncaught TypeError: getParentSectionBlock is not a function
    at index.js:92:6
    at index.js:154:11
    at __unstableMarkListeningStores (registry.js:123:20)
    at Object.__unstableMarkListeningStores (registry.js:204:30)
    at updateValue (index.js:153:31)
    at index.js:203:3
    at useMappingSelect (index.js:228:34)
    at useSelect (index.js:317:5)
    at BlockPopover (index.js:80:72)
    at renderWithHooks (react-dom.js?ver=18:15496:20)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ups! on it

getBlockOrder,
} = unlock( select( blockEditorStore ) );

return {
isZoomOut: isZoomOutSelector(),
parentSectionBlock:
getParentSectionBlock( clientId ) ?? clientId,
isSectionSelected: getBlockOrder(
getSectionRootClientId()
).includes( clientId ),
};
},
[ clientId ]
);

// This element is used to position the zoom out view vertical toolbar
// correctly, relative to the selected section.
const parentSectionElement = useBlockElement( parentSectionBlock );

const popoverAnchor = useMemo( () => {
if (
// popoverDimensionsRecomputeCounter is by definition always equal or greater
// than 0. This check is only there to satisfy the correctness of the
// exhaustive-deps rule for the `useMemo` hook.
popoverDimensionsRecomputeCounter < 0 ||
( isZoomOut && ! parentSectionElement ) ||
! selectedElement ||
( bottomClientId && ! lastSelectedElement )
) {
Expand All @@ -88,6 +117,35 @@ function BlockPopover(

return {
getBoundingClientRect() {
// The zoom out view has a vertical block toolbar that should always
// be on the edge of the canvas, aligned to the top of the currently
// selected section. This condition changes the anchor of the toolbar
// to the section instead of the block to handle blocks that are
// not full width and nested blocks to keep section height.
if ( isZoomOut && isSectionSelected ) {
// Compute the height based on the parent section of the
// selected block, because the selected block may be
// shorter than the section.
const canvasElementRect = getVisibleElementBounds(
__unstableContentRef.current
);
const parentSectionElementRect =
getVisibleElementBounds( parentSectionElement );
const anchorHeight =
parentSectionElementRect.bottom -
parentSectionElementRect.top;

// Always use the width of the section root element to make sure
// the toolbar is always on the edge of the canvas.
const anchorWidth = canvasElementRect.width;
return new window.DOMRectReadOnly(
canvasElementRect.left,
parentSectionElementRect.top,
anchorWidth,
anchorHeight
);
}

return lastSelectedElement
? rectUnion(
getVisibleElementBounds( selectedElement ),
Expand All @@ -98,10 +156,14 @@ function BlockPopover(
contextElement: selectedElement,
};
}, [
popoverDimensionsRecomputeCounter,
isZoomOut,
parentSectionElement,
selectedElement,
bottomClientId,
lastSelectedElement,
selectedElement,
popoverDimensionsRecomputeCounter,
isSectionSelected,
__unstableContentRef,
] );

if ( ! selectedElement || ( bottomClientId && ! lastSelectedElement ) ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { isUnmodifiedDefaultBlock } from '@wordpress/blocks';
* Internal dependencies
*/
import { store as blockEditorStore } from '../../store';
import { unlock } from '../../lock-unlock';

/**
* Source of truth for which block tools are showing in the block editor.
Expand All @@ -25,7 +26,9 @@ export function useShowBlockTools() {
hasMultiSelection,
__unstableGetEditorMode,
isTyping,
} = select( blockEditorStore );
getBlockOrder,
getSectionRootClientId,
} = unlock( select( blockEditorStore ) );

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

const isZoomOut = editorMode === 'zoom-out';
const isSectionSelected = getBlockOrder(
getSectionRootClientId()
).includes( clientId );
const _showZoomOutToolbar =
clientId &&
isZoomOut &&
block?.attributes?.align === 'full' &&
! _showEmptyBlockSideInserter &&
! maybeShowBreadcrumb;
isSectionSelected;
const _showBlockToolbarPopover =
! _showZoomOutToolbar &&
! getSettings().hasFixedToolbar &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import clsx from 'clsx';
/**
* Internal dependencies
*/
import BlockPopover from '../block-popover';
import { PrivateBlockPopover as BlockPopover } from '../block-popover';
import useBlockToolbarPopoverProps from './use-block-toolbar-popover-props';
import useSelectedBlockToolProps from './use-selected-block-tool-props';
import ZoomOutToolbar from './zoom-out-toolbar';
Expand All @@ -29,6 +29,7 @@ export default function ZoomOutPopover( { clientId, __unstableContentRef } ) {

return (
<BlockPopover
__unstableContentRef={ __unstableContentRef }
clientId={ capturingClientId || clientId }
bottomClientId={ lastClientId }
className={ clsx( 'zoom-out-toolbar-popover', {
Expand Down
38 changes: 38 additions & 0 deletions packages/block-editor/src/store/private-selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
getBlockName,
getTemplateLock,
getClientIdsWithDescendants,
isNavigationMode,
} from './selectors';
import {
checkAllowListRecursive,
Expand Down Expand Up @@ -580,3 +581,40 @@ export function getZoomLevel( state ) {
export function isZoomOut( state ) {
return getZoomLevel( state ) < 100;
}

/**
* Retrieves the client ID of the parent section block.
*
* @param {Object} state Global application state.
* @param {string} clientId Client Id of the block.
*
* @return {?string} Client ID of the ancestor block that is content locking the block.
*/
export const getParentSectionBlock = ( state, clientId ) => {
let current = clientId;
let result;
while ( ! result && ( current = state.blocks.parents.get( current ) ) ) {
if ( isSectionBlock( state, current ) ) {
result = current;
}
}
return result;
};

/**
* Retrieves the client ID is a content locking parent
*
* @param {Object} state Global application state.
* @param {string} clientId Client Id of the block.
*
* @return {boolean} Whether the block is a content locking parent.
*/
export function isSectionBlock( state, clientId ) {
const sectionRootClientId = getSectionRootClientId( state );
const sectionClientIds = getBlockOrder( state, sectionRootClientId );
return (
getBlockName( state, clientId ) === 'core/block' ||
getTemplateLock( state, clientId ) === 'contentOnly' ||
( isNavigationMode( state ) && sectionClientIds.includes( clientId ) )
);
}
Loading