Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
d046d05
In-editor revisions (initial changes, without diffing)
ellatrix Jan 20, 2026
0e3292e
Remove diff related stuff
ellatrix Jan 20, 2026
1629a01
minimise diff
ellatrix Jan 20, 2026
2f05405
Reduce store state
ellatrix Jan 20, 2026
9f60765
reorg
ellatrix Jan 20, 2026
9c8631e
Header skeleton
ellatrix Jan 20, 2026
3ecd4d5
restore comment
ellatrix Jan 20, 2026
8354457
restore comment
ellatrix Jan 20, 2026
5808464
Fix slider tooltip
ellatrix Jan 20, 2026
7a9d9d1
Delete custom sidebar
ellatrix Jan 20, 2026
9bfdcdd
Fix canvas selector
ellatrix Jan 20, 2026
2e97e42
disable actions
ellatrix Jan 20, 2026
052b77c
min diff
ellatrix Jan 20, 2026
c564c90
Fix restore and some errors
ellatrix Jan 20, 2026
7f29dd0
Fix footnotes e2e test
ellatrix Jan 20, 2026
b74d096
Return no slider for only one revision
ellatrix Jan 21, 2026
11439e3
Use getRevisions to avoid selector quirks
ellatrix Jan 21, 2026
f763d80
Reverse order
ellatrix Jan 21, 2026
1c1bc1d
Add author
ellatrix Jan 21, 2026
5e11c83
Disable more menu for now
ellatrix Jan 21, 2026
2470e93
Remove block styles
ellatrix Jan 21, 2026
c2faf77
Remove eye button
ellatrix Jan 21, 2026
b657574
Remove block tab for now
ellatrix Jan 21, 2026
071eb49
Pad empty rich text
ellatrix Jan 22, 2026
b912e87
Disable in-between inserter
ellatrix Jan 22, 2026
733b8cd
Pad only in editor
ellatrix Jan 22, 2026
cd32037
Address feedback, let's see if native tests pass with the rich text c…
ellatrix Jan 22, 2026
19a72dd
Fix navigation revisions
ellatrix Jan 22, 2026
0dc940f
Disable block contents, keep blocks focusable
ellatrix Jan 22, 2026
988e0c1
Fix arrow nav in preview
ellatrix Jan 22, 2026
06baf88
combine
ellatrix Jan 22, 2026
70543b9
Fix multi selection
ellatrix Jan 22, 2026
451b48a
nav fix
ellatrix Jan 22, 2026
5b81953
Provide blockEditingMode in preview mode
ellatrix Jan 22, 2026
ee88a60
Disable locking
ellatrix Jan 26, 2026
5261b01
Remove remnant
ellatrix Jan 27, 2026
b75955a
Add basic e2e test
ellatrix Jan 27, 2026
69b1585
restore post-last-edited-panel
ellatrix Jan 27, 2026
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
7 changes: 5 additions & 2 deletions packages/block-editor/src/components/block-list/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,8 @@ function BlockListBlockProvider( props ) {
settings?.[ deviceTypeKey ]?.toLowerCase() || 'desktop';

const hasLightBlockWrapper = blockType?.apiVersion > 1;
const isMultiSelected = isBlockMultiSelected( clientId );
const blockEditingMode = getBlockEditingMode( clientId );
const previewContext = {
isPreviewMode,
blockWithoutAttributes,
Expand All @@ -643,6 +645,9 @@ function BlockListBlockProvider( props ) {
bindableAttributes,
blockVisibility,
deviceType,
isMultiSelected,
blockEditingMode,
isEditingDisabled: blockEditingMode === 'disabled',
};

// When in preview mode, we can avoid a lot of selection and
Expand All @@ -654,13 +659,11 @@ function BlockListBlockProvider( props ) {
const canRemove = canRemoveBlock( clientId );
const canMove = canMoveBlock( clientId );
const match = getActiveBlockVariation( blockName, attributes );
const isMultiSelected = isBlockMultiSelected( clientId );
const checkDeep = true;
const isAncestorOfSelectedBlock = hasSelectedInnerBlock(
clientId,
checkDeep
);
const blockEditingMode = getBlockEditingMode( clientId );
const sectionBlockClientId = _isSectionBlock( clientId )
? clientId
: getParentSectionBlock( clientId );
Expand Down
11 changes: 11 additions & 0 deletions packages/block-editor/src/components/block-list/content.scss
Original file line number Diff line number Diff line change
Expand Up @@ -476,3 +476,14 @@ _::-webkit-full-page-media, _:future, :root [data-has-multi-selection="true"] .b
cursor: grabbing;
}

.is-preview-mode {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we avoid a global style like that, also why can't we use the useDisabled that we already have in useBlockProps instead of adding yet a new behavior/hook/mode?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

useDisabled adds inert to all child elements, so that doesn't work. What do you want instead of a style like this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I see I think we should at least target a specific class of an element and not a generic modifier class like this which could impact a lot of things.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The reason I also don't like class and CSS to solve this is also because there's a huge chance for conflicts with other things. For instance, would this risk "enable" interactions on content-only patterns (or patterns in general when the experiment is on). Instead it feels the logic being tied together in useBlockProps with the block editing... feels safer.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I don't really follow. How could it interact with content-only? The preview mode is a global thing, not really per-block. I don't really understand what I'd have to add to useBlockProps, there's no related prop at the block level. Even if there was, we'd still need separate CSS to disable pointer-events on child elements within.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I didn't test but:

  • Patterns (with simple editing on) disable interactions on non "content" blocks (think groups, columns...) within the parent.
  • the global preview mode enables "mouse pointers" on these intermediary blocks.

These two things can conflict with each other depending on how they are implemented. Also, patterns is potentially not the only think that disable selection on blocks, we need to check all of them, block locking might be another one, block editing mode is another one.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Exactly, they are two different things. One disables everything inside block, the other disables entire blocks. It doesn't seem possible to reuse logic there.

There was actually an issue with content-only not enabling for revisions, but it was because the selector data was not present. Fixed in 4c4b009. This just selects data from an object so I'm not worried about performance.

Yes, preview mode enables pointer events, but lower specificity than content only. I can make it even lower if you want by wrapping it in :where()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we at least make this more specific like:

.block-editor-block-list__block.is-root-container.is-preview-mode

pointer-events: none;

.block-editor-block-list__block {
pointer-events: auto;

> *:not(.block-editor-block-list__block) {
pointer-events: none;
}
}
}
42 changes: 25 additions & 17 deletions packages/block-editor/src/components/block-list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,23 +48,30 @@ const delayedBlockVisibilityDebounceOptions = {
};

function Root( { className, ...settings } ) {
const { isOutlineMode, isFocusMode, editedContentOnlySection } = useSelect(
( select ) => {
const {
getSettings,
isTyping,
hasBlockSpotlight,
getEditedContentOnlySection,
} = unlock( select( blockEditorStore ) );
const { outlineMode, focusMode } = getSettings();
return {
isOutlineMode: outlineMode && ! isTyping(),
isFocusMode: focusMode || hasBlockSpotlight(),
editedContentOnlySection: getEditedContentOnlySection(),
};
},
[]
);
const {
isOutlineMode,
isFocusMode,
isPreviewMode,
editedContentOnlySection,
} = useSelect( ( select ) => {
const {
getSettings,
isTyping,
hasBlockSpotlight,
getEditedContentOnlySection,
} = unlock( select( blockEditorStore ) );
const {
outlineMode,
focusMode,
isPreviewMode: _isPreviewMode,
} = getSettings();
return {
isOutlineMode: outlineMode && ! isTyping(),
isFocusMode: focusMode || hasBlockSpotlight(),
isPreviewMode: _isPreviewMode,
editedContentOnlySection: getEditedContentOnlySection(),
};
}, [] );
const registry = useRegistry();
const { setBlockVisibility } = useDispatch( blockEditorStore );

Expand Down Expand Up @@ -111,6 +118,7 @@ function Root( { className, ...settings } ) {
className: clsx( 'is-root-container', className, {
'is-outline-mode': isOutlineMode,
'is-focus-mode': isFocusMode,
'is-preview-mode': isPreviewMode,
} ),
},
settings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ import { unlock } from '../../lock-unlock';

export function useInBetweenInserter() {
const openRef = useContext( InsertionPointOpenRef );
const isInBetweenInserterDisabled = useSelect(
( select ) =>
select( blockEditorStore ).getSettings().isDistractionFree ||
unlock( select( blockEditorStore ) ).isZoomOut(),
[]
);
const isInBetweenInserterDisabled = useSelect( ( select ) => {
const settings = select( blockEditorStore ).getSettings();
return (
settings.isDistractionFree ||
settings.isPreviewMode ||
unlock( select( blockEditorStore ) ).isZoomOut()
);
}, [] );
const {
getBlockListSettings,
getBlockIndex,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ const BlockSettingsMenuControlsSlot = ( { fillProps, clientIds = null } ) => {
selectedClientIds,
isContentOnly,
canToggleSelectedBlocksVisibility,
canEdit,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you clarify why these canEdit changes are needed? Any performance concerns?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We should not render action buttons for actions that cannot be performed. It's actually good to have a look a these, for example in the next file you'll see that the Cut action was missing canRemove. I don't see any performance concern since this is mounted in a dropdown.

} = useSelect(
( select ) => {
const {
getBlocksByClientId,
getBlockNamesByClientId,
getSelectedBlockClientIds,
getBlockEditingMode,
canEditBlock,
} = select( blockEditorStore );
const ids =
clientIds !== null ? clientIds : getSelectedBlockClientIds();
Expand All @@ -52,6 +54,7 @@ const BlockSettingsMenuControlsSlot = ( { fillProps, clientIds = null } ) => {
).every( ( block ) =>
hasBlockSupport( block.name, 'visibility', true )
),
canEdit: canEditBlock( ids[ 0 ] ),
};
},
[ clientIds ]
Expand Down Expand Up @@ -105,17 +108,17 @@ const BlockSettingsMenuControlsSlot = ( { fillProps, clientIds = null } ) => {
onClose={ fillProps?.onClose }
/>
) }
{ showLockButton && (
{ canEdit && showLockButton && (
<BlockLockMenuItem
clientId={ selectedClientIds[ 0 ] }
/>
) }
{ showRenameButton && (
{ canEdit && showRenameButton && (
<BlockRenameControl
clientId={ selectedClientIds[ 0 ] }
/>
) }
{ showVisibilityButton && (
{ canEdit && showVisibilityButton && (
<BlockVisibilityViewportMenuItem
clientIds={ selectedClientIds }
/>
Expand All @@ -127,12 +130,14 @@ const BlockSettingsMenuControlsSlot = ( { fillProps, clientIds = null } ) => {
onClose={ fillProps?.onClose }
/>
) }
{ fillProps?.count === 1 && ! isContentOnly && (
<BlockModeToggle
clientId={ fillProps?.firstBlockClientId }
onToggle={ fillProps?.onClose }
/>
) }
{ canEdit &&
fillProps?.count === 1 &&
! isContentOnly && (
<BlockModeToggle
clientId={ fillProps?.firstBlockClientId }
onToggle={ fillProps?.onClose }
/>
) }
</MenuGroup>
);
} }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export function BlockSettingsDropdown( {
selectedBlockClientIds,
isContentOnly,
isZoomOut,
canEdit,
} = useSelect(
( select ) => {
const {
Expand All @@ -97,6 +98,7 @@ export function BlockSettingsDropdown( {
getBlockAttributes,
getBlockEditingMode,
isZoomOut: _isZoomOut,
canEditBlock,
} = unlock( select( blockEditorStore ) );

const { getActiveBlockVariation } = select( blocksStore );
Expand All @@ -121,6 +123,7 @@ export function BlockSettingsDropdown( {
isContentOnly:
getBlockEditingMode( firstBlockClientId ) === 'contentOnly',
isZoomOut: _isZoomOut(),
canEdit: canEditBlock( firstBlockClientId ),
};
},
[ firstBlockClientId ]
Expand Down Expand Up @@ -240,7 +243,7 @@ export function BlockSettingsDropdown( {
parentBlockType={ parentBlockType }
/>
) }
{ count === 1 && (
{ canEdit && count === 1 && (
<BlockHTMLConvertButton
clientId={ firstBlockClientId }
/>
Expand All @@ -252,7 +255,7 @@ export function BlockSettingsDropdown( {
shortcut={ shortcuts.copy }
/>
) }
{ ! isContentOnly && (
{ canRemove && ! isContentOnly && (
<CopyMenuItem
clientIds={ clientIds }
label={ __( 'Cut' ) }
Expand Down Expand Up @@ -301,7 +304,7 @@ export function BlockSettingsDropdown( {
</MenuItem>
</>
) }
{ count === 1 && (
{ canEdit && count === 1 && (
<CommentIconSlotFill.Slot
fillProps={ {
clientId: firstBlockClientId,
Expand All @@ -318,9 +321,11 @@ export function BlockSettingsDropdown( {
label={ __( 'Copy styles' ) }
eventType="copyStyles"
/>
<MenuItem onClick={ onPasteStyles }>
{ __( 'Paste styles' ) }
</MenuItem>
{ canEdit && (
<MenuItem onClick={ onPasteStyles }>
{ __( 'Paste styles' ) }
</MenuItem>
) }
</MenuGroup>
) }
{ ! isContentOnly && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ function getBlockIconVariant( { select, clientIds } ) {
canRemoveBlocks,
getTemplateLock,
getBlockEditingMode,
canEditBlock,
} = unlock( select( blockEditorStore ) );
const { getBlockStyles } = select( blocksStore );

Expand All @@ -53,7 +54,7 @@ function getBlockIconVariant( { select, clientIds } ) {
0
);
const canRemove = canRemoveBlocks( clientIds );

const canEdit = clientIds.every( ( clientId ) => canEditBlock( clientId ) );
const isDefaultEditingMode =
getBlockEditingMode( clientIds[ 0 ] ) === 'default';
const _hideTransformsForSections =
Expand All @@ -63,7 +64,8 @@ function getBlockIconVariant( { select, clientIds } ) {
! _hideTransformsForSections &&
isDefaultEditingMode &&
( hasBlockStyles || canRemove ) &&
! hasTemplateLock;
! hasTemplateLock &&
canEdit;

const _showPatternOverrides = hasPatternOverrides && hasParentPattern;

Expand Down
2 changes: 1 addition & 1 deletion packages/block-editor/src/components/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ const PublicForwardedRichTextContainer = forwardRef( ( props, ref ) => {
ref={ ref }
{ ...contentProps }
dangerouslySetInnerHTML={ {
__html: valueToHTMLString( value, multiline ),
__html: valueToHTMLString( value, multiline ) || '<br>',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What is this about?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We have to pad empty rich text elements such as paragraphs (just like we do for the editable version), otherwise they collapse.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This change seems low level though, won't this have impact on RichText usage outside revision mode. Just want to make sure it doesn't create regressions for folks using RichText in contexts we might not have thought about.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Previews have always been the editor, but with some performance improvements. Omitting the BR padding was an oversight.

} }
/>
);
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 @@ -17,6 +17,7 @@ import { forwardRef } from '@wordpress/element';
import useMultiSelection from './use-multi-selection';
import useTabNav from './use-tab-nav';
import useArrowNav from './use-arrow-nav';
import { usePreviewModeNav } from './use-preview-mode-nav';
import useSelectAll from './use-select-all';
import useDragSelection from './use-drag-selection';
import useSelectionObserver from './use-selection-observer';
Expand Down Expand Up @@ -44,6 +45,7 @@ export function useWritingFlow() {
useMultiSelection(),
useSelectAll(),
useArrowNav(),
usePreviewModeNav(),
useRefEffect(
( node ) => {
node.tabIndex = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ export default function useArrowNav() {
return;
}

// In preview mode, navigation is handled by useSelectableBlocksNav.
if ( getSettings().isPreviewMode ) {
return;
}

// If there is a multi-selection, the arrow keys should collapse the
// selection to the start or end of the selection.
if ( hasMultiSelection() ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default function useDragSelection() {
const { startMultiSelect, stopMultiSelect } =
useDispatch( blockEditorStore );
const {
getSettings,
isSelectionEnabled,
hasSelectedBlock,
isDraggingBlocks,
Expand Down Expand Up @@ -123,7 +124,12 @@ export default function useDragSelection() {
// child elements of the content editable wrapper are editable
// and return true for this property. We only want to start
// multi selecting when the mouse leaves the wrapper.
if ( target.getAttribute( 'contenteditable' ) !== 'true' ) {
// In preview mode, allow drag selection from blocks since they
// are not contenteditable.
if (
target.getAttribute( 'contenteditable' ) !== 'true' &&
! getSettings().isPreviewMode
) {
return;
}

Expand Down
Loading
Loading