diff --git a/packages/block-library/src/freeform/test/__snapshots__/index.native.js.snap b/packages/block-library/src/freeform/test/__snapshots__/index.native.js.snap new file mode 100644 index 00000000000000..aad87487b93bec --- /dev/null +++ b/packages/block-library/src/freeform/test/__snapshots__/index.native.js.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Classic block converts content into blocks 1`] = ` +" +

I'm classic!

+" +`; diff --git a/packages/block-library/src/freeform/test/index.native.js b/packages/block-library/src/freeform/test/index.native.js new file mode 100644 index 00000000000000..08ba635d4cd777 --- /dev/null +++ b/packages/block-library/src/freeform/test/index.native.js @@ -0,0 +1,57 @@ +/** + * External dependencies + */ +import { + fireEvent, + getBlock, + getEditorHtml, + initializeEditor, + screen, + setupCoreBlocks, + within, +} from 'test/helpers'; + +const CLASSIC_BLOCK_HTML = `

I'm classic!

`; +const DEFAULT_EDITOR_CAPABILITIES = { + unsupportedBlockEditor: true, + canEnableUnsupportedBlockEditor: true, +}; + +setupCoreBlocks(); + +describe( 'Classic block', () => { + it( 'displays option to edit using web editor', async () => { + await initializeEditor( { + initialHtml: CLASSIC_BLOCK_HTML, + capabilities: DEFAULT_EDITOR_CAPABILITIES, + } ); + + const block = getBlock( screen, 'Classic' ); + fireEvent.press( block ); + + // Tap the block to open the unsupported block details + fireEvent.press( within( block ).getByText( 'Unsupported' ) ); + + const actionButton = screen.getByText( 'Edit using web editor' ); + expect( actionButton ).toBeVisible(); + } ); + + it( 'converts content into blocks', async () => { + await initializeEditor( { + initialHtml: CLASSIC_BLOCK_HTML, + capabilities: DEFAULT_EDITOR_CAPABILITIES, + } ); + + const block = getBlock( screen, 'Classic' ); + fireEvent.press( block ); + + // Tap the block to open the unsupported block details + fireEvent.press( within( block ).getByText( 'Unsupported' ) ); + + const actionButton = screen.getByText( 'Convert to blocks' ); + expect( actionButton ).toBeVisible(); + + fireEvent.press( actionButton ); + expect( getEditorHtml() ).toMatchSnapshot(); + } ); +} ); diff --git a/packages/block-library/src/missing/edit.native.js b/packages/block-library/src/missing/edit.native.js index 8aa4738aeea85d..a6164f590ca21d 100644 --- a/packages/block-library/src/missing/edit.native.js +++ b/packages/block-library/src/missing/edit.native.js @@ -14,7 +14,7 @@ import { import { Icon } from '@wordpress/components'; import { compose, withPreferredColorScheme } from '@wordpress/compose'; import { coreBlocks } from '@wordpress/block-library'; -import { normalizeIconObject } from '@wordpress/blocks'; +import { normalizeIconObject, rawHandler, serialize } from '@wordpress/blocks'; import { Component } from '@wordpress/element'; import { __, _x, sprintf } from '@wordpress/i18n'; import { help, plugins } from '@wordpress/icons'; @@ -24,6 +24,7 @@ import { UnsupportedBlockDetails, store as blockEditorStore, } from '@wordpress/block-editor'; +import { store as noticesStore } from '@wordpress/notices'; /** * Internal dependencies @@ -34,6 +35,8 @@ import styles from './style.scss'; const UBE_INCOMPATIBLE_BLOCKS = [ 'core/block' ]; const I18N_BLOCK_SCHEMA_TITLE = 'block title'; +const EMPTY_ARRAY = []; + export class UnsupportedBlockEdit extends Component { constructor( props ) { super( props ); @@ -119,16 +122,39 @@ export class UnsupportedBlockEdit extends Component { } renderSheet( blockTitle, blockName ) { - const { clientId } = this.props; + const { block, clientId, createSuccessNotice, replaceBlocks } = + this.props; const { showHelp } = this.state; + /* translators: Missing block alert title. %s: The localized block name */ const titleFormat = __( "'%s' is not fully-supported" ); const title = sprintf( titleFormat, blockTitle ); - const description = applyFilters( + let description = applyFilters( 'native.missing_block_detail', __( 'We are working hard to add more blocks with each release.' ), blockName ); + let customActions = EMPTY_ARRAY; + + // For Classic blocks, we offer the alternative to convert the content to blocks. + if ( blockName === 'core/freeform' ) { + description += + ' ' + + __( 'Alternatively, you can convert the content to blocks.' ); + /* translators: displayed right after the classic block is converted to blocks. %s: The localized classic block name */ + const successNotice = __( "'%s' block converted to blocks" ); + customActions = [ + { + label: __( 'Convert to blocks' ), + onPress: () => { + createSuccessNotice( + sprintf( successNotice, blockTitle ) + ); + replaceBlocks( block ); + }, + }, + ]; + } return ( ); } @@ -202,8 +229,9 @@ export class UnsupportedBlockEdit extends Component { } export default compose( [ - withSelect( ( select, { attributes } ) => { - const { capabilities } = select( blockEditorStore ).getSettings(); + withSelect( ( select, { attributes, clientId } ) => { + const { getBlock, getSettings } = select( blockEditorStore ); + const { capabilities } = getSettings(); return { isUnsupportedBlockEditorSupported: capabilities?.unsupportedBlockEditor === true, @@ -211,14 +239,23 @@ export default compose( [ capabilities?.canEnableUnsupportedBlockEditor === true, isEditableInUnsupportedBlockEditor: ! UBE_INCOMPATIBLE_BLOCKS.includes( attributes.originalName ), + block: getBlock( clientId ), }; } ), withDispatch( ( dispatch, ownProps ) => { - const { selectBlock } = dispatch( blockEditorStore ); + const { selectBlock, replaceBlocks } = dispatch( blockEditorStore ); + const { createSuccessNotice } = dispatch( noticesStore ); return { selectBlock() { selectBlock( ownProps.clientId ); }, + replaceBlocks( block ) { + replaceBlocks( + ownProps.clientId, + rawHandler( { HTML: serialize( block ) } ) + ); + }, + createSuccessNotice, }; } ), withPreferredColorScheme, diff --git a/packages/react-native-editor/CHANGELOG.md b/packages/react-native-editor/CHANGELOG.md index 9e69c51a6b73ba..3c5fe5766720b0 100644 --- a/packages/react-native-editor/CHANGELOG.md +++ b/packages/react-native-editor/CHANGELOG.md @@ -10,6 +10,7 @@ For each user feature we should also add a importance categorization label to i --> ## Unreleased +- [*] Classic block: Add option to convert to blocks [#55461] ## 1.106.0 - [*] Exit Preformatted and Verse blocks by triple pressing the Return key [#53354]