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

Add a built-in exploded mode instead of a separate view #40376

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/reference-guides/data/data-core-block-editor.md
Expand Up @@ -1492,7 +1492,7 @@ Action that enables or disables the navigation mode.

_Parameters_

- _isNavigationMode_ `string`: Enable/Disable navigation mode.
- _isNavigationMode_ `boolean`: Enable/Disable navigation mode.

### setTemplateValidity

Expand Down
51 changes: 30 additions & 21 deletions packages/block-editor/src/components/block-list-appender/index.js
Expand Up @@ -6,7 +6,7 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { withSelect } from '@wordpress/data';
import { useSelect } from '@wordpress/data';
import { getDefaultBlockName } from '@wordpress/blocks';

/**
Expand All @@ -18,14 +18,38 @@ import { store as blockEditorStore } from '../../store';

function BlockListAppender( {
rootClientId,
canInsertDefaultBlock,
isLocked,
renderAppender: CustomAppender,
className,
selectedBlockClientId,
tagName: TagName = 'div',
} ) {
if ( isLocked || CustomAppender === false ) {
const {
hideInserter,
canInsertDefaultBlock,
selectedBlockClientId,
} = useSelect(
( select ) => {
const {
canInsertBlockType,
getTemplateLock,
getSelectedBlockClientId,
__unstableGetEditorMode,
} = select( blockEditorStore );

return {
hideInserter:
!! getTemplateLock( rootClientId ) ||
__unstableGetEditorMode() !== 'edit',
canInsertDefaultBlock: canInsertBlockType(
getDefaultBlockName(),
rootClientId
),
selectedBlockClientId: getSelectedBlockClientId(),
};
},
[ rootClientId ]
);

if ( hideInserter || CustomAppender === false ) {
return null;
}

Expand Down Expand Up @@ -92,19 +116,4 @@ function BlockListAppender( {
);
}

export default withSelect( ( select, { rootClientId } ) => {
const {
canInsertBlockType,
getTemplateLock,
getSelectedBlockClientId,
} = select( blockEditorStore );

return {
isLocked: !! getTemplateLock( rootClientId ),
canInsertDefaultBlock: canInsertBlockType(
getDefaultBlockName(),
rootClientId
),
selectedBlockClientId: getSelectedBlockClientId(),
};
} )( BlockListAppender );
export default BlockListAppender;
9 changes: 5 additions & 4 deletions packages/block-editor/src/components/block-list/index.js
Expand Up @@ -34,16 +34,16 @@ export const IntersectionObserver = createContext();
function Root( { className, ...settings } ) {
const [ element, setElement ] = useState();
const isLargeViewport = useViewportMatch( 'medium' );
const { isOutlineMode, isFocusMode, isNavigationMode } = useSelect(
const { isOutlineMode, isFocusMode, editorMode } = useSelect(
( select ) => {
const { getSettings, isNavigationMode: _isNavigationMode } = select(
const { getSettings, __unstableGetEditorMode } = select(
blockEditorStore
);
const { outlineMode, focusMode } = getSettings();
return {
isOutlineMode: outlineMode,
isFocusMode: focusMode,
isNavigationMode: _isNavigationMode(),
editorMode: __unstableGetEditorMode(),
};
},
[]
Expand Down Expand Up @@ -75,7 +75,8 @@ function Root( { className, ...settings } ) {
className: classnames( 'is-root-container', className, {
'is-outline-mode': isOutlineMode,
'is-focus-mode': isFocusMode && isLargeViewport,
'is-navigate-mode': isNavigationMode,
'is-navigate-mode': editorMode === 'navigation',
'is-exploded-mode': editorMode === 'exploded',
} ),
},
settings
Expand Down
35 changes: 35 additions & 0 deletions packages/block-editor/src/components/block-list/style.scss
Expand Up @@ -408,3 +408,38 @@
margin-bottom: auto;
}
}

/** Exploded mode styles **/
.is-root-container.is-exploded-mode > .wp-block {
transform-origin: center center;
position: relative;
overflow: hidden;

&::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: z-index(".block-editor-block-content-overlay__overlay");
pointer-events: unset !important;
}

&:hover:not(.is-selected)::after {
background: rgba(var(--wp-admin-theme-color--rgb), 0.1);
box-shadow: 0 0 0 0 var(--wp-admin-theme-color) inset;
}

