diff --git a/lib/experimental/block-editor-settings-mobile.php b/lib/experimental/block-editor-settings-mobile.php
index 4319f8766352c..b0da17e929667 100644
--- a/lib/experimental/block-editor-settings-mobile.php
+++ b/lib/experimental/block-editor-settings-mobile.php
@@ -29,8 +29,8 @@ function gutenberg_get_block_editor_settings_mobile( $settings ) {
// To tell mobile that the site uses quote v2 (inner blocks).
// See https://github.com/WordPress/gutenberg/pull/25892.
$settings['__experimentalEnableQuoteBlockV2'] = true;
- // To be set to true when the web makes quote v2 (inner blocks) the default.
- $settings['__experimentalEnableListBlockV2'] = gutenberg_is_list_v2_enabled();
+ // To tell mobile that the site uses list v2 (inner blocks).
+ $settings['__experimentalEnableListBlockV2'] = true;
}
return $settings;
diff --git a/lib/experimental/blocks.php b/lib/experimental/blocks.php
deleted file mode 100644
index 80691e5d917ab..0000000000000
--- a/lib/experimental/blocks.php
+++ /dev/null
@@ -1,27 +0,0 @@
- __( 'Test a new list block that uses nested list item blocks (Warning: The new block is not ready. You may experience content loss, avoid using it on production sites)', 'gutenberg' ),
- 'id' => 'gutenberg-list-v2',
- )
- );
register_setting(
'gutenberg-experiments',
'gutenberg-experiments'
diff --git a/lib/load.php b/lib/load.php
index 9600d3100d3b7..cb2ad7721c320 100644
--- a/lib/load.php
+++ b/lib/load.php
@@ -103,7 +103,6 @@ function gutenberg_is_experiment_enabled( $name ) {
require __DIR__ . '/experimental/class-wp-webfonts-provider.php';
require __DIR__ . '/experimental/class-wp-webfonts-provider-local.php';
require __DIR__ . '/experimental/webfonts.php';
-require __DIR__ . '/experimental/blocks.php';
require __DIR__ . '/experimental/navigation-theme-opt-in.php';
require __DIR__ . '/experimental/navigation-page.php';
diff --git a/packages/block-editor/src/components/block-list/use-block-props/use-focus-first-element.js b/packages/block-editor/src/components/block-list/use-block-props/use-focus-first-element.js
index 8b95f19f3c9ff..492555935dadf 100644
--- a/packages/block-editor/src/components/block-list/use-block-props/use-focus-first-element.js
+++ b/packages/block-editor/src/components/block-list/use-block-props/use-focus-first-element.js
@@ -85,7 +85,7 @@ export function useFocusFirstElement( clientId ) {
const { ownerDocument } = ref.current;
// Do not focus the block if it already contains the active element.
- if ( ref.current.contains( ownerDocument.activeElement ) ) {
+ if ( isInsideRootBlock( ref.current, ownerDocument.activeElement ) ) {
return;
}
diff --git a/packages/block-editor/src/components/writing-flow/use-select-all.js b/packages/block-editor/src/components/writing-flow/use-select-all.js
index 15473e3a201c7..93c55c185b8c7 100644
--- a/packages/block-editor/src/components/writing-flow/use-select-all.js
+++ b/packages/block-editor/src/components/writing-flow/use-select-all.js
@@ -37,28 +37,25 @@ export default function useSelectAll() {
return;
}
+ event.preventDefault();
+
const [ firstSelectedClientId ] = selectedClientIds;
const rootClientId = getBlockRootClientId( firstSelectedClientId );
- let blockClientIds = getBlockOrder( rootClientId );
+ const blockClientIds = getBlockOrder( rootClientId );
// If we have selected all sibling nested blocks, try selecting up a
// level. See: https://github.com/WordPress/gutenberg/pull/31859/
if ( selectedClientIds.length === blockClientIds.length ) {
- blockClientIds = getBlockOrder(
- getBlockRootClientId( rootClientId )
- );
- }
-
- const firstClientId = first( blockClientIds );
- const lastClientId = last( blockClientIds );
-
- if ( firstClientId === lastClientId ) {
- selectBlock( firstClientId );
+ if ( rootClientId ) {
+ node.ownerDocument.defaultView
+ .getSelection()
+ .removeAllRanges();
+ selectBlock( rootClientId );
+ }
return;
}
- multiSelect( firstClientId, lastClientId );
- event.preventDefault();
+ multiSelect( first( blockClientIds ), last( blockClientIds ) );
}
node.addEventListener( 'keydown', onKeyDown );
diff --git a/packages/block-library/src/index.js b/packages/block-library/src/index.js
index f0d5924d7248d..e71ee9326a4b8 100644
--- a/packages/block-library/src/index.js
+++ b/packages/block-library/src/index.js
@@ -290,10 +290,7 @@ export const registerCoreBlocks = (
export const __experimentalRegisterExperimentalCoreBlocks = process.env
.IS_GUTENBERG_PLUGIN
? ( { enableFSEBlocks } = {} ) => {
- const enabledExperiments = [
- window.__experimentalEnableListBlockV2 ? 'list-v2' : null,
- enableFSEBlocks ? 'fse' : null,
- ];
+ const enabledExperiments = [ enableFSEBlocks ? 'fse' : null ];
getAllBlocks()
.filter( ( { metadata } ) =>
isBlockMetadataExperimental( metadata )
diff --git a/packages/block-library/src/index.native.js b/packages/block-library/src/index.native.js
index 6285ad2f91377..1acc90c0116c6 100644
--- a/packages/block-library/src/index.native.js
+++ b/packages/block-library/src/index.native.js
@@ -186,14 +186,6 @@ const devOnly = ( block ) => ( !! __DEV__ ? block : null );
const iOSOnly = ( block ) =>
Platform.OS === 'ios' ? block : devOnly( block );
-// To be removed once List V2 is released on the web editor.
-function listCheck( listBlock, blocksFlags ) {
- if ( blocksFlags?.__experimentalEnableListBlockV2 ) {
- listBlock.settings = listBlock?.settingsV2;
- }
- return listBlock;
-}
-
// Hide the Classic block and SocialLink block
addFilter(
'blocks.registerBlockType',
@@ -245,11 +237,8 @@ addFilter(
*
* registerCoreBlocks();
* ```
- * @param {Object} [blocksFlags] Experimental flags
- *
- *
*/
-export const registerCoreBlocks = ( blocksFlags ) => {
+export const registerCoreBlocks = () => {
// When adding new blocks to this list please also consider updating /src/block-support/supported-blocks.json in the Gutenberg-Mobile repo
[
paragraph,
@@ -261,7 +250,7 @@ export const registerCoreBlocks = ( blocksFlags ) => {
video,
nextpage,
separator,
- listCheck( list, blocksFlags ),
+ list,
listItem,
quote,
mediaText,
diff --git a/packages/block-library/src/list-item/block.json b/packages/block-library/src/list-item/block.json
index 5b8ad8456944f..674cf381aa99c 100644
--- a/packages/block-library/src/list-item/block.json
+++ b/packages/block-library/src/list-item/block.json
@@ -1,7 +1,6 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
- "__experimental": "list-v2",
"name": "core/list-item",
"title": "List item",
"category": "text",
diff --git a/packages/block-library/src/list-item/hooks/use-space.js b/packages/block-library/src/list-item/hooks/use-space.js
index 3fc6d1157eb2e..6079b2c5edb28 100644
--- a/packages/block-library/src/list-item/hooks/use-space.js
+++ b/packages/block-library/src/list-item/hooks/use-space.js
@@ -19,13 +19,21 @@ export default function useSpace( clientId ) {
return useRefEffect(
( element ) => {
function onKeyDown( event ) {
+ const { keyCode, shiftKey, altKey, metaKey, ctrlKey } = event;
+
if (
event.defaultPrevented ||
- event.keyCode !== SPACE ||
- ! canIndent
+ ! canIndent ||
+ keyCode !== SPACE ||
+ // Only override when no modifiers are pressed.
+ shiftKey ||
+ altKey ||
+ metaKey ||
+ ctrlKey
) {
return;
}
+
const selectionStart = getSelectionStart();
const selectionEnd = getSelectionEnd();
if (
diff --git a/packages/block-library/src/list/deprecated.js b/packages/block-library/src/list/deprecated.js
index a3454f5ae050c..cfd7e3039cee8 100644
--- a/packages/block-library/src/list/deprecated.js
+++ b/packages/block-library/src/list/deprecated.js
@@ -7,6 +7,7 @@ import { RichText, useBlockProps } from '@wordpress/block-editor';
* Internal dependencies
*/
import migrateFontFamily from '../utils/migrate-font-family';
+import { migrateToListV2 } from './utils';
const v0 = {
attributes: {
@@ -68,6 +69,75 @@ const v0 = {
},
};
+const v1 = {
+ attributes: {
+ ordered: {
+ type: 'boolean',
+ default: false,
+ __experimentalRole: 'content',
+ },
+ values: {
+ type: 'string',
+ source: 'html',
+ selector: 'ol,ul',
+ multiline: 'li',
+ __unstableMultilineWrapperTags: [ 'ol', 'ul' ],
+ default: '',
+ __experimentalRole: 'content',
+ },
+ type: {
+ type: 'string',
+ },
+ start: {
+ type: 'number',
+ },
+ reversed: {
+ type: 'boolean',
+ },
+ placeholder: {
+ type: 'string',
+ },
+ },
+ supports: {
+ anchor: true,
+ className: false,
+ typography: {
+ fontSize: true,
+ __experimentalFontFamily: true,
+ lineHeight: true,
+ __experimentalFontStyle: true,
+ __experimentalFontWeight: true,
+ __experimentalLetterSpacing: true,
+ __experimentalTextTransform: true,
+ __experimentalDefaultControls: {
+ fontSize: true,
+ },
+ },
+ color: {
+ gradients: true,
+ link: true,
+ __experimentalDefaultControls: {
+ background: true,
+ text: true,
+ },
+ },
+ __unstablePasteTextInline: true,
+ __experimentalSelector: 'ol,ul',
+ __experimentalSlashInserter: true,
+ },
+ save( { attributes } ) {
+ const { ordered, values, type, reversed, start } = attributes;
+ const TagName = ordered ? 'ol' : 'ul';
+
+ return (
+
+
+
+ );
+ },
+ migrate: migrateToListV2,
+};
+
/**
* New deprecations need to be placed first
* for them to have higher priority.
@@ -76,4 +146,4 @@ const v0 = {
*
* See block-deprecation.md
*/
-export default [ v0 ];
+export default [ v1, v0 ];
diff --git a/packages/block-library/src/list/edit.js b/packages/block-library/src/list/edit.js
index 8d39252aee128..41b1376b51492 100644
--- a/packages/block-library/src/list/edit.js
+++ b/packages/block-library/src/list/edit.js
@@ -1,177 +1,189 @@
+/**
+ * External dependencies
+ */
+import { last } from 'lodash';
+
/**
* WordPress dependencies
*/
-import { __, _x, isRTL } from '@wordpress/i18n';
-import { createBlock } from '@wordpress/blocks';
import {
- RichText,
BlockControls,
- RichTextShortcut,
useBlockProps,
+ useInnerBlocksProps,
+ store as blockEditorStore,
} from '@wordpress/block-editor';
import { ToolbarButton } from '@wordpress/components';
-import {
- __unstableCanIndentListItems as canIndentListItems,
- __unstableCanOutdentListItems as canOutdentListItems,
- __unstableIndentListItems as indentListItems,
- __unstableOutdentListItems as outdentListItems,
- __unstableChangeListType as changeListType,
- __unstableIsListRootSelected as isListRootSelected,
- __unstableIsActiveListType as isActiveListType,
-} from '@wordpress/rich-text';
+import { useDispatch, useSelect, useRegistry } from '@wordpress/data';
+import { isRTL, __ } from '@wordpress/i18n';
import {
formatListBullets,
formatListBulletsRTL,
formatListNumbered,
formatListNumberedRTL,
- formatIndent,
- formatIndentRTL,
formatOutdent,
formatOutdentRTL,
} from '@wordpress/icons';
+import { createBlock } from '@wordpress/blocks';
+import { useCallback, useEffect, Platform } from '@wordpress/element';
+import deprecated from '@wordpress/deprecated';
/**
* Internal dependencies
*/
-import { name } from './';
import OrderedListSettings from './ordered-list-settings';
+import { migrateToListV2 } from './utils';
+import TagName from './tag-name';
-export default function ListEdit( {
- attributes,
- setAttributes,
- mergeBlocks,
- onReplace,
- style,
-} ) {
- const { ordered, values, type, reversed, start, placeholder } = attributes;
- const tagName = ordered ? 'ol' : 'ul';
+const TEMPLATE = [ [ 'core/list-item' ] ];
+const NATIVE_MARGIN_SPACING = 8;
- const controls = ( { value, onChange, onFocus } ) => (
- <>
- {
- onChange( outdentListItems( value ) );
- } }
- />
- {
- onChange( indentListItems( value, { type: tagName } ) );
- } }
- />
- {
- onChange( indentListItems( value, { type: tagName } ) );
- } }
- />
- {
- onChange( outdentListItems( value ) );
- } }
- />
-
- {
- onChange( changeListType( value, { type: 'ul' } ) );
- onFocus();
+/**
+ * At the moment, deprecations don't handle create blocks from attributes
+ * (like when using CPT templates). For this reason, this hook is necessary
+ * to avoid breaking templates using the old list block format.
+ *
+ * @param {Object} attributes Block attributes.
+ * @param {string} clientId Block client ID.
+ */
+function useMigrateOnLoad( attributes, clientId ) {
+ const registry = useRegistry();
+ const { updateBlockAttributes, replaceInnerBlocks } =
+ useDispatch( blockEditorStore );
- if ( isListRootSelected( value ) ) {
- setAttributes( { ordered: false } );
- }
- } }
- />
- {
- onChange( changeListType( value, { type: 'ol' } ) );
- onFocus();
+ useEffect( () => {
+ // As soon as the block is loaded, migrate it to the new version.
- if ( isListRootSelected( value ) ) {
- setAttributes( { ordered: true } );
- }
- } }
- />
- {
- onChange( outdentListItems( value ) );
- onFocus();
- } }
- />
- {
- onChange( indentListItems( value, { type: tagName } ) );
- onFocus();
- } }
- />
-
+ if ( ! attributes.values ) {
+ return;
+ }
+
+ const [ newAttributes, newInnerBlocks ] = migrateToListV2( attributes );
+
+ deprecated( 'Value attribute on the list block', {
+ since: '6.0',
+ version: '6.5',
+ alternative: 'inner blocks',
+ } );
+
+ registry.batch( () => {
+ updateBlockAttributes( clientId, newAttributes );
+ replaceInnerBlocks( clientId, newInnerBlocks );
+ } );
+ }, [ attributes.values ] );
+}
+
+function useOutdentList( clientId ) {
+ const { canOutdent } = useSelect(
+ ( innerSelect ) => {
+ const { getBlockRootClientId, getBlock } =
+ innerSelect( blockEditorStore );
+ const parentId = getBlockRootClientId( clientId );
+ return {
+ canOutdent:
+ !! parentId &&
+ getBlock( parentId ).name === 'core/list-item',
+ };
+ },
+ [ clientId ]
+ );
+ const { replaceBlocks, selectionChange } = useDispatch( blockEditorStore );
+ const { getBlockRootClientId, getBlockAttributes, getBlock } =
+ useSelect( blockEditorStore );
+
+ return [
+ canOutdent,
+ useCallback( () => {
+ const parentBlockId = getBlockRootClientId( clientId );
+ const parentBlockAttributes = getBlockAttributes( parentBlockId );
+ // Create a new parent block without the inner blocks.
+ const newParentBlock = createBlock(
+ 'core/list-item',
+ parentBlockAttributes
+ );
+ const { innerBlocks } = getBlock( clientId );
+ // Replace the parent block with a new parent block without inner blocks,
+ // and make the inner blocks siblings of the parent.
+ replaceBlocks(
+ [ parentBlockId ],
+ [ newParentBlock, ...innerBlocks ]
+ );
+ // Select the last child of the list being outdent.
+ selectionChange( last( innerBlocks ).clientId );
+ }, [ clientId ] ),
+ ];
+}
+
+function IndentUI( { clientId } ) {
+ const [ canOutdent, outdentList ] = useOutdentList( clientId );
+ return (
+ <>
+
>
);
+}
+export default function Edit( { attributes, setAttributes, clientId, style } ) {
const blockProps = useBlockProps( {
- style,
+ ...( Platform.isNative && { style } ),
+ } );
+ const innerBlocksProps = useInnerBlocksProps( blockProps, {
+ allowedBlocks: [ 'core/list-item' ],
+ template: TEMPLATE,
+ templateInsertUpdatesSelection: true,
+ ...( Platform.isNative && {
+ marginVertical: NATIVE_MARGIN_SPACING,
+ marginHorizontal: NATIVE_MARGIN_SPACING,
+ } ),
} );
+ useMigrateOnLoad( attributes, clientId );
+ const { ordered, type, reversed, start } = attributes;
+
+ const controls = (
+
+ {
+ setAttributes( { ordered: false } );
+ } }
+ />
+ {
+ setAttributes( { ordered: true } );
+ } }
+ />
+
+
+ );
return (
<>
-
- setAttributes( { values: nextValues } )
- }
- value={ values }
- aria-label={ __( 'List text' ) }
- placeholder={ placeholder || __( 'List' ) }
- onMerge={ mergeBlocks }
- onSplit={ ( value ) =>
- createBlock( name, { ...attributes, values: value } )
- }
- __unstableOnSplitMiddle={ () =>
- createBlock( 'core/paragraph' )
- }
- onReplace={ onReplace }
- onRemove={ () => onReplace( [] ) }
- start={ start }
+
- { controls }
-
+ { ...innerBlocksProps }
+ />
+ { controls }
{ ordered && (
) }
>
diff --git a/packages/block-library/src/list/index.js b/packages/block-library/src/list/index.js
index a401d75eb1458..6df2d4ef40333 100644
--- a/packages/block-library/src/list/index.js
+++ b/packages/block-library/src/list/index.js
@@ -2,6 +2,7 @@
* WordPress dependencies
*/
import { list as icon } from '@wordpress/icons';
+import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
@@ -11,41 +12,41 @@ import edit from './edit';
import metadata from './block.json';
import save from './save';
import transforms from './transforms';
-import settingsV2 from './v2';
const { name } = metadata;
-export { metadata, name, settingsV2 };
+export { metadata, name };
-const settingsV1 = {
+const settings = {
icon,
example: {
- attributes: {
- values: 'Alice.The White Rabbit.The Cheshire Cat.The Mad Hatter.The Queen of Hearts.',
- },
+ innerBlocks: [
+ {
+ name: 'core/list-item',
+ attributes: { content: __( 'Alice.' ) },
+ },
+ {
+ name: 'core/list-item',
+ attributes: { content: __( 'The White Rabbit.' ) },
+ },
+ {
+ name: 'core/list-item',
+ attributes: { content: __( 'The Cheshire Cat.' ) },
+ },
+ {
+ name: 'core/list-item',
+ attributes: { content: __( 'The Mad Hatter.' ) },
+ },
+ {
+ name: 'core/list-item',
+ attributes: { content: __( 'The Queen of Hearts.' ) },
+ },
+ ],
},
transforms,
- merge( attributes, attributesToMerge ) {
- const { values } = attributesToMerge;
-
- if ( ! values || values === '' ) {
- return attributes;
- }
-
- return {
- ...attributes,
- values: attributes.values + values,
- };
- },
edit,
save,
deprecated,
};
-let settings = settingsV1;
-if ( process.env.IS_GUTENBERG_PLUGIN ) {
- settings = window?.__experimentalEnableListBlockV2
- ? settingsV2
- : settingsV1;
-}
export { settings };
diff --git a/packages/block-library/src/list/save.js b/packages/block-library/src/list/save.js
index 7d4f8a37fc86a..c74893f38b67b 100644
--- a/packages/block-library/src/list/save.js
+++ b/packages/block-library/src/list/save.js
@@ -1,15 +1,14 @@
/**
* WordPress dependencies
*/
-import { RichText, useBlockProps } from '@wordpress/block-editor';
+import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
export default function save( { attributes } ) {
- const { ordered, values, type, reversed, start } = attributes;
+ const { ordered, type, reversed, start } = attributes;
const TagName = ordered ? 'ol' : 'ul';
-
return (
-
+
);
}
diff --git a/packages/block-library/src/list/v2/tag-name.js b/packages/block-library/src/list/tag-name.js
similarity index 100%
rename from packages/block-library/src/list/v2/tag-name.js
rename to packages/block-library/src/list/tag-name.js
diff --git a/packages/block-library/src/list/v2/tag-name.native.js b/packages/block-library/src/list/tag-name.native.js
similarity index 100%
rename from packages/block-library/src/list/v2/tag-name.native.js
rename to packages/block-library/src/list/tag-name.native.js
diff --git a/packages/block-library/src/list/test/__snapshots__/edit.native.js.snap b/packages/block-library/src/list/test/__snapshots__/edit.native.js.snap
index 3fe53069b1775..a573276840bb6 100644
--- a/packages/block-library/src/list/test/__snapshots__/edit.native.js.snap
+++ b/packages/block-library/src/list/test/__snapshots__/edit.native.js.snap
@@ -122,12 +122,24 @@ exports[`List V2 block shows different indentation levels 1`] = `
exports[`List block inserts block 1`] = `
"
-
+
"
`;
exports[`List block renders a list with a few items 1`] = `
"
-
+
+- Item 1
+
+
+
+- Item 2
+
+
+
+- Item 3
+
"
`;
diff --git a/packages/block-library/src/list/test/migrate.js b/packages/block-library/src/list/test/migrate.js
deleted file mode 100644
index a57693d341bd5..0000000000000
--- a/packages/block-library/src/list/test/migrate.js
+++ /dev/null
@@ -1,158 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { registerBlockType, serialize } from '@wordpress/blocks';
-
-/**
- * Internal dependencies
- */
-import { migrateToListV2 } from '../v2/migrate';
-import * as listItem from '../../list-item';
-import * as list from '../../list';
-import listV2 from '../../list/v2';
-
-describe( 'Migrate list block', () => {
- beforeAll( () => {
- const prev = window.__experimentalEnableListBlockV2;
-
- // force list and list item block registration.
- registerBlockType(
- { name: listItem.name, ...listItem.metadata },
- listItem.settings
- );
- registerBlockType( { name: list.name, ...list.metadata }, listV2 );
-
- window.__experimentalEnableListBlockV2 = prev;
- } );
-
- it( 'should migrate the values attribute to inner blocks', () => {
- const [ updatedAttributes, updatedInnerBlocks ] = migrateToListV2( {
- values: 'testtesttest- test test
- test est eesssss
',
- ordered: false,
- } );
-
- expect( updatedAttributes ).toEqual( {
- ordered: false,
- // Ideally the values attributes shouldn't be here
- // but since we didn't enable v2 by default yet,
- // we're keeping the old default value in block.json
- values: '',
- } );
- expect( serialize( updatedInnerBlocks ) )
- .toEqual( `
-test
-
-
-
-test
-
-
-
-test
-
-- test test
-
-
-
-- test est eesssss
-
-
-` );
- } );
-
- it( 'should handle empty space properly', () => {
- const [ updatedAttributes, updatedInnerBlocks ] = migrateToListV2( {
- values: `Europe
-
- \tAfrica
-
- - Algeria
-
- \t
- `,
- ordered: false,
- } );
-
- expect( updatedAttributes ).toEqual( {
- ordered: false,
- // Ideally the values attributes shouldn't be here
- // but since we didn't enable v2 by default yet,
- // we're keeping the old default value in block.json
- values: '',
- } );
- expect( serialize( updatedInnerBlocks ) )
- .toEqual( `
-Europe
-
-
-
-Africa
-
-- Algeria
-
-
-` );
- } );
-
- it( 'should handle formats properly', () => {
- const [ updatedAttributes, updatedInnerBlocks ] = migrateToListV2( {
- values: `Europe- France
- Lyon Rhones
- Paris Ile de france
`,
- ordered: false,
- } );
-
- expect( updatedAttributes ).toEqual( {
- ordered: false,
- // Ideally the values attributes shouldn't be here
- // but since we didn't enable v2 by default yet,
- // we're keeping the old default value in block.json
- values: '',
- } );
- expect( serialize( updatedInnerBlocks ) )
- .toEqual( `
-Europe
-
-- France
-
-- Lyon Rhones
-
-
-
-- Paris Ile de france
-
-
-
-
-
-
-` );
- } );
-
- it( 'should not add random space', () => {
- const [ updatedAttributes, updatedInnerBlocks ] = migrateToListV2( {
- values: `Europe`,
- ordered: false,
- } );
-
- expect( updatedAttributes ).toEqual( {
- ordered: false,
- // Ideally the values attributes shouldn't be here
- // but since we didn't enable v2 by default yet,
- // we're keeping the old default value in block.json
- values: '',
- } );
- expect( serialize( updatedInnerBlocks ) )
- .toEqual( `
-Europe
-
-
-` );
- } );
-} );
diff --git a/packages/block-library/src/list/transforms.js b/packages/block-library/src/list/transforms.js
index 8f2c768a343b7..a6263d7ad639c 100644
--- a/packages/block-library/src/list/transforms.js
+++ b/packages/block-library/src/list/transforms.js
@@ -1,15 +1,13 @@
/**
* WordPress dependencies
*/
-import { createBlock, getBlockAttributes } from '@wordpress/blocks';
-import {
- __UNSTABLE_LINE_SEPARATOR,
- create,
- join,
- replace,
- split,
- toHTMLString,
-} from '@wordpress/rich-text';
+import { createBlock } from '@wordpress/blocks';
+import { create, split, toHTMLString } from '@wordpress/rich-text';
+
+/**
+ * Internal dependencies
+ */
+import { createListBlockFromDOMElement } from './utils';
function getListContentSchema( { phrasingContentSchema } ) {
const listContentSchema = {
@@ -32,6 +30,15 @@ function getListContentSchema( { phrasingContentSchema } ) {
return listContentSchema;
}
+function getListContentFlat( blocks ) {
+ return blocks.flatMap( ( { name, attributes, innerBlocks = [] } ) => {
+ if ( name === 'core/list-item' ) {
+ return [ attributes.content, ...getListContentFlat( innerBlocks ) ];
+ }
+ return getListContentFlat( innerBlocks );
+ } );
+}
+
const transforms = {
from: [
{
@@ -39,30 +46,28 @@ const transforms = {
isMultiBlock: true,
blocks: [ 'core/paragraph', 'core/heading' ],
transform: ( blockAttributes ) => {
- return createBlock( 'core/list', {
- values: toHTMLString( {
- value: join(
- blockAttributes.map( ( { content } ) => {
- const value = create( { html: content } );
-
- if ( blockAttributes.length > 1 ) {
- return value;
- }
-
- // When converting only one block, transform
- // every line to a list item.
- return replace(
- value,
- /\n/g,
- __UNSTABLE_LINE_SEPARATOR
- );
- } ),
- __UNSTABLE_LINE_SEPARATOR
- ),
- multilineTag: 'li',
- } ),
- anchor: blockAttributes.anchor,
- } );
+ let childBlocks = [];
+ if ( blockAttributes.length > 1 ) {
+ childBlocks = blockAttributes.map( ( { content } ) => {
+ return createBlock( 'core/list-item', { content } );
+ } );
+ } else if ( blockAttributes.length === 1 ) {
+ const value = create( {
+ html: blockAttributes[ 0 ].content,
+ } );
+ childBlocks = split( value, '\n' ).map( ( result ) => {
+ return createBlock( 'core/list-item', {
+ content: toHTMLString( { value: result } ),
+ } );
+ } );
+ }
+ return createBlock(
+ 'core/list',
+ {
+ anchor: blockAttributes.anchor,
+ },
+ childBlocks
+ );
},
},
{
@@ -72,102 +77,43 @@ const transforms = {
ol: getListContentSchema( args ).ol,
ul: getListContentSchema( args ).ul,
} ),
- transform( node ) {
- const attributes = {
- ordered: node.nodeName === 'OL',
- anchor: node.id === '' ? undefined : node.id,
- };
-
- if ( attributes.ordered ) {
- const type = node.getAttribute( 'type' );
-
- if ( type ) {
- attributes.type = type;
- }
-
- if ( node.getAttribute( 'reversed' ) !== null ) {
- attributes.reversed = true;
- }
-
- const start = parseInt( node.getAttribute( 'start' ), 10 );
-
- if (
- ! isNaN( start ) &&
- // start=1 only makes sense if the list is reversed.
- ( start !== 1 || attributes.reversed )
- ) {
- attributes.start = start;
- }
- }
-
- return createBlock( 'core/list', {
- ...getBlockAttributes( 'core/list', node.outerHTML ),
- ...attributes,
- } );
- },
+ transform: createListBlockFromDOMElement,
},
...[ '*', '-' ].map( ( prefix ) => ( {
type: 'prefix',
prefix,
transform( content ) {
- return createBlock( 'core/list', {
- values: `${ content }`,
- } );
+ return createBlock( 'core/list', {}, [
+ createBlock( 'core/list-item', { content } ),
+ ] );
},
} ) ),
...[ '1.', '1)' ].map( ( prefix ) => ( {
type: 'prefix',
prefix,
transform( content ) {
- return createBlock( 'core/list', {
- ordered: true,
- values: `${ content }`,
- } );
+ return createBlock(
+ 'core/list',
+ {
+ ordered: true,
+ },
+ [ createBlock( 'core/list-item', { content } ) ]
+ );
},
} ) ),
],
to: [
- {
+ ...[ 'core/paragraph', 'core/heading' ].map( ( block ) => ( {
type: 'block',
- blocks: [ 'core/paragraph' ],
- transform: ( { values } ) =>
- split(
- create( {
- html: values,
- multilineTag: 'li',
- multilineWrapperTags: [ 'ul', 'ol' ],
- } ),
- __UNSTABLE_LINE_SEPARATOR
- ).map( ( piece ) =>
- createBlock( 'core/paragraph', {
- content: toHTMLString( { value: piece } ),
+ blocks: [ block ],
+ transform: ( _attributes, childBlocks ) => {
+ return getListContentFlat( childBlocks ).map( ( content ) =>
+ createBlock( block, {
+ content,
} )
- ),
- },
- {
- type: 'block',
- blocks: [ 'core/heading' ],
- transform: ( { values } ) =>
- split(
- create( {
- html: values,
- multilineTag: 'li',
- multilineWrapperTags: [ 'ul', 'ol' ],
- } ),
- __UNSTABLE_LINE_SEPARATOR
- ).map( ( piece ) =>
- createBlock( 'core/heading', {
- content: toHTMLString( { value: piece } ),
- } )
- ),
- },
- {
- type: 'block',
- blocks: [ 'core/table-of-contents' ],
- transform: () => {
- return createBlock( 'core/table-of-contents' );
+ );
},
- },
+ } ) ),
],
};
diff --git a/packages/block-library/src/list/v2/migrate.js b/packages/block-library/src/list/utils.js
similarity index 94%
rename from packages/block-library/src/list/v2/migrate.js
rename to packages/block-library/src/list/utils.js
index d0ed33e8f3c44..61d1cbef89234 100644
--- a/packages/block-library/src/list/v2/migrate.js
+++ b/packages/block-library/src/list/utils.js
@@ -11,11 +11,11 @@ import { createBlock } from '@wordpress/blocks';
export function createListBlockFromDOMElement( listElement ) {
const listAttributes = {
ordered: 'OL' === listElement.tagName,
+ anchor: listElement.id === '' ? undefined : listElement.id,
start: listElement.getAttribute( 'start' )
? parseInt( listElement.getAttribute( 'start' ), 10 )
: undefined,
- reversed:
- listElement.getAttribute( 'reversed' ) === true ? true : undefined,
+ reversed: listElement.hasAttribute( 'reversed' ) ? true : undefined,
type: listElement.getAttribute( 'type' ) ?? undefined,
};
diff --git a/packages/block-library/src/list/v2/deprecated.js b/packages/block-library/src/list/v2/deprecated.js
deleted file mode 100644
index f177e68bcff80..0000000000000
--- a/packages/block-library/src/list/v2/deprecated.js
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { RichText, useBlockProps } from '@wordpress/block-editor';
-
-/**
- * Internal dependencies
- */
-import initialDeprecations from '../deprecated';
-import { migrateToListV2 } from './migrate';
-
-const v1 = {
- attributes: {
- ordered: {
- type: 'boolean',
- default: false,
- __experimentalRole: 'content',
- },
- values: {
- type: 'string',
- source: 'html',
- selector: 'ol,ul',
- multiline: 'li',
- __unstableMultilineWrapperTags: [ 'ol', 'ul' ],
- default: '',
- __experimentalRole: 'content',
- },
- type: {
- type: 'string',
- },
- start: {
- type: 'number',
- },
- reversed: {
- type: 'boolean',
- },
- placeholder: {
- type: 'string',
- },
- },
- supports: {
- anchor: true,
- className: false,
- typography: {
- fontSize: true,
- __experimentalFontFamily: true,
- lineHeight: true,
- __experimentalFontStyle: true,
- __experimentalFontWeight: true,
- __experimentalLetterSpacing: true,
- __experimentalTextTransform: true,
- __experimentalDefaultControls: {
- fontSize: true,
- },
- },
- color: {
- gradients: true,
- link: true,
- __experimentalDefaultControls: {
- background: true,
- text: true,
- },
- },
- __unstablePasteTextInline: true,
- __experimentalSelector: 'ol,ul',
- __experimentalSlashInserter: true,
- },
- save( { attributes } ) {
- const { ordered, values, type, reversed, start } = attributes;
- const TagName = ordered ? 'ol' : 'ul';
-
- return (
-
-
-
- );
- },
- migrate: migrateToListV2,
-};
-
-/**
- * New deprecations need to be placed first
- * for them to have higher priority.
- *
- * Old deprecations may need to be updated as well.
- *
- * See block-deprecation.md
- */
-export default [ v1, ...initialDeprecations ];
diff --git a/packages/block-library/src/list/v2/edit.js b/packages/block-library/src/list/v2/edit.js
deleted file mode 100644
index 9ef320b53b001..0000000000000
--- a/packages/block-library/src/list/v2/edit.js
+++ /dev/null
@@ -1,192 +0,0 @@
-/**
- * External dependencies
- */
-import { last } from 'lodash';
-
-/**
- * WordPress dependencies
- */
-import {
- BlockControls,
- useBlockProps,
- useInnerBlocksProps,
- store as blockEditorStore,
-} from '@wordpress/block-editor';
-import { ToolbarButton } from '@wordpress/components';
-import { useDispatch, useSelect, useRegistry } from '@wordpress/data';
-import { isRTL, __ } from '@wordpress/i18n';
-import {
- formatListBullets,
- formatListBulletsRTL,
- formatListNumbered,
- formatListNumberedRTL,
- formatOutdent,
- formatOutdentRTL,
-} from '@wordpress/icons';
-import { createBlock } from '@wordpress/blocks';
-import { useCallback, useEffect, Platform } from '@wordpress/element';
-import deprecated from '@wordpress/deprecated';
-
-/**
- * Internal dependencies
- */
-import OrderedListSettings from '../ordered-list-settings';
-import { migrateToListV2 } from './migrate';
-import TagName from './tag-name';
-
-const TEMPLATE = [ [ 'core/list-item' ] ];
-const NATIVE_MARGIN_SPACING = 8;
-
-/**
- * At the moment, deprecations don't handle create blocks from attributes
- * (like when using CPT templates). For this reason, this hook is necessary
- * to avoid breaking templates using the old list block format.
- *
- * @param {Object} attributes Block attributes.
- * @param {string} clientId Block client ID.
- */
-function useMigrateOnLoad( attributes, clientId ) {
- const registry = useRegistry();
- const { updateBlockAttributes, replaceInnerBlocks } =
- useDispatch( blockEditorStore );
-
- useEffect( () => {
- // As soon as the block is loaded, migrate it to the new version.
-
- if ( ! attributes.values ) {
- return;
- }
-
- const [ newAttributes, newInnerBlocks ] = migrateToListV2( attributes );
-
- deprecated( 'Value attribute on the list block', {
- since: '6.0',
- version: '6.5',
- alternative: 'inner blocks',
- } );
-
- registry.batch( () => {
- updateBlockAttributes( clientId, newAttributes );
- replaceInnerBlocks( clientId, newInnerBlocks );
- } );
- }, [ attributes.values ] );
-}
-
-function useOutdentList( clientId ) {
- const { canOutdent } = useSelect(
- ( innerSelect ) => {
- const { getBlockRootClientId, getBlock } =
- innerSelect( blockEditorStore );
- const parentId = getBlockRootClientId( clientId );
- return {
- canOutdent:
- !! parentId &&
- getBlock( parentId ).name === 'core/list-item',
- };
- },
- [ clientId ]
- );
- const { replaceBlocks, selectionChange } = useDispatch( blockEditorStore );
- const { getBlockRootClientId, getBlockAttributes, getBlock } =
- useSelect( blockEditorStore );
-
- return [
- canOutdent,
- useCallback( () => {
- const parentBlockId = getBlockRootClientId( clientId );
- const parentBlockAttributes = getBlockAttributes( parentBlockId );
- // Create a new parent block without the inner blocks.
- const newParentBlock = createBlock(
- 'core/list-item',
- parentBlockAttributes
- );
- const { innerBlocks } = getBlock( clientId );
- // Replace the parent block with a new parent block without inner blocks,
- // and make the inner blocks siblings of the parent.
- replaceBlocks(
- [ parentBlockId ],
- [ newParentBlock, ...innerBlocks ]
- );
- // Select the last child of the list being outdent.
- selectionChange( last( innerBlocks ).clientId );
- }, [ clientId ] ),
- ];
-}
-
-function IndentUI( { clientId } ) {
- const [ canOutdent, outdentList ] = useOutdentList( clientId );
- return (
- <>
-
- >
- );
-}
-
-function Edit( { attributes, setAttributes, clientId, style } ) {
- const blockProps = useBlockProps( {
- ...( Platform.isNative && { style } ),
- } );
- const innerBlocksProps = useInnerBlocksProps( blockProps, {
- allowedBlocks: [ 'core/list-item' ],
- template: TEMPLATE,
- templateInsertUpdatesSelection: true,
- ...( Platform.isNative && {
- marginVertical: NATIVE_MARGIN_SPACING,
- marginHorizontal: NATIVE_MARGIN_SPACING,
- } ),
- } );
- useMigrateOnLoad( attributes, clientId );
- const { ordered, reversed, start } = attributes;
-
- const controls = (
-
- {
- setAttributes( { ordered: false } );
- } }
- />
- {
- setAttributes( { ordered: true } );
- } }
- />
-
-
- );
-
- return (
- <>
-
- { controls }
- { ordered && (
-
- ) }
- >
- );
-}
-
-export default Edit;
diff --git a/packages/block-library/src/list/v2/index.js b/packages/block-library/src/list/v2/index.js
deleted file mode 100644
index 33107a72ff1bf..0000000000000
--- a/packages/block-library/src/list/v2/index.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { list as icon } from '@wordpress/icons';
-
-/**
- * Internal dependencies
- */
-import edit from './edit';
-import save from './save';
-import transforms from './transforms';
-import deprecated from './deprecated';
-
-const settings = {
- icon,
- edit,
- save,
- transforms,
- deprecated,
-};
-
-export default settings;
diff --git a/packages/block-library/src/list/v2/save.js b/packages/block-library/src/list/v2/save.js
deleted file mode 100644
index 8d187a93f38b5..0000000000000
--- a/packages/block-library/src/list/v2/save.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
-
-export default function save( { attributes } ) {
- const { ordered, reversed, start } = attributes;
- const TagName = ordered ? 'ol' : 'ul';
- return (
-
-
-
- );
-}
diff --git a/packages/block-library/src/list/v2/transforms.js b/packages/block-library/src/list/v2/transforms.js
deleted file mode 100644
index ba5514815fc72..0000000000000
--- a/packages/block-library/src/list/v2/transforms.js
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { createBlock } from '@wordpress/blocks';
-import { create, split, toHTMLString } from '@wordpress/rich-text';
-
-/**
- * Internal dependencies
- */
-import { createListBlockFromDOMElement } from './migrate';
-
-function getListContentSchema( { phrasingContentSchema } ) {
- const listContentSchema = {
- ...phrasingContentSchema,
- ul: {},
- ol: { attributes: [ 'type', 'start', 'reversed' ] },
- };
-
- // Recursion is needed.
- // Possible: ul > li > ul.
- // Impossible: ul > ul.
- [ 'ul', 'ol' ].forEach( ( tag ) => {
- listContentSchema[ tag ].children = {
- li: {
- children: listContentSchema,
- },
- };
- } );
-
- return listContentSchema;
-}
-
-function getListContentFlat( blocks ) {
- return blocks.flatMap( ( { name, attributes, innerBlocks = [] } ) => {
- if ( name === 'core/list-item' ) {
- return [ attributes.content, ...getListContentFlat( innerBlocks ) ];
- }
- return getListContentFlat( innerBlocks );
- } );
-}
-
-const transforms = {
- from: [
- {
- type: 'block',
- isMultiBlock: true,
- blocks: [ 'core/paragraph', 'core/heading' ],
- transform: ( blockAttributes ) => {
- let childBlocks = [];
- if ( blockAttributes.length > 1 ) {
- childBlocks = blockAttributes.map( ( { content } ) => {
- return createBlock( 'core/list-item', { content } );
- } );
- } else if ( blockAttributes.length === 1 ) {
- const value = create( {
- html: blockAttributes[ 0 ].content,
- } );
- childBlocks = split( value, '\n' ).map( ( result ) => {
- return createBlock( 'core/list-item', {
- content: toHTMLString( { value: result } ),
- } );
- } );
- }
- return createBlock(
- 'core/list',
- {
- anchor: blockAttributes.anchor,
- },
- childBlocks
- );
- },
- },
- ...[ '*', '-' ].map( ( prefix ) => ( {
- type: 'prefix',
- prefix,
- transform( content ) {
- return createBlock( 'core/list', {}, [
- createBlock( 'core/list-item', { content } ),
- ] );
- },
- } ) ),
- ...[ '1.', '1)' ].map( ( prefix ) => ( {
- type: 'prefix',
- prefix,
- transform( content ) {
- return createBlock(
- 'core/list',
- {
- ordered: true,
- },
- [ createBlock( 'core/list-item', { content } ) ]
- );
- },
- } ) ),
- {
- type: 'raw',
- selector: 'ol,ul',
- schema: ( args ) => ( {
- ol: getListContentSchema( args ).ol,
- ul: getListContentSchema( args ).ul,
- } ),
- transform: createListBlockFromDOMElement,
- },
- ],
- to: [
- ...[ 'core/paragraph', 'core/heading' ].map( ( block ) => ( {
- type: 'block',
- blocks: [ block ],
- transform: ( _attributes, childBlocks ) => {
- return getListContentFlat( childBlocks ).map( ( content ) =>
- createBlock( block, {
- content,
- } )
- );
- },
- } ) ),
- ],
-};
-
-export default transforms;
diff --git a/packages/blocks/src/api/raw-handling/paste-handler.js b/packages/blocks/src/api/raw-handling/paste-handler.js
index a8edd9347d7b9..d0193bc87eb74 100644
--- a/packages/blocks/src/api/raw-handling/paste-handler.js
+++ b/packages/blocks/src/api/raw-handling/paste-handler.js
@@ -226,8 +226,9 @@ export function pasteHandler( {
blocks.length === 1 &&
hasBlockSupport( blocks[ 0 ].name, '__unstablePasteTextInline', false )
) {
+ const trimRegex = /^[\n]+|[\n]+$/g;
// Don't catch line breaks at the start or end.
- const trimmedPlainText = plainText.replace( /^[\n]+|[\n]+$/g, '' );
+ const trimmedPlainText = plainText.replace( trimRegex, '' );
if (
trimmedPlainText !== '' &&
@@ -236,7 +237,7 @@ export function pasteHandler( {
return removeInvalidHTML(
getBlockInnerHTML( blocks[ 0 ] ),
phrasingContentSchema
- );
+ ).replace( trimRegex, '' );
}
}
diff --git a/packages/e2e-tests/specs/editor/plugins/__snapshots__/cpt-locking.test.js.snap b/packages/e2e-tests/specs/editor/plugins/__snapshots__/cpt-locking.test.js.snap
index fcacbe069610c..f12d66f3f2f33 100644
--- a/packages/e2e-tests/specs/editor/plugins/__snapshots__/cpt-locking.test.js.snap
+++ b/packages/e2e-tests/specs/editor/plugins/__snapshots__/cpt-locking.test.js.snap
@@ -84,7 +84,9 @@ exports[`cpt locking template_lock false should allow blocks to be inserted 1`]
-
+
"
`;
diff --git a/packages/e2e-tests/specs/editor/plugins/inner-blocks-allowed-blocks.test.js b/packages/e2e-tests/specs/editor/plugins/inner-blocks-allowed-blocks.test.js
index 3cbb2312ad946..e5e1854cc1708 100644
--- a/packages/e2e-tests/specs/editor/plugins/inner-blocks-allowed-blocks.test.js
+++ b/packages/e2e-tests/specs/editor/plugins/inner-blocks-allowed-blocks.test.js
@@ -75,6 +75,9 @@ describe( 'Allowed Blocks Setting on InnerBlocks', () => {
await page.$x( `//button//span[contains(text(), 'List')]` )
)[ 0 ];
await insertButton.click();
+ // Select the list wrapper so the image is inserable.
+ await page.keyboard.press( 'ArrowUp' );
+ await page.keyboard.press( 'ArrowUp' );
await insertBlock( 'Image' );
await closeGlobalBlockInserter();
await page.waitForSelector( '.product[data-number-of-children="2"]' );
diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/block-deletion.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/block-deletion.test.js.snap
index a433a325d2a92..8b0dcaec4067f 100644
--- a/packages/e2e-tests/specs/editor/various/__snapshots__/block-deletion.test.js.snap
+++ b/packages/e2e-tests/specs/editor/various/__snapshots__/block-deletion.test.js.snap
@@ -24,7 +24,9 @@ exports[`block deletion - deleting the third and fourth blocks using backspace w
-
+
"
`;
diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/keep-styles-on-block-transforms.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/keep-styles-on-block-transforms.test.js.snap
index c8ec4b42cb346..126fda3cc96e3 100644
--- a/packages/e2e-tests/specs/editor/various/__snapshots__/keep-styles-on-block-transforms.test.js.snap
+++ b/packages/e2e-tests/specs/editor/various/__snapshots__/keep-styles-on-block-transforms.test.js.snap
@@ -6,12 +6,6 @@ exports[`Keep styles on block transforms Should keep colors during a transform 1
"
`;
-exports[`Keep styles on block transforms Should keep the font size during a transform from multiple blocks into a single one 1`] = `
-"
-- Line 1 to be made large
- Line 2 to be made large
- Line 3 to be made large
-"
-`;
-
exports[`Keep styles on block transforms Should keep the font size during a transform from multiple blocks into multiple blocks 1`] = `
"
Line 1 to be made large
diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/multi-block-selection.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/multi-block-selection.test.js.snap
index de86d82627bf0..51e7f452082d8 100644
--- a/packages/e2e-tests/specs/editor/various/__snapshots__/multi-block-selection.test.js.snap
+++ b/packages/e2e-tests/specs/editor/various/__snapshots__/multi-block-selection.test.js.snap
@@ -152,7 +152,9 @@ exports[`Multi-block selection should multi-select from within the list block 1`
-
+
"
`;
@@ -248,6 +250,28 @@ exports[`Multi-block selection should preserve dragged selection on move 1`] = `
"
`;
+exports[`Multi-block selection should properly select multiple blocks if selected nested blocks belong to different parent 1`] = `
+"
+
+
+
+
+
+"
+`;
+
exports[`Multi-block selection should return original focus after failed multi selection attempt 1`] = `
"
2
diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/rich-text.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/rich-text.test.js.snap
index 92baa3662c13e..074158c55f096 100644
--- a/packages/e2e-tests/specs/editor/various/__snapshots__/rich-text.test.js.snap
+++ b/packages/e2e-tests/specs/editor/various/__snapshots__/rich-text.test.js.snap
@@ -102,12 +102,24 @@ exports[`RichText should only mutate text data on input 1`] = `
exports[`RichText should paste list contents into paragraph 1`] = `
"
-
+
-
-1
2
-"
+
+
+"
`;
exports[`RichText should paste paragraph contents into list 1`] = `
@@ -116,7 +128,9 @@ exports[`RichText should paste paragraph contents into list 1`] = `
-
+
"
`;
diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/writing-flow.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/writing-flow.test.js.snap
index 37328170c07e1..e0425d7d46d74 100644
--- a/packages/e2e-tests/specs/editor/various/__snapshots__/writing-flow.test.js.snap
+++ b/packages/e2e-tests/specs/editor/various/__snapshots__/writing-flow.test.js.snap
@@ -24,16 +24,6 @@ exports[`Writing Flow Should navigate inner blocks with arrow keys 1`] = `
"
`;
-exports[`Writing Flow should allow selecting entire list with longer last item 1`] = `
-"
-a
-
-
-
-
-"
-`;
-
exports[`Writing Flow should create valid paragraph blocks when rapidly pressing Enter 1`] = `
"
@@ -208,7 +198,9 @@ exports[`Writing Flow should navigate empty paragraphs 1`] = `
exports[`Writing Flow should not create extra line breaks in multiline value 1`] = `
"
-
+
"
`;
diff --git a/packages/e2e-tests/specs/editor/various/block-switcher.test.js b/packages/e2e-tests/specs/editor/various/block-switcher.test.js
index 1b82f1f23ad02..d4029557e5120 100644
--- a/packages/e2e-tests/specs/editor/various/block-switcher.test.js
+++ b/packages/e2e-tests/specs/editor/various/block-switcher.test.js
@@ -18,6 +18,8 @@ describe( 'Block Switcher', () => {
// Insert a list block.
await insertBlock( 'List' );
await page.keyboard.type( 'List content' );
+ await page.keyboard.press( 'ArrowUp' );
+ await page.keyboard.press( 'ArrowUp' );
await pressKeyWithModifier( 'alt', 'F10' );
// Verify the block switcher exists.
@@ -31,7 +33,6 @@ describe( 'Block Switcher', () => {
'Heading',
'Quote',
'Columns',
- 'Table of Contents',
] )
);
} );
@@ -45,6 +46,8 @@ describe( 'Block Switcher', () => {
// Insert a list block.
await insertBlock( 'List' );
await page.keyboard.type( 'List content' );
+ await page.keyboard.press( 'ArrowUp' );
+ await page.keyboard.press( 'ArrowUp' );
await pressKeyWithModifier( 'alt', 'F10' );
// Verify the block switcher exists.
@@ -56,7 +59,7 @@ describe( 'Block Switcher', () => {
'Group',
'Paragraph',
'Heading',
- 'Table of Contents',
+ 'Columns',
] )
);
} );
@@ -71,13 +74,14 @@ describe( 'Block Switcher', () => {
'core/group',
'core/heading',
'core/columns',
- 'core/table-of-contents',
].map( ( block ) => wp.blocks.unregisterBlockType( block ) );
} );
// Insert a list block.
await insertBlock( 'List' );
await page.keyboard.type( 'List content' );
+ await page.keyboard.press( 'ArrowUp' );
+ await page.keyboard.press( 'ArrowUp' );
await pressKeyWithModifier( 'alt', 'F10' );
// Verify the block switcher exists.
@@ -91,6 +95,8 @@ describe( 'Block Switcher', () => {
it( 'Should show Columns block only if selected blocks are between limits (1-6)', async () => {
await insertBlock( 'List' );
await page.keyboard.type( 'List content' );
+ await page.keyboard.press( 'ArrowUp' );
+ await page.keyboard.press( 'ArrowUp' );
await insertBlock( 'Heading' );
await page.keyboard.type( 'I am a header' );
await page.keyboard.down( 'Shift' );
@@ -103,6 +109,8 @@ describe( 'Block Switcher', () => {
it( 'Should NOT show Columns transform only if selected blocks are more than max limit(6)', async () => {
await insertBlock( 'List' );
await page.keyboard.type( 'List content' );
+ await page.keyboard.press( 'ArrowUp' );
+ await page.keyboard.press( 'ArrowUp' );
await insertBlock( 'Heading' );
await page.keyboard.type( 'I am a header' );
await page.keyboard.press( 'Enter' );
diff --git a/packages/e2e-tests/specs/editor/various/keep-styles-on-block-transforms.test.js b/packages/e2e-tests/specs/editor/various/keep-styles-on-block-transforms.test.js
index 1443b49e5131b..56b2ea6263d92 100644
--- a/packages/e2e-tests/specs/editor/various/keep-styles-on-block-transforms.test.js
+++ b/packages/e2e-tests/specs/editor/various/keep-styles-on-block-transforms.test.js
@@ -34,23 +34,6 @@ describe( 'Keep styles on block transforms', () => {
expect( await getEditedPostContent() ).toMatchSnapshot();
} );
- it( 'Should keep the font size during a transform from multiple blocks into a single one', async () => {
- // Create a paragraph block with some content.
- await clickBlockAppender();
- await page.keyboard.type( 'Line 1 to be made large' );
- await page.keyboard.press( 'Enter' );
- await page.keyboard.type( 'Line 2 to be made large' );
- await page.keyboard.press( 'Enter' );
- await page.keyboard.type( 'Line 3 to be made large' );
- await pressKeyWithModifier( 'shift', 'ArrowUp' );
- await pressKeyWithModifier( 'shift', 'ArrowUp' );
- await page.click(
- '[role="radiogroup"][aria-label="Font size"] [aria-label="Large"]'
- );
- await transformBlockTo( 'List' );
- expect( await getEditedPostContent() ).toMatchSnapshot();
- } );
-
it( 'Should keep the font size during a transform from multiple blocks into multiple blocks', async () => {
// Create a paragraph block with some content.
await clickBlockAppender();
diff --git a/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js b/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js
index 33d7295a4ab46..a5954796bff9e 100644
--- a/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js
+++ b/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js
@@ -331,6 +331,9 @@ describe( 'Multi-block selection', () => {
await page.keyboard.up( 'Shift' );
await transformBlockTo( 'Group' );
+ // Confirm setup.
+ expect( await getEditedPostContent() ).toMatchSnapshot();
+
// Click the first paragraph in the first Group block while pressing `shift` key.
const firstParagraph = await page.waitForXPath( "//p[text()='first']" );
await page.keyboard.down( 'Shift' );
@@ -676,6 +679,10 @@ describe( 'Multi-block selection', () => {
await pressKeyWithModifier( 'primary', 'a' );
+ await page.waitForSelector( '[data-type="core/column"].is-selected' );
+
+ await pressKeyWithModifier( 'primary', 'a' );
+
await page.waitForSelector(
'[data-type="core/column"].is-multi-selected'
);
@@ -699,6 +706,7 @@ describe( 'Multi-block selection', () => {
// Confirm correct setup: a paragraph and a list.
expect( await getEditedPostContent() ).toMatchSnapshot();
+ await pressKeyWithModifier( 'primary', 'a' );
await pressKeyWithModifier( 'primary', 'a' );
await pressKeyWithModifier( 'primary', 'a' );
diff --git a/packages/e2e-tests/specs/editor/various/rich-text.test.js b/packages/e2e-tests/specs/editor/various/rich-text.test.js
index 4d8b899eafbad..f4d8e0d391721 100644
--- a/packages/e2e-tests/specs/editor/various/rich-text.test.js
+++ b/packages/e2e-tests/specs/editor/various/rich-text.test.js
@@ -473,15 +473,18 @@ describe( 'RichText', () => {
await page.keyboard.press( 'Enter' );
await page.keyboard.type( ' 2' );
- // Select all and copy.
+ // Select all text.
+ await pressKeyWithModifier( 'primary', 'a' );
+ // Select the nested list.
+ await pressKeyWithModifier( 'primary', 'a' );
+ // Select the parent list item.
+ await pressKeyWithModifier( 'primary', 'a' );
+ // Select all the parent list item text.
+ await pressKeyWithModifier( 'primary', 'a' );
+ // Select the entire list.
await pressKeyWithModifier( 'primary', 'a' );
await pressKeyWithModifier( 'primary', 'c' );
- // Collapse the selection to the end.
- await page.keyboard.press( 'ArrowRight' );
-
- // Create a paragraph.
- await page.keyboard.press( 'Enter' );
await page.keyboard.press( 'Enter' );
// Paste paragraph contents.
diff --git a/packages/e2e-tests/specs/editor/various/splitting-merging.test.js b/packages/e2e-tests/specs/editor/various/splitting-merging.test.js
index 8ff33dfcc233b..c3c47706af9c2 100644
--- a/packages/e2e-tests/specs/editor/various/splitting-merging.test.js
+++ b/packages/e2e-tests/specs/editor/various/splitting-merging.test.js
@@ -235,7 +235,7 @@ describe( 'splitting and merging blocks', () => {
await page.keyboard.type( 'item 1' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( 'item 2' );
- await pressKeyTimes( 'ArrowUp', 2 );
+ await pressKeyTimes( 'ArrowUp', 5 );
await page.keyboard.press( 'Delete' );
// Carret should be in the first block and at the proper position.
await page.keyboard.type( '-' );
@@ -257,13 +257,18 @@ describe( 'splitting and merging blocks', () => {
await page.keyboard.press( 'Enter' );
await page.keyboard.type( 'item 2' );
await page.keyboard.press( 'ArrowUp' );
+ await page.keyboard.press( 'ArrowUp' );
await pressKeyTimes( 'ArrowLeft', 6 );
await page.keyboard.press( 'Backspace' );
// Carret should be in the first block and at the proper position.
await page.keyboard.type( '-' );
expect( await getEditedPostContent() ).toMatchInlineSnapshot( `
"
- hi-item 1
+ hi
+
+
+
+ -item 1
diff --git a/packages/e2e-tests/specs/editor/various/toolbar-roving-tabindex.test.js b/packages/e2e-tests/specs/editor/various/toolbar-roving-tabindex.test.js
index 87869b3354409..d131ddbbe0742 100644
--- a/packages/e2e-tests/specs/editor/various/toolbar-roving-tabindex.test.js
+++ b/packages/e2e-tests/specs/editor/various/toolbar-roving-tabindex.test.js
@@ -86,7 +86,8 @@ describe( 'Toolbar roving tabindex', () => {
it( 'ensures list block toolbar uses roving tabindex', async () => {
await insertBlock( 'List' );
await page.keyboard.type( 'List' );
- await testBlockToolbarKeyboardNavigation( 'Block: List', 'List' );
+ await testBlockToolbarKeyboardNavigation( 'List text', 'Select List' );
+ await page.click( `[aria-label="Select List"]` );
await wrapCurrentBlockWithGroup( 'List' );
await testGroupKeyboardNavigation( 'Block: List', 'List' );
} );
diff --git a/packages/e2e-tests/specs/editor/various/writing-flow.test.js b/packages/e2e-tests/specs/editor/various/writing-flow.test.js
index 322f64f0fcffe..2a918c4d2a1db 100644
--- a/packages/e2e-tests/specs/editor/various/writing-flow.test.js
+++ b/packages/e2e-tests/specs/editor/various/writing-flow.test.js
@@ -570,21 +570,25 @@ describe( 'Writing Flow', () => {
expect( await getEditedPostContent() ).toMatchSnapshot();
} );
- it( 'should allow selecting entire list with longer last item', async () => {
+ it( 'should extend selection into paragraph for list with longer last item', async () => {
await page.keyboard.press( 'Enter' );
await page.keyboard.type( 'a' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( '* b' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( 'cd' );
+
+ // Selects part of the first list item, although invisible.
await pressKeyWithModifier( 'shift', 'ArrowUp' );
+ await page.evaluate( () => new Promise( window.requestIdleCallback ) );
+ // Extends selection into the first paragraph
await pressKeyWithModifier( 'shift', 'ArrowUp' );
+ await page.evaluate( () => new Promise( window.requestIdleCallback ) );
- // Ensure multi selection is not triggered and selection stays within
- // the list.
+ // Mixed selection, so all content will be removed.
await page.keyboard.press( 'Backspace' );
- expect( await getEditedPostContent() ).toMatchSnapshot();
+ expect( await getEditedPostContent() ).toBe( '' );
} );
it( 'should not have a dead zone between blocks (lower)', async () => {
diff --git a/packages/react-native-editor/src/setup.js b/packages/react-native-editor/src/setup.js
index 47c9bd501386f..912efeaee94b9 100644
--- a/packages/react-native-editor/src/setup.js
+++ b/packages/react-native-editor/src/setup.js
@@ -59,11 +59,8 @@ const gutenbergSetup = () => {
const setupInitHooks = () => {
addAction( 'native.pre-render', 'core/react-native-editor', ( props ) => {
const capabilities = props.capabilities ?? {};
- const blocksFlags = {
- __experimentalEnableListBlockV2: props?.listBlockV2,
- };
- registerBlocks( blocksFlags );
+ registerBlocks();
// Unregister non-supported blocks by capabilities
if (
@@ -121,12 +118,12 @@ const setupInitHooks = () => {
};
let blocksRegistered = false;
-const registerBlocks = ( blocksFlags ) => {
+const registerBlocks = () => {
if ( blocksRegistered ) {
return;
}
- registerCoreBlocks( blocksFlags );
+ registerCoreBlocks();
blocksRegistered = true;
};
diff --git a/test/e2e/specs/editor/blocks/list.spec.js b/test/e2e/specs/editor/blocks/list.spec.js
index 99f60ae49693b..7545056812614 100644
--- a/test/e2e/specs/editor/blocks/list.spec.js
+++ b/test/e2e/specs/editor/blocks/list.spec.js
@@ -21,7 +21,13 @@ test.describe( 'List', () => {
await page.keyboard.type( 'Another list item' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-- A list item
- Another list item
+
+- A list item
+
+
+
+- Another list item
+
`
);
} );
@@ -38,7 +44,9 @@ test.describe( 'List', () => {
await page.keyboard.type( '* ' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
@@ -53,7 +61,9 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-- A list item
+
+- A list item
+
`
);
} );
@@ -170,7 +180,6 @@ test.describe( 'List', () => {
page,
} ) => {
await page.click( 'role=button[name="Add default block"i]' );
- await page.keyboard.press( 'Enter' );
await page.keyboard.type( '* ' );
await expect( page.locator( '[data-type="core/list"]' ) ).toBeVisible();
await page.keyboard.press( 'ArrowUp' );
@@ -192,7 +201,9 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
@@ -207,7 +218,9 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
@@ -227,7 +240,13 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
@@ -245,7 +264,13 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
@@ -268,7 +293,13 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
@@ -278,6 +309,7 @@ test.describe( 'List', () => {
await page.keyboard.type( 'one' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( 'two' );
+ await editor.clickBlockToolbarButton( 'Select List' );
await editor.transformBlockTo( 'core/paragraph' );
await expect.poll( editor.getEditedPostContent ).toBe(
@@ -294,12 +326,14 @@ test.describe( 'List', () => {
test( 'can be converted when nested to paragraphs', async ( {
editor,
page,
+ pageUtils,
} ) => {
await editor.insertBlock( { name: 'core/list' } );
await page.keyboard.type( 'one' );
await page.keyboard.press( 'Enter' );
await editor.clickBlockToolbarButton( 'Indent' );
await page.keyboard.type( 'two' );
+ await pageUtils.pressKeyTimes( 'ArrowUp', 5 );
await editor.transformBlockTo( 'core/paragraph' );
await expect.poll( editor.getEditedPostContent ).toBe(
@@ -318,12 +352,19 @@ test.describe( 'List', () => {
await page.keyboard.type( 'one' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( 'two' );
+ await editor.clickBlockToolbarButton( 'Select List' );
await editor.transformBlockTo( 'core/quote' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
@@ -341,7 +382,9 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
@@ -355,7 +398,13 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
@@ -370,11 +419,22 @@ test.describe( 'List', () => {
await page.keyboard.press( 'Enter' );
await page.keyboard.type( 'two' );
await page.keyboard.press( 'ArrowUp' );
+ await page.keyboard.press( 'ArrowUp' );
await page.keyboard.press( 'Enter' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
+- one
+
+
+
+
+
+
+
+- two
+
`
);
@@ -382,7 +442,9 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
@@ -390,7 +452,9 @@ test.describe( 'List', () => {
-
+
`
);
@@ -403,11 +467,19 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
-
+
`
);
} );
@@ -421,12 +493,15 @@ test.describe( 'List', () => {
await page.keyboard.press( 'Enter' );
await page.keyboard.type( 'two' );
await page.keyboard.press( 'ArrowUp' );
+ await page.keyboard.press( 'ArrowUp' );
await page.keyboard.press( 'Enter' );
await page.keyboard.press( 'Enter' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-- one
+
+- one
+
@@ -434,7 +509,9 @@ test.describe( 'List', () => {
-- two
+
+- two
+
`
);
} );
@@ -450,7 +527,17 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
@@ -458,26 +545,34 @@ test.describe( 'List', () => {
test( 'should be immeadiately saved on indentation', async ( {
editor,
page,
- pageUtils,
} ) => {
await editor.insertBlock( { name: 'core/list' } );
await page.keyboard.type( 'one' );
await page.keyboard.press( 'Enter' );
- await pageUtils.pressKeyWithModifier( 'primary', 'm' );
+ await editor.clickBlockToolbarButton( 'Indent' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
test( 'should change the base list type', async ( { editor } ) => {
await editor.insertBlock( { name: 'core/list' } );
+ await editor.clickBlockToolbarButton( 'Select List' );
await editor.clickBlockToolbarButton( 'Ordered' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
+
+
`
);
} );
@@ -485,82 +580,124 @@ test.describe( 'List', () => {
test( 'should change the indented list type', async ( {
editor,
page,
- pageUtils,
} ) => {
await editor.insertBlock( { name: 'core/list' } );
await page.keyboard.type( 'a' );
await page.keyboard.press( 'Enter' );
- await pageUtils.pressKeyWithModifier( 'primary', 'm' );
+ await editor.clickBlockToolbarButton( 'Indent' );
await page.keyboard.type( '1' );
-
+ await editor.clickBlockToolbarButton( 'Select List' );
await editor.clickBlockToolbarButton( 'Ordered' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
- test( 'should indent and outdent level 1', async ( {
- editor,
- page,
- pageUtils,
- } ) => {
+ test( 'should indent and outdent level 1', async ( { editor, page } ) => {
await editor.insertBlock( { name: 'core/list' } );
await page.keyboard.type( 'a' );
await page.keyboard.press( 'Enter' );
- await pageUtils.pressKeyWithModifier( 'primary', 'm' );
+ await editor.clickBlockToolbarButton( 'Indent' );
await page.keyboard.type( '1' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
- await pageUtils.pressKeyWithModifier( 'primaryShift', 'm' );
+ await editor.clickBlockToolbarButton( 'Outdent' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
- test( 'should indent and outdent level 2', async ( {
- editor,
- page,
- pageUtils,
- } ) => {
+ test( 'should indent and outdent level 2', async ( { editor, page } ) => {
await editor.insertBlock( { name: 'core/list' } );
await page.keyboard.type( 'a' );
await page.keyboard.press( 'Enter' );
- await pageUtils.pressKeyWithModifier( 'primary', 'm' );
+ await editor.clickBlockToolbarButton( 'Indent' );
await page.keyboard.type( '1' );
await page.keyboard.press( 'Enter' );
- await pageUtils.pressKeyWithModifier( 'primary', 'm' );
+ await editor.clickBlockToolbarButton( 'Indent' );
await page.keyboard.type( 'i' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
- await pageUtils.pressKeyWithModifier( 'primaryShift', 'm' );
+ await editor.clickBlockToolbarButton( 'Outdent' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
- await pageUtils.pressKeyWithModifier( 'primaryShift', 'm' );
+ // To do: investigate why the toolbar is not showing up right after
+ // outdenting.
+ await page.keyboard.press( 'ArrowUp' );
+ await editor.clickBlockToolbarButton( 'Outdent' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
@@ -573,24 +710,44 @@ test.describe( 'List', () => {
await editor.insertBlock( { name: 'core/list' } );
await page.keyboard.type( 'a' );
await page.keyboard.press( 'Enter' );
- await pageUtils.pressKeyWithModifier( 'primary', 'm' );
+ await editor.clickBlockToolbarButton( 'Indent' );
await page.keyboard.type( 'b' );
await page.keyboard.press( 'Enter' );
- await pageUtils.pressKeyWithModifier( 'primary', 'm' );
+ await editor.clickBlockToolbarButton( 'Indent' );
await page.keyboard.type( 'c' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
- await page.keyboard.press( 'ArrowUp' );
- await pageUtils.pressKeyWithModifier( 'primaryShift', 'm' );
+ await pageUtils.pressKeyTimes( 'ArrowUp', 3 );
+ await editor.clickBlockToolbarButton( 'Outdent' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
@@ -606,7 +763,9 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
@@ -623,11 +782,22 @@ test.describe( 'List', () => {
await page.keyboard.press( 'Enter' );
await page.keyboard.type( 'c' );
await page.keyboard.press( 'ArrowUp' );
+ await page.keyboard.press( 'ArrowUp' );
await pageUtils.pressKeyWithModifier( 'shift', 'Enter' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
@@ -646,7 +816,17 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
@@ -655,7 +835,17 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
@@ -663,7 +853,17 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
@@ -671,7 +871,13 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
@@ -680,7 +886,13 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
@@ -688,7 +900,9 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
@@ -704,19 +918,30 @@ test.describe( 'List', () => {
test( 'should place the caret in the right place with nested list', async ( {
editor,
page,
+ pageUtils,
} ) => {
await page.click( 'role=button[name="Add default block"i]' );
await page.keyboard.type( '* 1' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( ' a' );
- await page.keyboard.press( 'ArrowUp' );
+ await pageUtils.pressKeyTimes( 'ArrowUp', 3 );
await page.keyboard.press( 'Enter' );
// The caret should land in the second item.
await page.keyboard.type( '2' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
@@ -734,7 +959,13 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
@@ -778,7 +1009,17 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
@@ -793,7 +1034,17 @@ test.describe( 'List', () => {
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
@@ -807,13 +1058,18 @@ test.describe( 'List', () => {
await page.keyboard.press( 'Enter' );
await page.keyboard.type( '2' );
await page.keyboard.press( 'ArrowUp' );
+ await page.keyboard.press( 'ArrowUp' );
await page.keyboard.press( 'Backspace' );
await page.keyboard.press( 'Backspace' );
await expect.poll( editor.getEditedPostContent ).toBe(
- `
-
-`
+ `
+
+
+
+
+2
+`
);
} );
@@ -827,11 +1083,22 @@ test.describe( 'List', () => {
await page.keyboard.type( '2' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( '3' );
+ await editor.clickBlockToolbarButton( 'Select List' );
await editor.clickBlockToolbarButton( 'Ordered' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-- 1
- 2
- 3
+
+- 1
+
+
+
+- 2
+
+
+
+- 3
+
`
);
} );
@@ -846,11 +1113,22 @@ test.describe( 'List', () => {
await page.keyboard.type( 'b' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( 'c' );
+ await editor.clickBlockToolbarButton( 'Select List' );
await editor.clickBlockToolbarButton( 'Unordered' );
await expect.poll( editor.getEditedPostContent ).toBe(
`
-
+
`
);
} );
diff --git a/test/integration/__snapshots__/blocks-raw-handling.test.js.snap b/test/integration/__snapshots__/blocks-raw-handling.test.js.snap
index 06f7a8d80716b..6c341c815e035 100644
--- a/test/integration/__snapshots__/blocks-raw-handling.test.js.snap
+++ b/test/integration/__snapshots__/blocks-raw-handling.test.js.snap
@@ -85,7 +85,9 @@ exports[`rawHandler should convert HTML post to blocks with minimal content chan
-- Item
+
+- Item
+
@@ -125,11 +127,13 @@ exports[`rawHandler should convert a caption shortcode with link 1`] = `
exports[`rawHandler should convert a list with attributes 1`] = `
"
-- 1
-
- - 1
-
-
+
+- 1
+
+- 1
+
+
+
"
`;
diff --git a/test/integration/blocks-raw-handling.test.js b/test/integration/blocks-raw-handling.test.js
index 1586b858c227e..4a5d7bd584c85 100644
--- a/test/integration/blocks-raw-handling.test.js
+++ b/test/integration/blocks-raw-handling.test.js
@@ -176,9 +176,19 @@ describe( 'Blocks raw handling', () => {
.map( getBlockContent )
.join( '' );
- expect( filtered ).toBe(
- ''
- );
+ expect( filtered ).toMatchInlineSnapshot( `
+ "
+ - one
+
+
+
+ - two
+
+
+
+ - three
+
"
+ ` );
expect( console ).toHaveLogged();
} );
@@ -282,9 +292,19 @@ describe( 'Blocks raw handling', () => {
.map( getBlockContent )
.join( '' );
- expect( filtered ).toBe(
- ''
- );
+ expect( filtered ).toMatchInlineSnapshot( `
+ "
+ - One
+
+
+
+ - Two
+
+
+
+ - Three
+
"
+ ` );
expect( console ).toHaveLogged();
} );
diff --git a/test/integration/fixtures/blocks/core__list-item.html b/test/integration/fixtures/blocks/core__list-item.html
new file mode 100644
index 0000000000000..abeec57ef9198
--- /dev/null
+++ b/test/integration/fixtures/blocks/core__list-item.html
@@ -0,0 +1,3 @@
+
+Text & Headings
+
diff --git a/test/integration/fixtures/blocks/core__list-item.json b/test/integration/fixtures/blocks/core__list-item.json
new file mode 100644
index 0000000000000..5110b465157a3
--- /dev/null
+++ b/test/integration/fixtures/blocks/core__list-item.json
@@ -0,0 +1,10 @@
+[
+ {
+ "name": "core/list-item",
+ "isValid": true,
+ "attributes": {
+ "content": "Text & Headings"
+ },
+ "innerBlocks": []
+ }
+]
diff --git a/test/integration/fixtures/blocks/core__list-item.parsed.json b/test/integration/fixtures/blocks/core__list-item.parsed.json
new file mode 100644
index 0000000000000..29966c6490c59
--- /dev/null
+++ b/test/integration/fixtures/blocks/core__list-item.parsed.json
@@ -0,0 +1,9 @@
+[
+ {
+ "blockName": "core/list-item",
+ "attrs": {},
+ "innerBlocks": [],
+ "innerHTML": "\nText & Headings\n",
+ "innerContent": [ "\nText & Headings\n" ]
+ }
+]
diff --git a/test/integration/fixtures/blocks/core__list-item.serialized.html b/test/integration/fixtures/blocks/core__list-item.serialized.html
new file mode 100644
index 0000000000000..abeec57ef9198
--- /dev/null
+++ b/test/integration/fixtures/blocks/core__list-item.serialized.html
@@ -0,0 +1,3 @@
+
+Text & Headings
+
diff --git a/test/integration/fixtures/blocks/core__list__deprecated-v0.html b/test/integration/fixtures/blocks/core__list__deprecated-v0.html
new file mode 100644
index 0000000000000..eb8ea358a2ef6
--- /dev/null
+++ b/test/integration/fixtures/blocks/core__list__deprecated-v0.html
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/test/integration/fixtures/blocks/core__list__deprecated-v0.json b/test/integration/fixtures/blocks/core__list__deprecated-v0.json
new file mode 100644
index 0000000000000..80712db768d4c
--- /dev/null
+++ b/test/integration/fixtures/blocks/core__list__deprecated-v0.json
@@ -0,0 +1,37 @@
+[
+ {
+ "name": "core/list",
+ "isValid": true,
+ "attributes": {
+ "ordered": false,
+ "values": "onetwothree",
+ "fontFamily": "cambria-georgia"
+ },
+ "innerBlocks": [
+ {
+ "name": "core/list-item",
+ "isValid": true,
+ "attributes": {
+ "content": "one"
+ },
+ "innerBlocks": []
+ },
+ {
+ "name": "core/list-item",
+ "isValid": true,
+ "attributes": {
+ "content": "two"
+ },
+ "innerBlocks": []
+ },
+ {
+ "name": "core/list-item",
+ "isValid": true,
+ "attributes": {
+ "content": "three"
+ },
+ "innerBlocks": []
+ }
+ ]
+ }
+]
diff --git a/test/integration/fixtures/blocks/core__list__deprecated-v0.parsed.json b/test/integration/fixtures/blocks/core__list__deprecated-v0.parsed.json
new file mode 100644
index 0000000000000..d76f8e369efe4
--- /dev/null
+++ b/test/integration/fixtures/blocks/core__list__deprecated-v0.parsed.json
@@ -0,0 +1,17 @@
+[
+ {
+ "blockName": "core/list",
+ "attrs": {
+ "style": {
+ "typography": {
+ "fontFamily": "var:preset|font-family|cambria-georgia"
+ }
+ }
+ },
+ "innerBlocks": [],
+ "innerHTML": "\n\n",
+ "innerContent": [
+ "\n\n"
+ ]
+ }
+]
diff --git a/test/integration/fixtures/blocks/core__list__deprecated-v0.serialized.html b/test/integration/fixtures/blocks/core__list__deprecated-v0.serialized.html
new file mode 100644
index 0000000000000..fa50fb5db17e7
--- /dev/null
+++ b/test/integration/fixtures/blocks/core__list__deprecated-v0.serialized.html
@@ -0,0 +1,13 @@
+
+
+- one
+
+
+
+- two
+
+
+
+- three
+
+
diff --git a/test/integration/fixtures/blocks/core__list__deprecated-v1.html b/test/integration/fixtures/blocks/core__list__deprecated-v1.html
index eb8ea358a2ef6..aef6bf669f2c9 100644
--- a/test/integration/fixtures/blocks/core__list__deprecated-v1.html
+++ b/test/integration/fixtures/blocks/core__list__deprecated-v1.html
@@ -1,3 +1,3 @@
-
-
-
\ No newline at end of file
+
+- Text & Headings
- Images & Videos
- Galleries
- Embeds, like YouTube, Tweets, or other WordPress posts.
- Layout blocks, like Buttons, Hero Images, Separators, etc.
- And Lists like this one of course :)
+
diff --git a/test/integration/fixtures/blocks/core__list__deprecated-v1.json b/test/integration/fixtures/blocks/core__list__deprecated-v1.json
index ca57dca6e8021..80cd87e4eb69e 100644
--- a/test/integration/fixtures/blocks/core__list__deprecated-v1.json
+++ b/test/integration/fixtures/blocks/core__list__deprecated-v1.json
@@ -4,9 +4,57 @@
"isValid": true,
"attributes": {
"ordered": false,
- "values": "onetwothree",
- "fontFamily": "cambria-georgia"
+ "values": ""
},
- "innerBlocks": []
+ "innerBlocks": [
+ {
+ "name": "core/list-item",
+ "isValid": true,
+ "attributes": {
+ "content": "Text & Headings"
+ },
+ "innerBlocks": []
+ },
+ {
+ "name": "core/list-item",
+ "isValid": true,
+ "attributes": {
+ "content": "Images & Videos"
+ },
+ "innerBlocks": []
+ },
+ {
+ "name": "core/list-item",
+ "isValid": true,
+ "attributes": {
+ "content": "Galleries"
+ },
+ "innerBlocks": []
+ },
+ {
+ "name": "core/list-item",
+ "isValid": true,
+ "attributes": {
+ "content": "Embeds, like YouTube, Tweets, or other WordPress posts."
+ },
+ "innerBlocks": []
+ },
+ {
+ "name": "core/list-item",
+ "isValid": true,
+ "attributes": {
+ "content": "Layout blocks, like Buttons, Hero Images, Separators, etc."
+ },
+ "innerBlocks": []
+ },
+ {
+ "name": "core/list-item",
+ "isValid": true,
+ "attributes": {
+ "content": "And Lists like this one of course :)"
+ },
+ "innerBlocks": []
+ }
+ ]
}
]
diff --git a/test/integration/fixtures/blocks/core__list__deprecated-v1.parsed.json b/test/integration/fixtures/blocks/core__list__deprecated-v1.parsed.json
index d76f8e369efe4..427f4c3a975cf 100644
--- a/test/integration/fixtures/blocks/core__list__deprecated-v1.parsed.json
+++ b/test/integration/fixtures/blocks/core__list__deprecated-v1.parsed.json
@@ -1,17 +1,11 @@
[
{
"blockName": "core/list",
- "attrs": {
- "style": {
- "typography": {
- "fontFamily": "var:preset|font-family|cambria-georgia"
- }
- }
- },
+ "attrs": {},
"innerBlocks": [],
- "innerHTML": "\n\n",
+ "innerHTML": "\n- Text & Headings
- Images & Videos
- Galleries
- Embeds, like YouTube, Tweets, or other WordPress posts.
- Layout blocks, like Buttons, Hero Images, Separators, etc.
- And Lists like this one of course :)
\n",
"innerContent": [
- "\n\n"
+ "\n- Text & Headings
- Images & Videos
- Galleries
- Embeds, like YouTube, Tweets, or other WordPress posts.
- Layout blocks, like Buttons, Hero Images, Separators, etc.
- And Lists like this one of course :)
\n"
]
}
]
diff --git a/test/integration/fixtures/blocks/core__list__deprecated-v1.serialized.html b/test/integration/fixtures/blocks/core__list__deprecated-v1.serialized.html
index 0eb7670601542..c09708d51db0b 100644
--- a/test/integration/fixtures/blocks/core__list__deprecated-v1.serialized.html
+++ b/test/integration/fixtures/blocks/core__list__deprecated-v1.serialized.html
@@ -1,3 +1,25 @@
-
-
+
+
+- Text & Headings
+
+
+
+- Images & Videos
+
+
+
+- Galleries
+
+
+
+- Embeds, like YouTube, Tweets, or other WordPress posts.
+
+
+
+- Layout blocks, like Buttons, Hero Images, Separators, etc.
+
+
+
+- And Lists like this one of course :)
+
diff --git a/test/integration/fixtures/blocks/core__list__ul.html b/test/integration/fixtures/blocks/core__list__ul.html
index aef6bf669f2c9..c09708d51db0b 100644
--- a/test/integration/fixtures/blocks/core__list__ul.html
+++ b/test/integration/fixtures/blocks/core__list__ul.html
@@ -1,3 +1,25 @@
-
-- Text & Headings
- Images & Videos
- Galleries
- Embeds, like YouTube, Tweets, or other WordPress posts.
- Layout blocks, like Buttons, Hero Images, Separators, etc.
- And Lists like this one of course :)
-
+
+
+- Text & Headings
+
+
+
+- Images & Videos
+
+
+
+- Galleries
+
+
+
+- Embeds, like YouTube, Tweets, or other WordPress posts.
+
+
+
+- Layout blocks, like Buttons, Hero Images, Separators, etc.
+
+
+
+- And Lists like this one of course :)
+
+
diff --git a/test/integration/fixtures/blocks/core__list__ul.json b/test/integration/fixtures/blocks/core__list__ul.json
index 841a5c5fd27eb..80cd87e4eb69e 100644
--- a/test/integration/fixtures/blocks/core__list__ul.json
+++ b/test/integration/fixtures/blocks/core__list__ul.json
@@ -4,8 +4,57 @@
"isValid": true,
"attributes": {
"ordered": false,
- "values": "Text & HeadingsImages & VideosGalleriesEmbeds, like YouTube, Tweets, or other WordPress posts.Layout blocks, like Buttons, Hero Images, Separators, etc.And Lists like this one of course :)"
+ "values": ""
},
- "innerBlocks": []
+ "innerBlocks": [
+ {
+ "name": "core/list-item",
+ "isValid": true,
+ "attributes": {
+ "content": "Text & Headings"
+ },
+ "innerBlocks": []
+ },
+ {
+ "name": "core/list-item",
+ "isValid": true,
+ "attributes": {
+ "content": "Images & Videos"
+ },
+ "innerBlocks": []
+ },
+ {
+ "name": "core/list-item",
+ "isValid": true,
+ "attributes": {
+ "content": "Galleries"
+ },
+ "innerBlocks": []
+ },
+ {
+ "name": "core/list-item",
+ "isValid": true,
+ "attributes": {
+ "content": "Embeds, like YouTube, Tweets, or other WordPress posts."
+ },
+ "innerBlocks": []
+ },
+ {
+ "name": "core/list-item",
+ "isValid": true,
+ "attributes": {
+ "content": "Layout blocks, like Buttons, Hero Images, Separators, etc."
+ },
+ "innerBlocks": []
+ },
+ {
+ "name": "core/list-item",
+ "isValid": true,
+ "attributes": {
+ "content": "And Lists like this one of course :)"
+ },
+ "innerBlocks": []
+ }
+ ]
}
]
diff --git a/test/integration/fixtures/blocks/core__list__ul.parsed.json b/test/integration/fixtures/blocks/core__list__ul.parsed.json
index 427f4c3a975cf..2853bc5558ebe 100644
--- a/test/integration/fixtures/blocks/core__list__ul.parsed.json
+++ b/test/integration/fixtures/blocks/core__list__ul.parsed.json
@@ -2,10 +2,71 @@
{
"blockName": "core/list",
"attrs": {},
- "innerBlocks": [],
- "innerHTML": "\n- Text & Headings
- Images & Videos
- Galleries
- Embeds, like YouTube, Tweets, or other WordPress posts.
- Layout blocks, like Buttons, Hero Images, Separators, etc.
- And Lists like this one of course :)
\n",
+ "innerBlocks": [
+ {
+ "blockName": "core/list-item",
+ "attrs": {},
+ "innerBlocks": [],
+ "innerHTML": "\nText & Headings\n",
+ "innerContent": [ "\nText & Headings\n" ]
+ },
+ {
+ "blockName": "core/list-item",
+ "attrs": {},
+ "innerBlocks": [],
+ "innerHTML": "\nImages & Videos\n",
+ "innerContent": [ "\nImages & Videos\n" ]
+ },
+ {
+ "blockName": "core/list-item",
+ "attrs": {},
+ "innerBlocks": [],
+ "innerHTML": "\nGalleries\n",
+ "innerContent": [ "\nGalleries\n" ]
+ },
+ {
+ "blockName": "core/list-item",
+ "attrs": {},
+ "innerBlocks": [],
+ "innerHTML": "\nEmbeds, like YouTube, Tweets, or other WordPress posts.\n",
+ "innerContent": [
+ "\nEmbeds, like YouTube, Tweets, or other WordPress posts.\n"
+ ]
+ },
+ {
+ "blockName": "core/list-item",
+ "attrs": {},
+ "innerBlocks": [],
+ "innerHTML": "\nLayout blocks, like Buttons, Hero Images, Separators, etc.\n",
+ "innerContent": [
+ "\nLayout blocks, like Buttons, Hero Images, Separators, etc.\n"
+ ]
+ },
+ {
+ "blockName": "core/list-item",
+ "attrs": {},
+ "innerBlocks": [],
+ "innerHTML": "\nAnd Lists like this one of course :)\n",
+ "innerContent": [
+ "\nAnd Lists like this one of course :)\n"
+ ]
+ }
+ ],
+ "innerHTML": "\n\n",
"innerContent": [
- "\n- Text & Headings
- Images & Videos
- Galleries
- Embeds, like YouTube, Tweets, or other WordPress posts.
- Layout blocks, like Buttons, Hero Images, Separators, etc.
- And Lists like this one of course :)
\n"
+ "\n",
+ null,
+ "\n\n",
+ null,
+ "\n\n",
+ null,
+ "\n\n",
+ null,
+ "\n\n",
+ null,
+ "\n\n",
+ null,
+ "
\n"
]
}
]
diff --git a/test/integration/fixtures/blocks/core__list__ul.serialized.html b/test/integration/fixtures/blocks/core__list__ul.serialized.html
index 6b83b73a47ea1..c09708d51db0b 100644
--- a/test/integration/fixtures/blocks/core__list__ul.serialized.html
+++ b/test/integration/fixtures/blocks/core__list__ul.serialized.html
@@ -1,3 +1,25 @@
-- Text & Headings
- Images & Videos
- Galleries
- Embeds, like YouTube, Tweets, or other WordPress posts.
- Layout blocks, like Buttons, Hero Images, Separators, etc.
- And Lists like this one of course :)
+
+- Text & Headings
+
+
+
+- Images & Videos
+
+
+
+- Galleries
+
+
+
+- Embeds, like YouTube, Tweets, or other WordPress posts.
+
+
+
+- Layout blocks, like Buttons, Hero Images, Separators, etc.
+
+
+
+- And Lists like this one of course :)
+
diff --git a/test/integration/fixtures/documents/apple-out.html b/test/integration/fixtures/documents/apple-out.html
index f10d4d526e6b3..d873c942ea9ce 100644
--- a/test/integration/fixtures/documents/apple-out.html
+++ b/test/integration/fixtures/documents/apple-out.html
@@ -11,11 +11,35 @@
-
+
+- A
+
+
+
+- Bulleted
+
+
+
+
+
+- List
+
-- One
- Two
- Three
+
+- One
+
+
+
+- Two
+
+
+
+- Three
+
diff --git a/test/integration/fixtures/documents/evernote-out.html b/test/integration/fixtures/documents/evernote-out.html
index dec057d999ef1..19102ab70dc48 100644
--- a/test/integration/fixtures/documents/evernote-out.html
+++ b/test/integration/fixtures/documents/evernote-out.html
@@ -7,11 +7,39 @@
-
+
+- An
+
+
+
+- Unordered
+
+
+
+
+
+- List
+
-
-- One
- Two
- Indented
- Three
+
+
+- One
+
+
+
+- Two
+
+- Indented
+
+
+
+
+
+- Three
+
diff --git a/test/integration/fixtures/documents/google-docs-out.html b/test/integration/fixtures/documents/google-docs-out.html
index 42b98c6553247..db8bc81948fcc 100644
--- a/test/integration/fixtures/documents/google-docs-out.html
+++ b/test/integration/fixtures/documents/google-docs-out.html
@@ -11,11 +11,35 @@ This is a heading
-
+
+- A
+
+
+
+- Bulleted
+
+
+
+
+
+- List
+
-- One
- Two
- Three
+
+- One
+
+
+
+- Two
+
+
+
+- Three
+
diff --git a/test/integration/fixtures/documents/google-docs-with-comments-out.html b/test/integration/fixtures/documents/google-docs-with-comments-out.html
index 42b98c6553247..db8bc81948fcc 100644
--- a/test/integration/fixtures/documents/google-docs-with-comments-out.html
+++ b/test/integration/fixtures/documents/google-docs-with-comments-out.html
@@ -11,11 +11,35 @@ This is a heading
-
+
+- A
+
+
+
+- Bulleted
+
+
+
+
+
+- List
+
-- One
- Two
- Three
+
+- One
+
+
+
+- Two
+
+
+
+- Three
+
diff --git a/test/integration/fixtures/documents/markdown-out.html b/test/integration/fixtures/documents/markdown-out.html
index 104996580b223..c1237925a750b 100644
--- a/test/integration/fixtures/documents/markdown-out.html
+++ b/test/integration/fixtures/documents/markdown-out.html
@@ -15,11 +15,35 @@ Lists
-
+
+- A
+
+
+
+- Bulleted
+
+
+
+
+
+- List
+
-- One
- Two
- Three
+
+- One
+
+
+
+- Two
+
+
+
+- Three
+
diff --git a/test/integration/fixtures/documents/ms-word-online-out.html b/test/integration/fixtures/documents/ms-word-online-out.html
index d3aaeb98e302f..398281520f254 100644
--- a/test/integration/fixtures/documents/ms-word-online-out.html
+++ b/test/integration/fixtures/documents/ms-word-online-out.html
@@ -7,11 +7,35 @@
-
+
+- A
+
+
+
+- Bulleted
+
+
+
+- Indented
+
+
+
+- List
+
-
-- One
- Two
- Three
+
+
+- One
+
+
+
+- Two
+
+
+
+- Three
+
diff --git a/test/integration/fixtures/documents/ms-word-out.html b/test/integration/fixtures/documents/ms-word-out.html
index faae96541aa5f..9a5d5fdf557a4 100644
--- a/test/integration/fixtures/documents/ms-word-out.html
+++ b/test/integration/fixtures/documents/ms-word-out.html
@@ -19,11 +19,35 @@ This is a heading level 2
-
+
+- A
+
+
+
+- Bulleted
+
+
+
+
+
+- List
+
-- One
- Two
- Three
+
+- One
+
+
+
+- Two
+
+
+
+- Three
+