Skip to content

Commit

Permalink
Fix regression: Content locking does not stops automatically when an …
Browse files Browse the repository at this point in the history
…outside block is selected.
  • Loading branch information
jorgefilipecosta committed Jan 11, 2024
1 parent cd548af commit 6883e1b
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 52 deletions.
30 changes: 28 additions & 2 deletions packages/block-editor/src/components/block-list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
useMergeRefs,
useDebounce,
} from '@wordpress/compose';
import { createContext, useMemo, useCallback } from '@wordpress/element';
import { createContext, useMemo, useCallback, useEffect } from '@wordpress/element';

/**
* Internal dependencies
Expand Down Expand Up @@ -113,6 +113,29 @@ function Root( { className, ...settings } ) {
);
}

function StopEditingAsBlocksOnOutsideSelect( { clientId } ) {
const {
__unstableStopEditingAsBlocks,
} = useDispatch( blockEditorStore );
const isBlockOrDescendantSelected = useSelect(
( select ) => {
const { isBlockSelected, hasSelectedInnerBlock } =
select( blockEditorStore );
return (
isBlockSelected( clientId ) ||
hasSelectedInnerBlock( clientId, true )
);
},
[ clientId ]
);
useEffect( () => {
if ( ! isBlockOrDescendantSelected ) {
__unstableStopEditingAsBlocks( clientId );
}
}, [ isBlockOrDescendantSelected, clientId, __unstableStopEditingAsBlocks ] );
return null;
}

export default function BlockList( settings ) {
return (
<BlockEditContextProvider value={ DEFAULT_BLOCK_EDIT_CONTEXT }>
Expand All @@ -128,17 +151,19 @@ function Items( {
__experimentalAppenderTagName,
layout = defaultLayout,
} ) {
const { order, selectedBlocks, visibleBlocks } = useSelect(
const { order, selectedBlocks, visibleBlocks, temporarilyEditingAsBlocks } = useSelect(
( select ) => {
const {
getBlockOrder,
getSelectedBlockClientIds,
__unstableGetVisibleBlocks,
__unstableGetTemporarilyEditingAsBlocks,
} = select( blockEditorStore );
return {
order: getBlockOrder( rootClientId ),
selectedBlocks: getSelectedBlockClientIds(),
visibleBlocks: __unstableGetVisibleBlocks(),
temporarilyEditingAsBlocks: __unstableGetTemporarilyEditingAsBlocks(),
};
},
[ rootClientId ]
Expand All @@ -163,6 +188,7 @@ function Items( {
</AsyncModeProvider>
) ) }
{ order.length < 1 && placeholder }
{ !! temporarilyEditingAsBlocks && <StopEditingAsBlocksOnOutsideSelect clientId={ temporarilyEditingAsBlocks } /> }
<BlockListAppender
tagName={ __experimentalAppenderTagName }
rootClientId={ rootClientId }
Expand Down
61 changes: 12 additions & 49 deletions packages/block-editor/src/hooks/content-lock-ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,22 @@
import { ToolbarButton, MenuItem } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { useEffect, useRef, useCallback } from '@wordpress/element';
import { useCallback } from '@wordpress/element';

/**
* Internal dependencies
*/
import { store as blockEditorStore } from '../store';
import { BlockControls, BlockSettingsMenuControls } from '../components';

function StopEditingAsBlocksOnOutsideSelect( {
clientId,
stopEditingAsBlock,
} ) {
const isBlockOrDescendantSelected = useSelect(
( select ) => {
const { isBlockSelected, hasSelectedInnerBlock } =
select( blockEditorStore );
return (
isBlockSelected( clientId ) ||
hasSelectedInnerBlock( clientId, true )
);
},
[ clientId ]
);
useEffect( () => {
if ( ! isBlockOrDescendantSelected ) {
stopEditingAsBlock();
}
}, [ isBlockOrDescendantSelected, stopEditingAsBlock ] );
return null;
}
// The implementation of content locking is mainly in this file, although the mechanism
// to stop temporarily editing as blocks when an outside block is selected is on component StopEditingAsBlocksOnOutsideSelect
// at block-editor/src/components/block-list/index.js.
// Besides the components on this file and the file referenced above the implementation
// also includes artifacts on the store (actions, reducers, and selector).

