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
Original file line number Diff line number Diff line change
Expand Up @@ -229,16 +229,13 @@ function __experimentalBlockVariationTransforms( { blockClientId } ) {
( v ) => v.name !== 'stretchy-paragraph'
);
} else if ( blockName === 'core/heading' ) {
if (
activeBlockVariation?.name === 'stretchy-heading' ||
unfilteredVariations.every( ( v ) =>
[ 'heading', 'stretchy-heading' ].includes( v.name )
)
) {
// Hide variations picker when stretchy-heading is active.
if ( activeBlockVariation?.name === 'stretchy-heading' ) {
return [];
}
// Filter out stretchy-heading.
return unfilteredVariations.filter(
( v ) => v.name !== 'stretchy-heading'
( variation ) => variation.name !== 'stretchy-heading'
);
}
return unfilteredVariations;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
padding: 0 $grid-unit-20 $grid-unit-20 52px;

&:where(fieldset) {
// Reset `fieldset` browser defaults.
// Reset `fieldset` browser defaults, keeping intentional padding.
border: 0;
padding: 0;
margin: 0;
min-inline-size: 0;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,11 @@ export function BlockTypesTab(
continue;
}

// Skip search-only items from browse view (they're still searchable).
if ( item.isSearchOnly ) {
continue;
}

if ( item.isAllowedInCurrentRoot ) {
itemsForCurrentRoot.push( item );
} else {
Expand Down
25 changes: 24 additions & 1 deletion packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2078,6 +2078,8 @@ const getItemFromVariation = ( state, item ) => ( variation ) => {
innerBlocks: variation.innerBlocks,
keywords: variation.keywords || item.keywords,
frecency: calculateFrecency( time, count ),
// Pass through search-only flag for block-scope variations.
isSearchOnly: variation.isSearchOnly,
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a new flag right? I'm a little bit hesitant about it.

I mean "scope" have been used in variations to define where a variation should appear. And by adding this flag we now have two properties to define that. I may have a small preference for another "search" scope.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is not being set by the consumer, it's just an internal flag to explicitly treat "block" context to show up in search. I implemented the search scope initially but it seemed unnecessary and confusing, since you'd think you need to pass the extra search scope to ensure something shows up on searches, but "inserter" already handles that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah ok, maybe we can just pass down the scope or something no?

Copy link
Contributor

Choose a reason for hiding this comment

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

Regardless, I'm way less concerned now :)

};
};

Expand Down Expand Up @@ -2151,6 +2153,27 @@ const buildBlockTypeItem =
blockType.name,
'inserter'
);
const blockVariations = getBlockVariations( blockType.name, 'block' );
// Combine inserter and block variations. Block-scope variations without
// inserter scope are searchable via slash commands but hidden from browse.
const inserterVariationNames = new Set(
inserterVariations.map( ( variation ) => variation.name )
);
const allVariations = [
...inserterVariations,
...blockVariations
.filter(
( variation ) =>
! inserterVariationNames.has( variation.name )
)
.map( ( variation ) => ( {
...variation,
isSearchOnly: true,
// Block-scope `isDefault` is for the placeholder picker,
// not for the inserter, so don't carry it over.
isDefault: false,
} ) ),
];
return {
...blockItemBase,
initialAttributes: {},
Expand All @@ -2159,7 +2182,7 @@ const buildBlockTypeItem =
keywords: blockType.keywords,
parent: blockType.parent,
ancestor: blockType.ancestor,
variations: inserterVariations,
variations: allVariations,
example: blockType.example,
utility: 1, // Deprecated.
};
Expand Down
11 changes: 1 addition & 10 deletions packages/block-library/src/heading/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
RichText,
useBlockProps,
store as blockEditorStore,
HeadingLevelDropdown,
useBlockEditingMode,
} from '@wordpress/block-editor';

