Skip to content

Commit 9d4f918

Browse files
lezamalezamaMamadukagziolosimison
authored
Editor: Add extensibility to PreviewOptions v2 (WordPress#64644)
* add plugin-preview-dropdown-item * Add slot * export PluginPreviewDropdownItem * add registerPlugin example Co-authored-by: Greg Ziółkowski <[email protected]> * example import from @wordpress/editor Co-authored-by: Greg Ziółkowski <[email protected]> * rename to PluginPreviewMenuItem * add tests tests --------- Co-authored-by: Greg Ziółkowski <[email protected]> Co-authored-by: lezama <[email protected]> Co-authored-by: Mamaduka <[email protected]> Co-authored-by: gziolo <[email protected]> Co-authored-by: simison <[email protected]> Co-authored-by: fabiankaegy <[email protected]> Co-authored-by: youknowriad <[email protected]> Co-authored-by: fumikito <[email protected]> Co-authored-by: westonruter <[email protected]>
1 parent 9c62555 commit 9d4f918

File tree

7 files changed

+144
-0
lines changed

7 files changed

+144
-0
lines changed

packages/e2e-tests/plugins/plugins-api.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,19 @@ function enqueue_plugins_api_plugin_scripts() {
8686
filemtime( plugin_dir_path( __FILE__ ) . 'plugins-api/document-setting.js' ),
8787
true
8888
);
89+
90+
wp_enqueue_script(
91+
'gutenberg-test-plugins-api-preview-menu',
92+
plugins_url( 'plugins-api/preview-menu.js', __FILE__ ),
93+
array(
94+
'wp-editor',
95+
'wp-element',
96+
'wp-i18n',
97+
'wp-plugins',
98+
),
99+
filemtime( plugin_dir_path( __FILE__ ) . 'plugins-api/preview-menu.js' ),
100+
true
101+
);
89102
}
90103

91104
add_action( 'init', 'enqueue_plugins_api_plugin_scripts' );
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
( function () {
2+
const { __ } = wp.i18n;
3+
const { registerPlugin } = wp.plugins;
4+
const PluginPreviewMenuItem = wp.editor.PluginPreviewMenuItem;
5+
const el = wp.element.createElement;
6+
7+
function CustomPreviewMenuItem() {
8+
return el( PluginPreviewMenuItem, {}, __( 'Custom Preview' ) );
9+
}
10+
11+
registerPlugin( 'custom-preview-menu-item', {
12+
render: CustomPreviewMenuItem,
13+
} );
14+
} )();

packages/editor/README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,43 @@ _Returns_
862862

863863
- `Component`: The component to be rendered.
864864

865+
### PluginPreviewMenuItem
866+
867+
Renders a menu item in the Preview dropdown, which can be used as a button or link depending on the props provided. The text within the component appears as the menu item label.
868+
869+
_Usage_
870+
871+
```jsx
872+
import { __ } from '@wordpress/i18n';
873+
import { PluginPreviewMenuItem } from '@wordpress/editor';
874+
import { external } from '@wordpress/icons';
875+
876+
function onPreviewClick() {
877+
// Handle preview action
878+
}
879+
880+
const ExternalPreviewMenuItem = () => (
881+
<PreviewDropdownMenuItem icon={ external } onClick={ onPreviewClick }>
882+
{ __( 'Preview in new tab' ) }
883+
</PreviewDropdownMenuItem>
884+
);
885+
registerPlugin( 'external-preview-menu-item', {
886+
render: ExternalPreviewMenuItem,
887+
} );
888+
```
889+
890+
_Parameters_
891+
892+
- _props_ `Object`: Component properties.
893+
- _props.href_ `[string]`: When `href` is provided, the menu item is rendered as an anchor instead of a button. It corresponds to the `href` attribute of the anchor.
894+
- _props.icon_ `[WPBlockTypeIconRender]`: The icon to be rendered to the left of the menu item label. Can be a Dashicon slug or an SVG WP element.
895+
- _props.onClick_ `[Function]`: The callback function to be executed when the user clicks the menu item.
896+
- _props.other_ `[...*]`: Any additional props are passed through to the underlying MenuItem component.
897+
898+
_Returns_
899+
900+
- `Component`: The rendered menu item component.
901+
865902
### PluginSidebar
866903

867904
Renders a sidebar when activated. The contents within the `PluginSidebar` will appear as content within the sidebar. It also automatically renders a corresponding `PluginSidebarMenuItem` component when `isPinnable` flag is set to `true`. If you wish to display the sidebar, you can with use the `PluginSidebarMoreMenuItem` component or the `wp.data.dispatch` API:

packages/editor/src/components/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export { default as PluginMoreMenuItem } from './plugin-more-menu-item';
3232
export { default as PluginPostPublishPanel } from './plugin-post-publish-panel';
3333
export { default as PluginPostStatusInfo } from './plugin-post-status-info';
3434
export { default as PluginPrePublishPanel } from './plugin-pre-publish-panel';
35+
export { default as PluginPreviewMenuItem } from './plugin-preview-menu-item';
3536
export { default as PluginSidebar } from './plugin-sidebar';
3637
export { default as PluginSidebarMoreMenuItem } from './plugin-sidebar-more-menu-item';
3738
export { default as PostTemplatePanel } from './post-template/panel';
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* WordPress dependencies
3+
*/
4+
import { compose } from '@wordpress/compose';
5+
import { MenuItem } from '@wordpress/components';
6+
import { withPluginContext } from '@wordpress/plugins';
7+
import { ActionItem } from '@wordpress/interface';
8+
9+
/**
10+
* Renders a menu item in the Preview dropdown, which can be used as a button or link depending on the props provided.
11+
* The text within the component appears as the menu item label.
12+
*
13+
* @param {Object} props Component properties.
14+
* @param {string} [props.href] When `href` is provided, the menu item is rendered as an anchor instead of a button. It corresponds to the `href` attribute of the anchor.
15+
* @param {WPBlockTypeIconRender} [props.icon=inherits from the plugin] The icon to be rendered to the left of the menu item label. Can be a Dashicon slug or an SVG WP element.
16+
* @param {Function} [props.onClick] The callback function to be executed when the user clicks the menu item.
17+
* @param {...*} [props.other] Any additional props are passed through to the underlying MenuItem component.
18+
*
19+
* @example
20+
* ```jsx
21+
* import { __ } from '@wordpress/i18n';
22+
* import { PluginPreviewMenuItem } from '@wordpress/editor';
23+
* import { external } from '@wordpress/icons';
24+
*
25+
* function onPreviewClick() {
26+
* // Handle preview action
27+
* }
28+
*
29+
* const ExternalPreviewMenuItem = () => (
30+
* <PreviewDropdownMenuItem
31+
* icon={ external }
32+
* onClick={ onPreviewClick }
33+
* >
34+
* { __( 'Preview in new tab' ) }
35+
* </PreviewDropdownMenuItem>
36+
* );
37+
* registerPlugin( 'external-preview-menu-item', {
38+
* render: ExternalPreviewMenuItem,
39+
* } );
40+
* ```
41+
*
42+
* @return {Component} The rendered menu item component.
43+
*/
44+
export default compose(
45+
withPluginContext( ( context, ownProps ) => {
46+
return {
47+
as: ownProps.as ?? MenuItem,
48+
icon: ownProps.icon || context.icon,
49+
name: 'core/plugin-preview-menu',
50+
};
51+
} )
52+
)( ActionItem );

packages/editor/src/components/preview-dropdown/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { store as coreStore } from '@wordpress/core-data';
2222
import { useEffect, useRef } from '@wordpress/element';
2323
import { store as preferencesStore } from '@wordpress/preferences';
2424
import { store as blockEditorStore } from '@wordpress/block-editor';
25+
import { ActionItem } from '@wordpress/interface';
2526

2627
/**
2728
* Internal dependencies
@@ -206,6 +207,11 @@ export default function PreviewDropdown( { forceIsAutosaveable, disabled } ) {
206207
/>
207208
</MenuGroup>
208209
) }
210+
<ActionItem.Slot
211+
name="core/plugin-preview-menu"
212+
as={ MenuGroup }
213+
fillProps={ { onClick: onClose } }
214+
/>
209215
</>
210216
) }
211217
</DropdownMenu>

test/e2e/specs/editor/plugins/plugins-api.spec.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,4 +230,25 @@ test.describe( 'Plugins API', () => {
230230
).toBeVisible();
231231
} );
232232
} );
233+
234+
test.describe( 'Preview Menu Item', () => {
235+
test( 'Should render and interact with PluginPreviewMenuItem', async ( {
236+
page,
237+
} ) => {
238+
await page
239+
.getByRole( 'region', { name: 'Editor top bar' } )
240+
.locator( '.editor-preview-dropdown__toggle' )
241+
.click();
242+
243+
const customPreviewItem = page.getByRole( 'menuitem', {
244+
name: 'Custom Preview',
245+
} );
246+
247+
await expect( customPreviewItem ).toBeVisible();
248+
249+
await customPreviewItem.click();
250+
251+
await expect( customPreviewItem ).toBeHidden();
252+
} );
253+
} );
233254
} );

0 commit comments

Comments
 (0)