&.overlay-active * {
pointer-events: none;
}

&.is-selected {
box-shadow: $border-width 0 0 0 var(--wp-admin-theme-color) inset;
}
}

.is-root-container.is-exploded-mode > .block-list-appender {
display: none;
}
Expand Up @@ -74,6 +74,8 @@ export function useBlockProps(
isPartOfSelection,
adjustScrolling,
enableAnimation,
isExplodedMode,
isRootBlock,
} = useSelect(
( select ) => {
const {
Expand All @@ -86,6 +88,8 @@ export function useBlockProps(
isBlockMultiSelected,
isAncestorMultiSelected,
isFirstMultiSelectedBlock,
__unstableGetEditorMode,
getBlockRootClientId,
} = select( blockEditorStore );
const isSelected = isBlockSelected( clientId );
const isPartOfMultiSelection =
Expand All @@ -106,6 +110,8 @@ export function useBlockProps(
enableAnimation:
! isTyping() &&
getGlobalBlockCount() <= BLOCK_ANIMATION_THRESHOLD,
isExplodedMode: __unstableGetEditorMode() === 'exploded',
isRootBlock: ! getBlockRootClientId( clientId ),
};
},
[ clientId ]
Expand All @@ -128,6 +134,7 @@ export function useBlockProps(
adjustScrolling,
enableAnimation,
triggerAnimationOnChange: index,
scale: isExplodedMode && isRootBlock ? 0.8 : 1,
} ),
useDisabled( { isDisabled: ! __unstableIsDisabled } ),
] );
Expand Down
Expand Up @@ -36,15 +36,15 @@ function useInitialPosition( clientId ) {
( select ) => {
const {
getSelectedBlocksInitialCaretPosition,
isNavigationMode,
__unstableGetEditorMode,
isBlockSelected,
} = select( blockEditorStore );

if ( ! isBlockSelected( clientId ) ) {
return;
}

if ( isNavigationMode() ) {
if ( __unstableGetEditorMode() !== 'edit' ) {
return;
}

Expand Down
Expand Up @@ -26,8 +26,14 @@ function listener( event ) {
*/
export function useIsHovered() {
const isEnabled = useSelect( ( select ) => {
const { isNavigationMode, getSettings } = select( blockEditorStore );
return isNavigationMode() || getSettings().outlineMode;
const { __unstableGetEditorMode, getSettings } = select(
blockEditorStore
);
return (
__unstableGetEditorMode() === 'navigation' ||
( getSettings().outlineMode &&
__unstableGetEditorMode() === 'exploded' )
);
}, [] );

return useRefEffect(
Expand Down
57 changes: 39 additions & 18 deletions packages/block-editor/src/components/block-popover/inbetween.js
Expand Up @@ -7,7 +7,13 @@ import classnames from 'classnames';
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';
import { useCallback, useMemo, createContext } from '@wordpress/element';
import {
useCallback,
useMemo,
createContext,
useState,
useEffect,
} from '@wordpress/element';
import { Popover } from '@wordpress/components';
import { isRTL } from '@wordpress/i18n';

Expand All @@ -28,6 +34,13 @@ function BlockPopoverInbetween( {
__unstableContentRef,
...props
} ) {
// This is a temporary hack to get the inbetween inserter to recompute properly.
const [ positionRecompute, forceRecompute ] = useState( {} );
useEffect( () => {
const intervalHandle = setInterval( forceRecompute, 500 );
return () => clearInterval( intervalHandle );
}, [] );
Comment on lines +37 to +42
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a hack to be able to adjust the popover position while the animation is on going. Basically the popover position is dependent on the "block position" and every time the block position changes, we need to recompute the popover position and unfortunately we don't have APIs to "subscribe" to position and size of a given DOM element. (without inserting anything inside that element like we do with the resize handler).

Please let me know if there's anything better that we can use here.


const { orientation, rootClientId, isVisible } = useSelect(
( select ) => {
const {
Expand Down Expand Up @@ -66,9 +79,7 @@ function BlockPopoverInbetween( {

if ( isVertical ) {
return {
width: previousElement
? previousElement.offsetWidth
: nextElement.offsetWidth,
width: previousRect ? previousRect.width : nextRect.width,
height:
nextRect && previousRect
? nextRect.top - previousRect.bottom
Expand All @@ -85,11 +96,15 @@ function BlockPopoverInbetween( {

return {
width,
height: previousElement
? previousElement.offsetHeight
: nextElement.offsetHeight,
height: previousRect ? previousRect.height : nextRect.height,
};
}, [ previousElement, nextElement, isVertical ] );
}, [
previousElement,
nextElement,
isVertical,
positionRecompute,
isVisible,
] );

const getAnchorRect = useCallback( () => {
if ( ( ! previousElement && ! nextElement ) || ! isVisible ) {
Expand All @@ -110,8 +125,8 @@ function BlockPopoverInbetween( {
return {
top: previousRect ? previousRect.bottom : nextRect.top,
left: previousRect ? previousRect.right : nextRect.right,
right: previousRect ? previousRect.left : nextRect.left,
bottom: nextRect ? nextRect.top : previousRect.bottom,
right: previousRect ? previousRect.right : nextRect.right,
bottom: previousRect ? previousRect.bottom : nextRect.top,
height: 0,
width: 0,
ownerDocument,
Expand All @@ -121,8 +136,8 @@ function BlockPopoverInbetween( {
return {
top: previousRect ? previousRect.bottom : nextRect.top,
left: previousRect ? previousRect.left : nextRect.left,
right: previousRect ? previousRect.right : nextRect.right,
bottom: nextRect ? nextRect.top : previousRect.bottom,
right: previousRect ? previousRect.left : nextRect.left,
bottom: previousRect ? previousRect.bottom : nextRect.top,
height: 0,
width: 0,
ownerDocument,
Expand All @@ -133,8 +148,8 @@ function BlockPopoverInbetween( {
return {
top: previousRect ? previousRect.top : nextRect.top,
left: previousRect ? previousRect.left : nextRect.right,
right: nextRect ? nextRect.right : previousRect.left,
bottom: previousRect ? previousRect.bottom : nextRect.bottom,
right: previousRect ? previousRect.left : nextRect.right,
bottom: previousRect ? previousRect.top : nextRect.top,
height: 0,
width: 0,
ownerDocument,
Expand All @@ -144,13 +159,13 @@ function BlockPopoverInbetween( {
return {
top: previousRect ? previousRect.top : nextRect.top,
left: previousRect ? previousRect.right : nextRect.left,
right: nextRect ? nextRect.left : previousRect.right,
bottom: previousRect ? previousRect.bottom : nextRect.bottom,
right: previousRect ? previousRect.right : nextRect.left,
bottom: previousRect ? previousRect.left : nextRect.right,
height: 0,
width: 0,
ownerDocument,
};
}, [ previousElement, nextElement ] );
}, [ previousElement, nextElement, positionRecompute, isVisible ] );

const popoverScrollRef = usePopoverScroll( __unstableContentRef );

Expand Down Expand Up @@ -183,8 +198,14 @@ function BlockPopoverInbetween( {
props.className
) }
__unstableForcePosition
placement="bottom-start"
>
<div style={ style }>{ children }</div>
<div
className="block-editor-block-popover__inbetween-container"
style={ style }
>
{ children }
</div>
</Popover>
);
/* eslint-enable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
Expand Down
Expand Up @@ -62,6 +62,7 @@ export default function BlockPopover( {
// Observe movement for block animations (especially horizontal).
__unstableObserveElement={ selectedElement }
__unstableForcePosition
__unstableShift
{ ...props }
className={ classnames(
'block-editor-block-popover',
Expand Down
15 changes: 10 additions & 5 deletions packages/block-editor/src/components/block-popover/style.scss
Expand Up @@ -6,6 +6,9 @@
// like the popover is impacted by the block gap margin.
margin: 0 !important;

// Allow clicking through the toolbar holder.
pointer-events: none;

.components-popover__content {
margin: 0 !important;
min-width: auto;
Expand All @@ -16,13 +19,15 @@
box-shadow: none;
overflow-y: visible;

// Allow clicking through the toolbar holder.
pointer-events: none;

// Position the block toolbar.
> * {
> div > * {
pointer-events: all;
}
}
}

.block-editor-block-popover__inbetween-container {
pointer-events: none !important;
> div > * {
pointer-events: all;
}
}