Expand All @@ -32,8 +31,7 @@ function HeadingEdit( {
style,
clientId,
} ) {
const { textAlign, content, level, levelOptions, placeholder, anchor } =
attributes;
const { textAlign, content, level, placeholder, anchor } = attributes;
const tagName = 'h' + level;
const blockProps = useBlockProps( {
className: clsx( {
Expand Down Expand Up @@ -94,13 +92,6 @@ function HeadingEdit( {
<>
{ blockEditingMode === 'default' && (
<BlockControls group="block">
<HeadingLevelDropdown
value={ level }
options={ levelOptions }
onChange={ ( newLevel ) =>
setAttributes( { level: newLevel } )
}
/>
<AlignmentControl
value={ textAlign }
onChange={ ( nextAlign ) => {
Expand Down
25 changes: 23 additions & 2 deletions packages/block-library/src/heading/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
*/
import { heading as icon } from '@wordpress/icons';
import { __, sprintf } from '@wordpress/i18n';
import { privateApis as blocksPrivateApis } from '@wordpress/blocks';
import {
privateApis as blocksPrivateApis,
getBlockType,
unregisterBlockVariation,
} from '@wordpress/blocks';

/**
* Internal dependencies
Expand Down Expand Up @@ -86,4 +90,21 @@ if ( window.__experimentalContentOnlyInspectorFields ) {
};
}

export const init = () => initBlock( { name, metadata, settings } );
export const init = () => {
const block = initBlock( { name, metadata, settings } );

// Unregister heading level variations based on `levelOptions` attribute.
// This is for backwards compatibility, as extenders can now unregister the
// variation directly: `wp.blocks.unregisterBlockVariation( 'core/heading', 'h1' )`.
const levelOptions =
getBlockType( name )?.attributes?.levelOptions?.default;
if ( levelOptions ) {
[ 1, 2, 3, 4, 5, 6 ].forEach( ( level ) => {
if ( ! levelOptions.includes( level ) ) {
unregisterBlockVariation( name, `h${ level }` );
}
} );
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This works and I think it's totally fine for now but:

changing a "default" attribute value to define what levels are available seems like a bad thing to start with. I wonder if we should deprecate that attribute. Unregistering a variation seems like a way better approach.

Copy link
Member

Choose a reason for hiding this comment

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

That would break sites that rely on the default options attribute to remove the heading levels.

I think @fabiankaegy is also suggesting keeping the toolbar dropdown item - #73823 (comment).

Copy link
Contributor

Choose a reason for hiding this comment

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

This is why I said "deprecate" and not "remove" :)

Copy link
Contributor

Choose a reason for hiding this comment

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

That said, reading @fabiankaegy's comment I do agree that at a "pattern" level it's a good idea to allow disabling level options and things like that.


return block;
};
42 changes: 32 additions & 10 deletions packages/block-library/src/heading/variations.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,44 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { __, sprintf } from '@wordpress/i18n';
import { Path, SVG } from '@wordpress/primitives';
import { heading } from '@wordpress/icons';
import {
headingLevel1,
headingLevel2,
headingLevel3,
headingLevel4,
headingLevel5,
headingLevel6,
} from '@wordpress/icons';

const LEVEL_ICONS = [
headingLevel1,
headingLevel2,
headingLevel3,
headingLevel4,
headingLevel5,
headingLevel6,
];

const variations = [
{
name: 'heading',
title: __( 'Heading' ),
...[ 1, 2, 3, 4, 5, 6 ].map( ( level ) => ( {
name: `h${ level }`,
title: sprintf(
/* translators: %d: heading level e.g: "1", "2", "3" */
__( 'Heading %d' ),
level
),
description: __(
'Introduce new sections and organize content to help visitors (and search engines) understand the structure of your content.'
),
isDefault: true,
scope: [ 'inserter', 'transform' ],
attributes: { fitText: undefined },
icon: heading,
},
icon: LEVEL_ICONS[ level - 1 ],
attributes: { level },
scope: [ 'block', 'transform' ],
keywords: [ `h${ level }` ],
isActive: ( blockAttributes ) =>
! blockAttributes.fitText && blockAttributes.level === level,
} ) ),
// There is a hardcoded workaround in packages/block-editor/src/store/selectors.js
// to make Stretchy variations appear as the last of their sections in the inserter.
{
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/specs/editor/blocks/heading.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -365,8 +365,8 @@ test.describe( 'Heading', () => {

await expect(
headingListViewItem,
'should show default block name if the content is empty'
).toHaveText( 'Heading' );
'should show variation name if the content is empty'
).toHaveText( 'Heading 2' );

await editor.canvas
.getByRole( 'document', {
Expand Down
4 changes: 3 additions & 1 deletion test/e2e/specs/editor/plugins/block-variations.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ test.describe( 'Block variations', () => {
.locator( 'role=button[name="Add default block"i]' )
.click();
await page.keyboard.type( '/Columns' );
await page.getByRole( 'option', { name: 'Columns' } ).click();
await page
.getByRole( 'option', { name: 'Columns', exact: true } )
.click();

await editor.canvas
.getByRole( 'list', { name: 'Block variations' } )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -566,13 +566,11 @@ test.describe( 'Autocomplete (@firefox, @webkit)', () => {

await page.keyboard.type( 'heading' );
await expect(
page.locator( `role=option[name="Heading"i]` )
page.getByRole( 'option', { name: 'Heading', exact: true } )
).toBeVisible();
// Get the assertive live region screen reader announcement.
await expect(
page.getByText(
'3 results found, use up and down arrow keys to navigate.'
)
page.getByText( 'use up and down arrow keys to navigate.' )
).toBeVisible();
} );
} );
2 changes: 1 addition & 1 deletion test/e2e/specs/editor/various/content-only-lock.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ test.describe( 'Content-only lock', () => {
await editor.clickBlockOptionsMenuItem( 'Delete' );
// Select an outside block
await editor.canvas
.locator( 'role=document[name="Block: Heading"i]' )
.locator( 'role=document[name="Block: Heading 2"i]' )
.click();
// Select a locked nested paragraph block again
await pageUtils.pressKeys( 'ArrowUp' );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ test.describe( 'Keep styles on block transforms', () => {
await page.click( 'role=button[name="Text"i]' );
await page.click( 'role=option[name="Luminous vivid orange"i]' );

await page.click( 'role=button[name="Heading"i]' );
await page
.getByRole( 'toolbar', { name: 'Block tools' } )
.getByRole( 'button', { name: 'Heading 2' } )
.click();
await page.click( 'role=menuitem[name="Paragraph"i]' );

await expect.poll( editor.getBlocks ).toMatchObject( [
Expand Down
6 changes: 3 additions & 3 deletions test/e2e/specs/editor/various/list-view.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ test.describe( 'List View', () => {
exact: true,
} );
const headingBlockItem = listView.getByRole( 'gridcell', {
name: 'Heading',
name: 'Heading 2',
exact: true,
} );

Expand Down Expand Up @@ -1090,7 +1090,7 @@ test.describe( 'List View', () => {
await page.keyboard.press( 'ArrowRight' );
// Move focus and select the Heading block.
await listView
.getByRole( 'gridcell', { name: 'Heading', exact: true } )
.getByRole( 'gridcell', { name: 'Heading 2', exact: true } )
.dblclick();
// Select both inner blocks in the column.
await page.keyboard.press( 'Shift+ArrowDown' );
Expand Down Expand Up @@ -1188,7 +1188,7 @@ test.describe( 'List View', () => {
} );
// Click on the Heading block to select it.
await listView
.getByRole( 'gridcell', { name: 'Heading', exact: true } )
.getByRole( 'gridcell', { name: 'Heading 2', exact: true } )
.click();
await listView
.getByRole( 'gridcell', { name: 'File' } )
Expand Down
8 changes: 6 additions & 2 deletions test/e2e/specs/editor/various/rich-text.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ test.describe( 'RichText (@firefox, @webkit)', () => {
//
// See: https://github.com/WordPress/gutenberg/issues/3091
await editor.insertBlock( { name: 'core/heading' } );
await editor.clickBlockToolbarButton( 'Change level' );
await page.locator( 'role=menuitemradio[name="Heading 3"]' ).click();

// Open the block inspector sidebar and use variations to change level.
await editor.openDocumentSettingsSidebar();
await page
.getByRole( 'button', { name: 'Heading 3', exact: true } )
.click();

expect( await editor.getBlocks() ).toMatchObject( [
{
Expand Down
12 changes: 7 additions & 5 deletions test/e2e/specs/editor/various/toolbar-roving-tabindex.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,15 @@ test.describe( 'Toolbar roving tabindex', () => {
await editor.insertBlock( { name: 'core/heading' } );
await page.keyboard.type( 'Heading' );
await ToolbarRovingTabindexUtils.testBlockToolbarKeyboardNavigation(
'Block: Heading',
'Heading'
'Block: Heading 2',
'Heading 2'
);
await ToolbarRovingTabindexUtils.wrapCurrentBlockWithGroup(
'Heading 2'
);
await ToolbarRovingTabindexUtils.wrapCurrentBlockWithGroup( 'Heading' );
await ToolbarRovingTabindexUtils.testGroupKeyboardNavigation(
'Block: Heading',
'Heading'
'Block: Heading 2',
'Heading 2'
);

// ensures list block toolbar uses roving tabindex
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/specs/widgets/customizing-widgets.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ test.describe( 'Widgets Customizer', () => {
await editHeadingWidget.click();

const headingBlock = page.locator(
'role=document[name="Block: Heading"i] >> text="First Heading"'
'role=document[name="Block: Heading 2"i] >> text="First Heading"'
);
await expect( headingBlock ).toBeFocused();
} );
Expand Down
Loading