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

Writing flow: restore click redirect between blocks #42475

Open
wants to merge 12 commits into
base: trunk
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ function BlockPopoverInbetween( {
key={ nextClientId + '--' + rootClientId }
{ ...props }
className={ classnames(
'block-editor-block-popover',
'block-editor-block-popover block-editor-block-popover-in-between',
props.className
) }
__unstableForcePosition
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function InsertionPointPopover( {
__unstablePopoverSlot,
__unstableContentRef,
} ) {
const { selectBlock, hideInsertionPoint } = useDispatch( blockEditorStore );
const { hideInsertionPoint } = useDispatch( blockEditorStore );
const openRef = useContext( InsertionPointOpenRef );
const ref = useRef();
const {
Expand Down Expand Up @@ -74,12 +74,6 @@ function InsertionPointPopover( {

const disableMotion = useReducedMotion();

function onClick( event ) {
if ( event.target === ref.current && nextClientId ) {
selectBlock( nextClientId, -1 );
}
}

function onFocus( event ) {
// Only handle click on the wrapper specifically, and not an event
// bubbled from the inserter itself.
Expand Down Expand Up @@ -190,11 +184,8 @@ function InsertionPointPopover( {
exit="start"
ref={ ref }
tabIndex={ -1 }
onClick={ onClick }
onFocus={ onFocus }
className={ classnames( className, {
'is-with-inserter': isInserterShown,
} ) }
className={ className }
onHoverEnd={ maybeHideInserterPoint }
>
<motion.div
Expand All @@ -205,7 +196,10 @@ function InsertionPointPopover( {
<motion.div
variants={ inserterVariants }
className={ classnames(
'block-editor-block-list__insertion-point-inserter'
'block-editor-block-list__insertion-point-inserter',
{
'is-with-inserter': isInserterShown,
}
) }
>
<Inserter
Expand Down
6 changes: 6 additions & 0 deletions packages/block-editor/src/components/block-tools/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
* Insertion Point.
*/

.components-popover.block-editor-block-popover.block-editor-block-popover-in-between,
.components-popover.block-editor-block-popover.block-editor-block-popover-in-between .components-popover__content > * {
pointer-events: none;
}

.block-editor-block-list__insertion-point {
position: absolute;
top: 0;
Expand Down Expand Up @@ -29,6 +34,7 @@

// This is the clickable plus.
.block-editor-block-list__insertion-point-inserter {
pointer-events: all;
// Don't show on mobile.
display: none;
position: absolute;
Expand Down
2 changes: 2 additions & 0 deletions packages/block-editor/src/components/writing-flow/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import useSelectAll from './use-select-all';
import useDragSelection from './use-drag-selection';
import useSelectionObserver from './use-selection-observer';
import useClickSelection from './use-click-selection';
import useClickRedirect from './use-click-redirect';
import useInput from './use-input';
import { store as blockEditorStore } from '../../store';

Expand All @@ -39,6 +40,7 @@ export function useWritingFlow() {
useDragSelection(),
useSelectionObserver(),
useClickSelection(),
useClickRedirect(),
useMultiSelection(),
useSelectAll(),
useArrowNav(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* WordPress dependencies
*/
import { useRefEffect } from '@wordpress/compose';

export default function useClickSelection() {
return useRefEffect( ( node ) => {
function onMouseDown( event ) {
if (
! event.target.classList.contains(
'block-editor-block-list__layout'
)
) {
return;
}

node.contentEditable = true;
// Firefox doesn't automatically move focus.
node.focus();
// The selection observer will turn off contentEditable after a
// selection change.
}

node.addEventListener( 'mousedown', onMouseDown );

return () => {
node.removeEventListener( 'mousedown', onMouseDown );
};
}, [] );
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,40 @@ export default function useSelectionObserver() {
// For now we check if the event is a `mouse` event.
const isClickShift = event.shiftKey && event.type === 'mouseup';
if ( selection.isCollapsed && ! isClickShift ) {
// Only process if selection is enabled on the whole editor.
if ( node.getAttribute( 'contenteditable' ) === 'false' ) {
return;
}

let selectedNode = extractSelectionStartNode( selection );

setContentEditableWrapper( node, false );

const { activeElement } = ownerDocument;

// No selection.
if ( ! selectedNode ) return;
// Already focussed.
if ( selectedNode === activeElement ) return;
// Wrapper is focussed.
if ( node === activeElement ) return;
// Focus lies outside the editor.
if ( ! node.contains( activeElement ) ) return;

// Ensure that the selection is an element.
if ( selectedNode.nodeType !== selectedNode.ELEMENT_NODE ) {
selectedNode = selectedNode.parentElement;
}

// Find the closest focusable element.
selectedNode = selectedNode.closest( '[tabindex]' );

// Focus shouldn't be moved outside the editor.
if ( ! node.contains( selectedNode ) ) return;
// And focus shouldn't be moved to the editor's wrapper.
if ( selectedNode === node ) return;

selectedNode.focus();
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import type { RequestUtils } from './index';
import { WP_BASE_URL } from '../config';

const THEMES_URL = new URL( '/wp-admin/themes.php', WP_BASE_URL ).href;
const THEMES_URL = new URL( 'wp-admin/themes.php', WP_BASE_URL ).href;

async function activateTheme(
this: RequestUtils,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,29 @@ exports[`Writing Flow should not have a dead zone above an aligned block 1`] = `
<!-- /wp:image -->"
`;

exports[`Writing Flow should not have a dead zone abover separator 1`] = `
"<!-- wp:paragraph -->
<p>1</p>
<!-- /wp:paragraph -->

<!-- wp:separator -->
<hr class=\\"wp-block-separator has-alpha-channel-opacity\\"/>
<!-- /wp:separator -->"
`;

exports[`Writing Flow should not have a dead zone abover separator 2`] = `
"<!-- wp:paragraph -->
<p>1</p>
<!-- /wp:paragraph -->"
`;

exports[`Writing Flow should not have a dead zone between blocks (lower) 1`] = `
"<!-- wp:paragraph -->
<p>1</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>23</p>
<p>32</p>
<!-- /wp:paragraph -->"
`;

Expand Down
30 changes: 30 additions & 0 deletions packages/e2e-tests/specs/editor/various/writing-flow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -613,11 +613,41 @@ describe( 'Writing Flow', () => {
const lowerInserterY = inserterRect.y + ( 2 * inserterRect.height ) / 3;

await page.mouse.click( x, lowerInserterY );
await page.waitForFunction(
() => window.getSelection().type === 'Caret'
);
await page.keyboard.type( '3' );

expect( await getEditedPostContent() ).toMatchSnapshot();
} );

it( 'should not have a dead zone abover separator', async () => {
await page.keyboard.press( 'Enter' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( '---' );
await page.keyboard.press( 'Enter' );
await page.keyboard.press( 'ArrowUp' );
await page.keyboard.type( '1' );

// Test setup: "1" + separator.
expect( await getEditedPostContent() ).toMatchSnapshot();

// Find a point outside the paragraph between the blocks where it's
// expected that the sibling inserter would be placed.
const paragraph = await page.$( '[data-type="core/paragraph"]' );
const paragraphRect = await paragraph.boundingBox();
const x = paragraphRect.x + ( 2 * paragraphRect.width ) / 3;
const y = paragraphRect.y + paragraphRect.height + 1;

await page.mouse.click( x, y );
await page.waitForFunction(
() => window.getSelection().type === 'Caret'
);
await page.keyboard.press( 'Backspace' );

expect( await getEditedPostContent() ).toMatchSnapshot();
} );

it( 'should not have a dead zone above an aligned block', async () => {
await page.keyboard.press( 'Enter' );
await page.keyboard.type( '1' );
Expand Down