Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RNMobile] Add media inserter blocks to toolbar #51827

Merged
merged 18 commits into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/block-library/src/gallery/test/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ describe( 'Gallery block', () => {

// This case is disabled until the issue (https://github.com/WordPress/gutenberg/issues/38444)
// is addressed.
it.skip( 'block remains selected after dimissing the media options picker', async () => {
it.skip( 'block remains selected after dismissing the media options picker', async () => {
// Initialize with an empty gallery
const { getByLabelText, getByText, getByTestId } =
await initializeEditor( {
Expand All @@ -175,7 +175,7 @@ describe( 'Gallery block', () => {
expect( getByText( 'Choose images' ) ).toBeVisible();
expect( getByText( 'WordPress Media Library' ) ).toBeVisible();

// Dimiss the picker
// Dismiss the picker
if ( Platform.isIOS ) {
fireEvent.press( getByText( 'Cancel' ) );
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@ import {
import { ToolbarGroup, ToolbarButton } from '@wordpress/components';
import {
keyboardClose,
audio as audioIcon,
media as imageIcon,
video as videoIcon,
gallery as galleryIcon,
undo as undoIcon,
redo as redoIcon,
} from '@wordpress/icons';
import { store as editorStore } from '@wordpress/editor';
import { createBlock } from '@wordpress/blocks';

/**
* Internal dependencies
Expand All @@ -38,6 +43,7 @@ function HeaderToolbar( {
showInserter,
showKeyboardHideButton,
getStylesFromColorScheme,
insertBlock,
onHideKeyboard,
isRTL,
noContentSelected,
Expand All @@ -55,6 +61,7 @@ function HeaderToolbar( {
scrollViewRef.current.scrollTo( { x: 0 } );
}
};

const renderHistoryButtons = () => {
const buttons = [
/* TODO: replace with EditorHistoryRedo and EditorHistoryUndo. */
Expand Down Expand Up @@ -83,6 +90,60 @@ function HeaderToolbar( {
return isRTL ? buttons.reverse() : buttons;
};

const onInsertBlock = useCallback(
( blockType ) => () => {
insertBlock( createBlock( blockType ), undefined, undefined, true, {
source: 'inserter_menu',
} );
},
[ insertBlock ]
);

const renderMediaButtons = (
<ToolbarGroup>
<ToolbarButton
key="imageButton"
title={ __( 'Image' ) }
icon={ imageIcon }
onClick={ onInsertBlock( 'core/image' ) }
testID="insert-image-button"
extraProps={ {
hint: __( 'Insert Image Block' ),
} }
/>
<ToolbarButton
key="videoButton"
title={ __( 'Video' ) }
icon={ videoIcon }
onClick={ onInsertBlock( 'core/video' ) }
testID="insert-video-button"
extraProps={ {
hint: __( 'Insert Video Block' ),
} }
/>
<ToolbarButton
key="galleryButton"
title={ __( 'Gallery' ) }
icon={ galleryIcon }
onClick={ onInsertBlock( 'core/gallery' ) }
testID="insert-gallery-button"
extraProps={ {
hint: __( 'Insert Gallery Block' ),
} }
/>
<ToolbarButton
key="audioButton"
title={ __( 'Audio' ) }
icon={ audioIcon }
onClick={ onInsertBlock( 'core/audio' ) }
testID="insert-audio-button"
extraProps={ {
hint: __( 'Insert Audio Block' ),
} }
/>
</ToolbarGroup>
);

const onToggleInserter = useCallback(
( isOpen ) => {
if ( isOpen ) {
Expand Down Expand Up @@ -131,6 +192,7 @@ function HeaderToolbar( {
useExpandedMode={ useExpandedMode }
onToggle={ onToggleInserter }
/>
{ noContentSelected && renderMediaButtons }
{ renderHistoryButtons() }
<BlockToolbar />
</ScrollView>
Expand Down Expand Up @@ -181,7 +243,8 @@ export default compose( [
};
} ),
withDispatch( ( dispatch ) => {
const { clearSelectedBlock } = dispatch( blockEditorStore );
const { clearSelectedBlock, insertBlock } =
dispatch( blockEditorStore );
const { togglePostTitleSelection } = dispatch( editorStore );

return {
Expand All @@ -191,6 +254,7 @@ export default compose( [
clearSelectedBlock();
togglePostTitleSelection( false );
},
insertBlock,
};
} ),
withViewportMatch( { isLargeViewport: 'medium' } ),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`when nothing is selected media buttons and picker display correctly 1`] = `
"<!-- wp:paragraph -->
<p>First example paragraph.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Second example paragraph.</p>
<!-- /wp:paragraph -->

<!-- wp:gallery {"linkTo":"none"} -->
<figure class="wp-block-gallery has-nested-images columns-default is-cropped"></figure>
<!-- /wp:gallery -->"
`;
119 changes: 118 additions & 1 deletion packages/edit-post/src/components/visual-editor/test/index.native.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/**
* External dependencies
*/
import { initializeEditor, fireEvent } from 'test/helpers';
import { initializeEditor, getEditorHtml, fireEvent } from 'test/helpers';

/**
* WordPress dependencies
*/
import { Platform } from '@wordpress/element';
import { getBlockTypes, unregisterBlockType } from '@wordpress/blocks';
import { registerCoreBlocks } from '@wordpress/block-library';

Expand All @@ -21,6 +22,12 @@ afterAll( () => {
} );
} );

const MEDIA_OPTIONS = [
'Choose from device',
'Take a Photo',
'WordPress Media Library',
];

const initialHtml = `
<!-- wp:paragraph -->
<p>First example paragraph.</p>
Expand Down Expand Up @@ -63,6 +70,38 @@ describe( 'when title is focused', () => {
screen.getAllByLabelText( /Paragraph Block. Row 3/ )[ 0 ]
).toBeDefined();
} );

it( 'media blocks should be displayed', async () => {
const screen = await initializeEditor( {
initialHtml,
} );

// Focus first block
fireEvent.press(
screen.getAllByLabelText( /Paragraph Block. Row 1/ )[ 0 ]
);

// Focus title
fireEvent(
screen.getAllByLabelText( 'Post title. test' )[ 0 ],
'select'
);

// Assert that the media buttons are visible
const imageButton = await screen.findByTestId( 'insert-image-button' );
expect( imageButton ).toBeVisible();

const videoButton = await screen.findByTestId( 'insert-video-button' );
expect( videoButton ).toBeVisible();

const galleryButton = await screen.findByTestId(
'insert-gallery-button'
);
expect( galleryButton ).toBeVisible();

const audioButton = await screen.findByTestId( 'insert-audio-button' );
expect( audioButton ).toBeVisible();
} );
} );

describe( 'when title is no longer focused', () => {
Expand Down Expand Up @@ -101,4 +140,82 @@ describe( 'when title is no longer focused', () => {
screen.getAllByLabelText( /Heading Block. Row 3/ )[ 0 ]
).toBeDefined();
} );

it( 'media blocks should not be displayed', async () => {
const screen = await initializeEditor( {
initialHtml,
} );

// Focus first block
fireEvent.press(
screen.getAllByLabelText( /Paragraph Block. Row 1/ )[ 0 ]
);

// Focus title
fireEvent(
screen.getAllByLabelText( 'Post title. test' )[ 0 ],
'select'
);

// Focus last block
fireEvent.press(
screen.getAllByLabelText( /Paragraph Block. Row 2/ )[ 0 ]
);

// Assert that the media buttons are not visible
const imageButton = screen.queryByTestId( 'insert-image-button' );
expect( imageButton ).toBeNull();

const videoButton = screen.queryByTestId( 'insert-video-button' );
expect( videoButton ).toBeNull();

const galleryButton = screen.queryByTestId( 'insert-gallery-button' );
expect( galleryButton ).toBeNull();

const audioButton = screen.queryByTestId( 'insert-audio-button' );
expect( audioButton ).toBeNull();
} );
} );

describe( 'when nothing is selected', () => {
it( 'media buttons and picker display correctly', async () => {
const screen = await initializeEditor( {
initialHtml,
} );

const { getByText, getByTestId } = screen;

// Check that the gallery button is visible within the toolbar
const galleryButton = await screen.queryByTestId(
'insert-gallery-button'
);
expect( galleryButton ).toBeVisible();

// Press the toolbar Gallery button
fireEvent.press( galleryButton );

// Expect the block to be created
expect(
screen.getAllByLabelText( /Gallery Block. Row 3/ )[ 0 ]
).toBeDefined();

expect( getByText( 'Choose images' ) ).toBeVisible();
MEDIA_OPTIONS.forEach( ( option ) =>
expect( getByText( option ) ).toBeVisible()
);

// Dismiss the picker
if ( Platform.isIOS ) {
fireEvent.press( getByText( 'Cancel' ) );
} else {
fireEvent( getByTestId( 'media-options-picker' ), 'backdropPress' );
}

// Expect the Gallery block to remain
expect(
screen.getAllByLabelText( /Gallery Block. Row 3/ )[ 0 ]
).toBeDefined();

expect( getEditorHtml() ).toMatchSnapshot();
} );
} );
1 change: 1 addition & 0 deletions packages/react-native-editor/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ For each user feature we should also add a importance categorization label to i
## Unreleased
- [*] Rename "Reusable blocks" to "Synced patterns", aligning with the web editor. [#51704]
- [**] Fix a crash related to Reanimated when closing the editor [#52320]
- [**] Add media inserter buttons to editor toolbar [#51827]

## 1.98.1
- [*] fix: Display heading level dropdown icons and labels [#52004]
Expand Down