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
    +
      +
    • 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: '
  • test
  • test
  • test
    1. test test
    2. 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 -
      -
    1. test test
    2. - - - -
    3. test est eesssss
    4. -
    -
  • -` ); - } ); - - it( 'should handle empty space properly', () => { - const [ updatedAttributes, updatedInnerBlocks ] = migrateToListV2( { - values: `
  • Europe
  • -
  • - \tAfrica -
      -
    1. Algeria
    2. -
    - \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 -
      -
    1. Algeria
    2. -
    -
  • -` ); - } ); - - it( 'should handle formats properly', () => { - const [ updatedAttributes, updatedInnerBlocks ] = migrateToListV2( { - values: `
  • Europe
    • France
      • Lyon Rhones
      • Paris Ile de france
        • 1er
  • `, - 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 -
          -
        • 1er
        • -
        -
      • -
      -
    • -
    -
  • -` ); - } ); - - it( 'should not add random space', () => { - const [ updatedAttributes, updatedInnerBlocks ] = migrateToListV2( { - values: `
  • Europe
    • France
      • Paris
  • `, - 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 -
        -
      • Paris
      • -
      -
    • -
    -
  • -` ); - } ); -} ); 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`] -
    • List content
    +
      +
    • List content
    • +
    " `; 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 -
    • caret was here
    +
      +
    • caret was here
    • +
    " `; 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` -
    • 1
    +
      +
    • 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`] = ` +" +
    +

    first

    + + + +

    group

    +
    + + + +
    +

    second

    + + + +

    group

    +
    +" +`; + 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
    +
      +
    • 1 +
        +
      • 2
      • +
      +
    • +
    - -

    1
    2

    -" + +
      +
    • 1 +
        +
      • 2
      • +
      +
    • +
    +" `; exports[`RichText should paste paragraph contents into list 1`] = ` @@ -116,7 +128,9 @@ exports[`RichText should paste paragraph contents into list 1`] = ` -
    • 1
    • 2
    +
      +
    • 1
      2
    • +
    " `; 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( ` -
    • test
    +
      +
    • test
    • +
    ` ); } ); @@ -53,7 +61,9 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    1. A list item
    +
      +
    1. A list item
    2. +
    ` ); } ); @@ -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( ` -
    • I’m a list
    +
      +
    • I’m a list
    • +
    ` ); } ); @@ -207,7 +218,9 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • test
    +
      +
    • test
    • +
    ` ); } ); @@ -227,7 +240,13 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • one
    • two
    +
      +
    • one
    • + + + +
    • two
    • +
    ` ); } ); @@ -245,7 +264,13 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • one
    • two
    +
      +
    • one
    • + + + +
    • two
    • +
    ` ); } ); @@ -268,7 +293,13 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • one
      ...
    • two
    +
      +
    • one
      ...
    • + + + +
    • two
    • +
    ` ); } ); @@ -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( `
    -
    • one
    • two
    +
      +
    • one
    • + + + +
    • two
    • +
    ` ); @@ -341,7 +382,9 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • one
    +
      +
    • one
    • +
    @@ -355,7 +398,13 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • one
    • two
    +
      +
    • one
    • + + + +
    • two
    • +
    ` ); } ); @@ -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
    +
      +
    • one
    • + + + +
    • + + + +
    • two
    • +
    ` ); @@ -382,7 +442,9 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • one
    +
      +
    • one
    • +
    @@ -390,7 +452,9 @@ test.describe( 'List', () => { -
    • two
    +
      +
    • two
    • +
    ` ); @@ -403,11 +467,19 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • one
    +
      +
    • one
    • + + + +
    • +
    -
    • two
    +
      +
    • two
    • +
    ` ); } ); @@ -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( ` -
    1. one
    +
      +
    1. one
    2. +
    @@ -434,7 +509,9 @@ test.describe( 'List', () => { -
    1. two
    +
      +
    1. two
    2. +
    ` ); } ); @@ -450,7 +527,17 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • one
      • two
      • three
    +
      +
    • one +
        +
      • two
      • + + + +
      • three
      • +
      +
    • +
    ` ); } ); @@ -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( ` -
    • one
    +
      +
    • one +
        +
      • +
      +
    • +
    ` ); } ); 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( ` -
    +
      +
    1. +
    ` ); } ); @@ -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( ` -
    • a
      1. 1
    +
      +
    • a +
        +
      1. 1
      2. +
      +
    • +
    ` ); } ); - 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( ` -
    • a
      • 1
    +
      +
    • a +
        +
      • 1
      • +
      +
    • +
    ` ); - await pageUtils.pressKeyWithModifier( 'primaryShift', 'm' ); + await editor.clickBlockToolbarButton( 'Outdent' ); await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • a
    • 1
    +
      +
    • a
    • + + + +
    • 1
    • +
    ` ); } ); - 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( ` -
    • a
      • 1
        • i
    +
      +
    • a +
        +
      • 1 +
          +
        • i
        • +
        +
      • +
      +
    • +
    ` ); - await pageUtils.pressKeyWithModifier( 'primaryShift', 'm' ); + await editor.clickBlockToolbarButton( 'Outdent' ); await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • a
      • 1
      • i
    +
      +
    • a +
        +
      • 1
      • + + + +
      • i
      • +
      +
    • +
    ` ); - 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( ` -
    • a
      • 1
    • i
    +
      +
    • a +
        +
      • 1
      • +
      +
    • + + + +
    • i
    • +
    ` ); } ); @@ -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( ` -
    • a
      • b
        • c
    +
      +
    • a +
        +
      • b +
          +
        • c
        • +
        +
      • +
      +
    • +
    ` ); - 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( ` -
    • a
    • b
      • c
    +
      +
    • a
    • + + + +
    • b +
        +
      • c
      • +
      +
    • +
    ` ); } ); @@ -606,7 +763,9 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • a
    +
      +
    • a
    • +
    ` ); } ); @@ -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( ` -
    • a
    • b
    • c
    +
      +
    • a
    • + + + +
    • b
    • + + + +
    • c
    • +
    ` ); } ); @@ -646,7 +816,17 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • 1
      • a
        • i
    +
      +
    • 1 +
        +
      • a +
          +
        • i
        • +
        +
      • +
      +
    • +
    ` ); @@ -655,7 +835,17 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • 1
      • a
    +
      +
    • 1 +
        +
      • a
      • + + + +
      • +
      +
    • +
    ` ); @@ -663,7 +853,17 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • 1
      • a
    +
      +
    • 1 +
        +
      • a
      • +
      +
    • + + + +
    • +
    ` ); @@ -671,7 +871,13 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • 1
      • a
    +
      +
    • 1 +
        +
      • a
      • +
      +
    • +
    ` ); @@ -680,7 +886,13 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • 1
    +
      +
    • 1
    • + + + +
    • +
    ` ); @@ -688,7 +900,9 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • 1
    +
      +
    • 1
    • +
    ` ); @@ -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( ` -
    • 1
    • 2
      • a
    +
      +
    • 1
    • + + + +
    • 2 +
        +
      • a
      • +
      +
    • +
    ` ); } ); @@ -734,7 +959,13 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • 1
    +
      +
    • 1
    • + + + +
    • +
    ` ); } ); @@ -778,7 +1009,17 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • 1
      • 2
      • 3
    +
      +
    • 1 +
        +
      • 2
      • + + + +
      • 3
      • +
      +
    • +
    ` ); @@ -793,7 +1034,17 @@ test.describe( 'List', () => { await expect.poll( editor.getEditedPostContent ).toBe( ` -
    • 1
      • 2
      • 3
    +
      +
    • 1 +
        +
      • 2
      • + + + +
      • 3
      • +
      +
    • +
    ` ); } ); @@ -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
    -` + ` +

    + + + +

    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. 1
    2. 2
    3. 3
    +
      +
    1. 1
    2. + + + +
    3. 2
    4. + + + +
    5. 3
    6. +
    ` ); } ); @@ -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( ` -
    • a
    • b
    • c
    +
      +
    • a
    • + + + +
    • b
    • + + + +
    • c
    • +
    ` ); } ); 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 -
    1. Item
    +
      +
    1. Item
    2. +
    @@ -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
      2. -
      -
    +
      +
    1. 1 +
        +
      1. 1
      2. +
      +
    2. +
    " `; 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( - '
    • one
    • two
    • three
    ' - ); + expect( filtered ).toMatchInlineSnapshot( ` + "
      +
    • one
    • + + + +
    • two
    • + + + +
    • three
    • +
    " + ` ); expect( console ).toHaveLogged(); } ); @@ -282,9 +292,19 @@ describe( 'Blocks raw handling', () => { .map( getBlockContent ) .join( '' ); - expect( filtered ).toBe( - '
    • One
    • Two
    • Three
    ' - ); + 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": "\n
  • Text & Headings
  • \n", + "innerContent": [ "\n
  • Text & 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 @@ + +
    • one
    • two
    • three
    + \ 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": "
  • one
  • two
  • three
  • ", + "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
    • one
    • two
    • three
    \n", + "innerContent": [ + "\n
    • one
    • two
    • three
    \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 @@ - -
    • one
    • two
    • three
    - \ 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": "
  • one
  • two
  • three
  • ", - "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
    • one
    • two
    • three
    \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
    • one
    • two
    • three
    \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 @@ - -
    • one
    • two
    • three
    + +
      +
    • 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 & 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 :)
  • " + "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": "\n
  • Text & Headings
  • \n", + "innerContent": [ "\n
  • Text & Headings
  • \n" ] + }, + { + "blockName": "core/list-item", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n
  • Images & Videos
  • \n", + "innerContent": [ "\n
  • Images & Videos
  • \n" ] + }, + { + "blockName": "core/list-item", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n
  • Galleries
  • \n", + "innerContent": [ "\n
  • Galleries
  • \n" ] + }, + { + "blockName": "core/list-item", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n
  • Embeds, like YouTube, Tweets, or other WordPress posts.
  • \n", + "innerContent": [ + "\n
  • Embeds, like YouTube, Tweets, or other WordPress posts.
  • \n" + ] + }, + { + "blockName": "core/list-item", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n
  • Layout blocks, like Buttons, Hero Images, Separators, etc.
  • \n", + "innerContent": [ + "\n
  • Layout blocks, like Buttons, Hero Images, Separators, etc.
  • \n" + ] + }, + { + "blockName": "core/list-item", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n
  • And Lists like this one of course :)
  • \n", + "innerContent": [ + "\n
  • And Lists like this one of course :)
  • \n" + ] + } + ], + "innerHTML": "\n
      \n\n\n\n\n\n\n\n\n\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
      • Indented
    • List
    +
      +
    • A
    • + + + +
    • Bulleted +
        +
      • Indented
      • +
      +
    • + + + +
    • List
    • +
    -
    1. One
    2. Two
    3. Three
    +
      +
    1. One
    2. + + + +
    3. Two
    4. + + + +
    5. Three
    6. +
    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
      • Indented
    • List
    +
      +
    • An
    • + + + +
    • Unordered +
        +
      • Indented
      • +
      +
    • + + + +
    • List
    • +
    - -
    1. One
    2. Two
      1. Indented
    3. Three
    + +
      +
    1. One
    2. + + + +
    3. Two +
        +
      1. Indented
      2. +
      +
    4. + + + +
    5. Three
    6. +
    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
      • Indented
    • List
    +
      +
    • A
    • + + + +
    • Bulleted +
        +
      • Indented
      • +
      +
    • + + + +
    • List
    • +
    -
    1. One
    2. Two
    3. Three
    +
      +
    1. One
    2. + + + +
    3. Two
    4. + + + +
    5. Three
    6. +
    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
      • Indented
    • List
    +
      +
    • A
    • + + + +
    • Bulleted +
        +
      • Indented
      • +
      +
    • + + + +
    • List
    • +
    -
    1. One
    2. Two
    3. Three
    +
      +
    1. One
    2. + + + +
    3. Two
    4. + + + +
    5. Three
    6. +
    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
      • Indented
    • List
    +
      +
    • A
    • + + + +
    • Bulleted +
        +
      • Indented
      • +
      +
    • + + + +
    • List
    • +
    -
    1. One
    2. Two
    3. Three
    +
      +
    1. One
    2. + + + +
    3. Two
    4. + + + +
    5. Three
    6. +
    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 @@ -
    • Bulleted 
    • Indented 
    • List 
    +
      +
    • + + + +
    • Bulleted 
    • + + + +
    • Indented 
    • + + + +
    • List 
    • +
    - -
    1. One 
    2. Two 
    3. Three 
    + +
      +
    1. One 
    2. + + + +
    3. Two 
    4. + + + +
    5. Three 
    6. +
    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
      • Indented
    • List
    +
      +
    • A
    • + + + +
    • Bulleted +
        +
      • Indented
      • +
      +
    • + + + +
    • List
    • +
    -
    1. One
    2. Two
    3. Three
    +
      +
    1. One
    2. + + + +
    3. Two
    4. + + + +
    5. Three
    6. +