function ContentLockControlsPure( { clientId, isSelected } ) {
const { getBlockListSettings, getSettings } = useSelect( blockEditorStore );
const focusModeToRevert = useRef();
const { templateLock, isLockedByParent, isEditingAsBlocks } = useSelect(
( select ) => {
const {
Expand All @@ -59,6 +41,7 @@ function ContentLockControlsPure( { clientId, isSelected } ) {
const {
updateSettings,
updateBlockListSettings,
__unstableStopEditingAsBlocks,
__unstableSetTemporarilyEditingAsBlocks,
} = useDispatch( blockEditorStore );
const isContentLocked =
Expand All @@ -67,25 +50,8 @@ function ContentLockControlsPure( { clientId, isSelected } ) {
useDispatch( blockEditorStore );

const stopEditingAsBlock = useCallback( () => {
__unstableMarkNextChangeAsNotPersistent();
updateBlockAttributes( clientId, {
templateLock: 'contentOnly',
} );
updateBlockListSettings( clientId, {
...getBlockListSettings( clientId ),
templateLock: 'contentOnly',
} );
updateSettings( { focusMode: focusModeToRevert.current } );
__unstableSetTemporarilyEditingAsBlocks();
}, [
clientId,
updateSettings,
updateBlockListSettings,
getBlockListSettings,
__unstableMarkNextChangeAsNotPersistent,
updateBlockAttributes,
__unstableSetTemporarilyEditingAsBlocks,
] );
__unstableStopEditingAsBlocks( clientId );
}, [ clientId, __unstableStopEditingAsBlocks ] );

if ( ! isContentLocked && ! isEditingAsBlocks ) {
return null;
Expand All @@ -99,10 +65,6 @@ function ContentLockControlsPure( { clientId, isSelected } ) {
<>
{ showStopEditingAsBlocks && (
<>
<StopEditingAsBlocksOnOutsideSelect
clientId={ clientId }
stopEditingAsBlock={ stopEditingAsBlock }
/>
<BlockControls group="other">
<ToolbarButton
onClick={ () => {
Expand All @@ -127,11 +89,12 @@ function ContentLockControlsPure( { clientId, isSelected } ) {
...getBlockListSettings( clientId ),
templateLock: false,
} );
focusModeToRevert.current =
const focusModeToRevert =
getSettings().focusMode;
updateSettings( { focusMode: true } );
__unstableSetTemporarilyEditingAsBlocks(
clientId
clientId,
focusModeToRevert
);
onClose();
} }
Expand Down
31 changes: 30 additions & 1 deletion packages/block-editor/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -1686,13 +1686,42 @@ export function setBlockVisibility( updates ) {
* removed anytime without any warning, causing breakage on any plugin or theme invoking it.
*
* @param {?string} temporarilyEditingAsBlocks The block's clientId being temporaritly edited as blocks.
* @param {?string} focusModeToRevert The focus mode to revert after temporarily edit as blocks finishes.
*/
export function __unstableSetTemporarilyEditingAsBlocks(
temporarilyEditingAsBlocks
temporarilyEditingAsBlocks,
focusModeToRevert
) {
return {
type: 'SET_TEMPORARILY_EDITING_AS_BLOCKS',
temporarilyEditingAsBlocks,
focusModeToRevert,
};
}

/**
* Action that stops temporarily editing as blocks.
*
* DO-NOT-USE in production.
* This action is created for internal/experimental only usage and may be
* removed anytime without any warning, causing breakage on any plugin or theme invoking it.
*
* @param {string} clientId The block's clientId.
*/
export function __unstableStopEditingAsBlocks( clientId ) {
return ( { select, dispatch } ) => {
const focusModeToRevert =
select.__unstableGetTemporarilyEditingFocusModeToRevert();
dispatch.__unstableMarkNextChangeAsNotPersistent();
dispatch.updateBlockAttributes( clientId, {
templateLock: 'contentOnly',
} );
dispatch.updateBlockListSettings( clientId, {
...select.getBlockListSettings( clientId ),
templateLock: 'contentOnly',
} );
dispatch.updateSettings( { focusMode: focusModeToRevert } );
dispatch.__unstableSetTemporarilyEditingAsBlocks();
};
}

Expand Down
16 changes: 16 additions & 0 deletions packages/block-editor/src/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1906,6 +1906,21 @@ export function temporarilyEditingAsBlocks( state = '', action ) {
return state;
}

/**
* Reducer returning the focus mode that should be used when temporarily edit as blocks finishes.
*
* @param {Object} state Current state.
* @param {Object} action Dispatched action.
*
* @return {Object} Updated state.
*/
export function temporarilyEditingFocusModeRevert( state = '', action ) {
if ( action.type === 'SET_TEMPORARILY_EDITING_AS_BLOCKS' ) {
return action.focusModeToRevert;
}
return state;
}

/**
* Reducer returning a map of block client IDs to block editing modes.
*
Expand Down Expand Up @@ -2024,6 +2039,7 @@ const combinedReducers = combineReducers( {
highlightedBlock,
lastBlockInserted,
temporarilyEditingAsBlocks,
temporarilyEditingFocusModeRevert,
blockVisibility,
blockEditingModes,
styleOverrides,
Expand Down
11 changes: 11 additions & 0 deletions packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2767,6 +2767,17 @@ export function __unstableGetTemporarilyEditingAsBlocks( state ) {
return state.temporarilyEditingAsBlocks;
}

/**
* DO-NOT-USE in production.
* This selector is created for internal/experimental only usage and may be
* removed anytime without any warning, causing breakage on any plugin or theme invoking it.
*
* @param {Object} state Global application state.
*/
export function __unstableGetTemporarilyEditingFocusModeToRevert( state ) {
return state.temporarilyEditingFocusModeRevert;
}

export function __unstableHasActiveBlockOverlayActive( state, clientId ) {
// Prevent overlay on blocks with a non-default editing mode. If the mdoe is
// 'disabled' then the overlay is redundant since the block can't be
Expand Down

0 comments on commit 6883e1b

Please sign in to comment.