Skip to content
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
1 change: 1 addition & 0 deletions packages/block-editor/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
- `InnerBlocks`: Resolve a container's legacy layout markup (`inherit: true`, or a bare `contentSize` / `wideSize` with no `type`) to a constrained layout for its inner blocks, so they are offered the wide and full alignments. Previously only the container's styles honoured the legacy form, and the inner blocks resolved to the flow layout ([#82637](https://github.com/WordPress/gutenberg/pull/82637)).
- Block Patterns, Block Visibility, and Block Lock: Preserve the intended colors of icons converted to strokes. ([#82540](https://github.com/WordPress/gutenberg/pull/82540), [#82754](https://github.com/WordPress/gutenberg/pull/82754))
- Layout: Treat a missing `spacing.blockGap` setting as no block gap support, as the server does. A theme that does not opt into block gap has the setting stored as `null`, which the block settings resolve to `undefined`, so per-block layout styles applied block gap values the front end never renders. An editor that never provides the setting must set it to `true` to keep rendering block gap values ([#82401](https://github.com/WordPress/gutenberg/pull/82401)).
- Block Toolbar: Show the parent block selector for blocks inside patterns and `contentOnly` locked blocks. It selects the nearest parent shown in List View and the breadcrumb ([#82912](https://github.com/WordPress/gutenberg/pull/82912)).

### Internal

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export default function BlockParentSelector() {
getBlockParents,
getSelectedBlockClientIds,
getParentSectionBlock,
getEnabledBlockParents,
getBlockName,
getNextBlockClientId,
} = unlock( select( blockEditorStore ) );
Expand All @@ -37,7 +38,12 @@ export default function BlockParentSelector() {
);
const parents = getBlockParents( selectedBlockClientId );
const immediateParentClientId = parents[ parents.length - 1 ];
const _parentClientId = parentSection ?? immediateParentClientId;
// The parent is the nearest one shown in List View and the
// breadcrumb, skipping any disabled blocks in between.
const _parentClientId = getEnabledBlockParents(
selectedBlockClientId,
true
)[ 0 ];
const parentBlockType = getBlockType(
getBlockName( _parentClientId )
);
Expand All @@ -53,12 +59,12 @@ export default function BlockParentSelector() {
nextSiblingClientId: getNextBlockClientId(
selectedBlockClientId
),
// When the shown parent is a section further up the tree
// rather than the direct parent, its content is locked and
// nothing can be inserted, so no button.
// No button when the parent shown is not the direct parent, nor
// within a section, where the structure is locked.
showInserter:
!! _parentClientId &&
_parentClientId === immediateParentClientId &&
! parentSection &&
! isTextFlowWrapper,
};
},
Expand Down
12 changes: 8 additions & 4 deletions packages/block-editor/src/components/block-toolbar/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,14 @@ export function PrivateBlockToolbar( {
const {
getBlockName,
getBlockMode,
getBlockParents,
getSelectedBlockClientIds,
isBlockValid,
getBlockEditingMode,
getBlockAttributes,
getSettings,
getTemplateLock,
getParentSectionBlock,
getEnabledBlockParents,
isZoomOut,
isSectionBlock,
isBlockHiddenAtViewport,
Expand All @@ -91,9 +91,13 @@ export function PrivateBlockToolbar( {
} = unlock( select( blockEditorStore ) );
const selectedBlockClientIds = getSelectedBlockClientIds();
const selectedBlockClientId = selectedBlockClientIds[ 0 ];
const parents = getBlockParents( selectedBlockClientId );
const parentSection = getParentSectionBlock( selectedBlockClientId );
const parentClientId = parentSection ?? parents[ parents.length - 1 ];
// The parent is the nearest one shown in List View and the breadcrumb,
// skipping any disabled blocks in between.
const parentClientId = getEnabledBlockParents(
selectedBlockClientId,
true
)[ 0 ];
const parentBlockName = getBlockName( parentClientId );
const parentBlockType = getBlockType( parentBlockName );
const editingMode = getBlockEditingMode( selectedBlockClientId );
Expand Down Expand Up @@ -144,7 +148,7 @@ export function PrivateBlockToolbar( {
showParentSelector:
! _isZoomOut &&
parentBlockType &&
editingMode !== 'contentOnly' &&
( editingMode !== 'contentOnly' || !! parentSection ) &&
getBlockEditingMode( parentClientId ) !== 'disabled' &&
hasBlockSupport(
parentBlockType,
Expand Down
58 changes: 58 additions & 0 deletions test/e2e/specs/editor/various/content-only-lock.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,64 @@ test.describe( 'Content-only lock', () => {
} );
} );

test( 'the parent block selector selects the nearest parent shown in List View', async ( {
editor,
page,
pageUtils,
} ) => {
await pageUtils.pressKeys( 'secondary+M' );

await page.getByPlaceholder( 'Start writing with text or HTML' )
.fill( `<!-- wp:group {"templateLock":"contentOnly","layout":{"type":"constrained"}} -->
<div class="wp-block-group"><!-- wp:group {"layout":{"type":"constrained"}} -->
<div class="wp-block-group"><!-- wp:buttons -->
<div class="wp-block-buttons"><!-- wp:button -->
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button">Learn more</a></div>
<!-- /wp:button --></div>
<!-- /wp:buttons --></div>
<!-- /wp:group --></div>
<!-- /wp:group -->` );

await pageUtils.pressKeys( 'secondary+M' );

const groupBlock = editor.canvas
.getByRole( 'document', { name: 'Block: Group' } )
.first();
const buttonsBlock = editor.canvas.getByRole( 'document', {
name: 'Block: Buttons',
includeHidden: true,
} );
const buttonBlock = editor.canvas.getByRole( 'document', {
name: 'Block: Button',
exact: true,
includeHidden: true,
} );

// Select the content-locked group block.
await editor.selectBlocks( groupBlock );

await editor.selectBlocks( buttonBlock );
await editor.showBlockToolbar();

const blockToolbar = page.getByRole( 'toolbar', {
name: 'Block tools',
} );
// The nested group is disabled, so the parent is the Buttons block.
const parentSelector = blockToolbar.getByRole( 'button', {
name: 'Select parent block: Buttons',
} );
await expect( parentSelector ).toBeVisible();
await expect(
blockToolbar.locator(
'.block-editor-block-parent-selector__inserter'
)
).toHaveCount( 0 );

await parentSelector.click();

await expect( buttonsBlock ).toHaveClass( /is-selected/ );
} );

test( 'pressing Enter on a non-text block in a contentOnly section should not insert a paragraph', async ( {
editor,
page,
Expand Down
42 changes: 42 additions & 0 deletions test/e2e/specs/editor/various/pattern-overrides.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,48 @@ test.describe( 'Pattern Overrides', () => {
} );
} );

test( 'the parent block selector of a block with overrides selects the pattern', async ( {
admin,
editor,
page,
requestUtils,
} ) => {
const { id } = await requestUtils.createBlock( {
title: 'Test Pattern',
content: `<!-- wp:paragraph {"metadata":{"name":"Editable Paragraph","bindings":{"__default":{"source":"core/pattern-overrides"}}}} -->
<p>Editable paragraph</p>
<!-- /wp:paragraph -->`,
status: 'publish',
} );

await admin.createNewPost();

await editor.insertBlock( {
name: 'core/block',
attributes: { ref: id },
} );

const patternBlock = editor.canvas.getByRole( 'document', {
name: 'Block: Pattern',
} );
const paragraph = editor.canvas.getByRole( 'document', {
name: 'Block: Paragraph',
includeHidden: true,
} );

await editor.selectBlocks( paragraph );
await editor.showBlockToolbar();

const parentSelector = page
.getByRole( 'toolbar', { name: 'Block tools' } )
.getByRole( 'button', { name: 'Select parent block' } );
await expect( parentSelector ).toBeVisible();

await parentSelector.click();

await expect( patternBlock ).toHaveClass( /is-selected/ );
} );

test.describe( 'block editing modes', () => {
test( 'blocks with bindings in a synced pattern are editable, and all other blocks are disabled', async ( {
admin,
Expand Down
Loading