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

Allow the Preview Menu to be extendible by plugins #25430

Closed
wants to merge 4 commits into from
Closed
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
27 changes: 15 additions & 12 deletions docs/designers-developers/developers/slotfills/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ export const { Fill, Slot } = createSlotFill( 'PluginPostStatusInfo' );

const PluginPostStatusInfo = ( { children, className } ) => (
<Fill>
<PanelRow className={ className }>
{ children }
</PanelRow>
<PanelRow className={ className }>{ children }</PanelRow>
</Fill>
);

Expand Down Expand Up @@ -97,12 +95,17 @@ const PostStatus = ( { isOpened, onTogglePanel } ) => (

There are currently eight available SlotFills in the `edit-post` package. Please refer to the individual items below for usage and example details:

* [MainDashboardButton](/docs/designers-developers/developers/slotfills/main-dashboard-button.md)
* [PluginBlockSettingsMenuItem](/docs/designers-developers/developers/slotfills/plugin-block-settings-menu-item.md)
* [PluginDocumentSettingPanel](/docs/designers-developers/developers/slotfills/plugin-document-setting-panel.md)
* [PluginMoreMenuItem](/docs/designers-developers/developers/slotfills/plugin-more-menu-item.md)
* [PluginPostPublishPanel](/docs/designers-developers/developers/slotfills/plugin-post-publish-panel.md)
* [PluginPostStatusInfo](/docs/designers-developers/developers/slotfills/plugin-post-status-info.md)
* [PluginPrePublishPanel](/docs/designers-developers/developers/slotfills/plugin-pre-publish-panel.md)
* [PluginSidebar](/docs/designers-developers/developers/slotfills/plugin-sidebar.md)
* [PluginSidebarMoreMenuItem](/docs/designers-developers/developers/slotfills/plugin-sidebar-more-menu-item.md)
- [MainDashboardButton](/docs/designers-developers/developers/slotfills/main-dashboard-button.md)
- [PluginBlockSettingsMenuItem](/docs/designers-developers/developers/slotfills/plugin-block-settings-menu-item.md)
- [PluginDocumentSettingPanel](/docs/designers-developers/developers/slotfills/plugin-document-setting-panel.md)
- [PluginMoreMenuItem](/docs/designers-developers/developers/slotfills/plugin-more-menu-item.md)
- [PluginPostPublishPanel](/docs/designers-developers/developers/slotfills/plugin-post-publish-panel.md)
- [PluginPostStatusInfo](/docs/designers-developers/developers/slotfills/plugin-post-status-info.md)
- [PluginPrePublishPanel](/docs/designers-developers/developers/slotfills/plugin-pre-publish-panel.md)
- [PluginSidebar](/docs/designers-developers/developers/slotfills/plugin-sidebar.md)
- [PluginSidebarMoreMenuItem](/docs/designers-developers/developers/slotfills/plugin-sidebar-more-menu-item.md)

There are currently two available SlotFills in the `block-editor` package:

- [PluginPreview](/docs/designers-developers/developers/slotfills/plugin-preview.md)
- [PluginPreviewMenuItem](/docs/designers-developers/developers/slotfills/plugin-preview-menu-item.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# PluginPreviewMenuItem

This is designed to be used alongside the PluginPreview.

- PluginPreviewMenuItem: Adds a menu item to the "Preview" menu.
- PluginPreview: Renders the main content area when that menu item is chosen.

Each of these takes 2 props, `previewId`, and `children`.

- `previewId` - A string that serves as an internal identifier for your
preview. Must match across PluginPreviewMenuItem and PluginPreview.
- `children` - What gets rendered in that spot.

## Example

```js
import { registerPlugin } from '@wordpress/plugins';
import { PluginPreview, PluginPreviewMenuItem } from '@wordpress/block-editor';
import { Fragment } from '@wordpress/element';

const PluginPreviewTest = () => (
<Fragment>
<PluginPreviewMenuItem previewId="preview-custom-1">
Custom Preview 1 Menu Text
</PluginPreviewMenuItem>
<PluginPreview previewId="preview-custom-1">
<div>
<h4>Custom Preview 1 Content</h4>
</div>
</PluginPreview>
</Fragment>
);

registerPlugin( 'plugin-preview-test', {
render: PluginPreviewTest,
} );
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# PluginPreview

This is designed to be used alongside the PluginPreviewMenuItem.

- PluginPreviewMenuItem: Adds a menu item to the "Preview" menu.
- PluginPreview: Renders the main content area when that menu item is chosen.

Each of these takes 2 props, `previewId`, and `children`.

- `previewId` - A string that serves as an internal identifier for your
preview. Must match across PluginPreviewMenuItem and PluginPreview.
- `children` - What gets rendered in that spot.

## Example

```js
import { registerPlugin } from '@wordpress/plugins';
import { PluginPreview, PluginPreviewMenuItem } from '@wordpress/block-editor';
import { Fragment } from '@wordpress/element';

const PluginPreviewTest = () => (
<Fragment>
<PluginPreviewMenuItem previewId="preview-custom-1">
Custom Preview 1 Menu Text
</PluginPreviewMenuItem>
<PluginPreview previewId="preview-custom-1">
<div>
<h4>Custom Preview 1 Content</h4>
</div>
</PluginPreview>
</Fragment>
);

registerPlugin( 'plugin-preview-test', {
render: PluginPreviewTest,
} );
```
28 changes: 28 additions & 0 deletions packages/block-editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,10 @@ Undocumented declaration.

Undocumented declaration.

<a name="coreDeviceTypes" href="#coreDeviceTypes">#</a> **coreDeviceTypes**

Undocumented declaration.

<a name="createCustomColorsHOC" href="#createCustomColorsHOC">#</a> **createCustomColorsHOC**

A higher-order component factory for creating a 'withCustomColors' HOC, which handles color logic
Expand Down Expand Up @@ -451,6 +455,30 @@ _Related_

- <https://github.com/WordPress/gutenberg/blob/master/packages/block-editor/src/components/plain-text/README.md>

<a name="PluginPreview" href="#PluginPreview">#</a> **PluginPreview**

Component used by a plugin to define the contents of a "custom
preview". The children of this component will be displayed in the main editor
screen when this "custom preview" is chosen from the preview menu.

_Parameters_

- _props_ `Object`: Component properties.
- _props.previewId_ `string`: The internal name of this custom preview. Must match the _previewId_ given to `PluginPreviewMenuItem`.
- _props.children_ `WPElement`: Children to be rendered.

<a name="PluginPreviewMenuItem" href="#PluginPreviewMenuItem">#</a> **PluginPreviewMenuItem**

Component used by a plugin to define the contents of a menu item that
selects a "custom preview". The children of this component will be displayed
inside the preview menu. Typically a single string is good enough.

_Parameters_

- _props_ `Object`: Component properties.
- _props.previewId_ `string`: The internal name of this custom preview. Must match the _previewId_ given to `PluginPreview`.
- _props.children_ `WPElement`: Children to be rendered.

<a name="PreserveScrollInReorder" href="#PreserveScrollInReorder">#</a> **PreserveScrollInReorder**

Undocumented declaration.
Expand Down
25 changes: 24 additions & 1 deletion packages/block-editor/src/components/preview-options/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,24 @@ import classnames from 'classnames';
* WordPress dependencies
*/
import { useViewportMatch } from '@wordpress/compose';
import { DropdownMenu, MenuGroup, MenuItem } from '@wordpress/components';
import { DropdownMenu, MenuGroup, MenuItem, Slot } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { check } from '@wordpress/icons';

/*
* coreDeviceTypes: An array of strings. The strings returned represent
* deviceType values that belong to the core system. When the deviceType,
* returned by `__experimentalGetPreviewDeviceType()`, is one of these values,
* the built in VisualEditor is responsible for rendering a preview of that
* type.

* When the deviceType is something other than one of the coreDeviceTypes, we are
* rendering a custom deviceType registered by the <PluginPreviewMenuItem /> and
* <PluginPreview /> components, and defer to a <Slot /> filled by the plugin to
* draw the preview.
*/
export const coreDeviceTypes = [ 'Desktop', 'Tablet', 'Mobile' ];

export default function PreviewOptions( {
children,
className,
Expand Down Expand Up @@ -67,6 +81,15 @@ export default function PreviewOptions( {
{ __( 'Mobile' ) }
</MenuItem>
</MenuGroup>

<Slot name="core/block-editor/plugin-preview-menu">
{ ( fills ) =>
! fills || fills.length === 0 ? null : (
<MenuGroup>{ fills }</MenuGroup>
)
}
</Slot>

{ children }
</>
) }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* WordPress dependencies
*/
import { Fill, MenuItem } from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
import { check } from '@wordpress/icons';

/**
* Internal dependencies
*/
import { coreDeviceTypes } from '../index';

/**
* Component used by a plugin to define the contents of a menu item that
* selects a "custom preview". The children of this component will be displayed
* inside the preview menu. Typically a single string is good enough.
*
* @param {Object} props Component properties.
* @param {string} props.previewId The internal name of this custom preview. Must match the _previewId_ given to `PluginPreview`.
* @param {WPElement} props.children Children to be rendered.
*/
export default function PluginPreviewMenuItem( {
children,
previewId,
...props
} ) {
const {
__experimentalSetPreviewDeviceType: setPreviewDeviceType,
} = useDispatch( 'core/edit-post' );

const { deviceType } = useSelect(
( select ) => ( {
deviceType: select(
'core/edit-post'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The block editor is a generic package that may be used outside WordPress, while the core/edit-post is a package to edit regular WordPress posts. I think we should avoid having the block-editor depending or querying data from core/edit-post.

I guess things will also not work as expected for edit-site scree where we don't have a core/edit-post module?

The device type is passed to the PreviewOptions as a prop. Could we rely on that prop instead?

Not directly related to this PR, but I think it makes sense to move the preview functionality under the WordPress/interface package. It is common to edit-post and edit-site. It has functionality like the singleEnableItems that can be used to store which preview is active. I guess the slot / fill here could also be abstracted as action item packages/interface/src/components/action-item/README.md.

Regarding the API, we are exposing PluginPreview, PluginPreviewMenuItem on the @wordpress/block-editor' package. As far as I know, the bock-editor does not expose slot & fills besides the ones used by blocks. All the plugin related API's are exposed under edit-post/edit-site. I guess for this case it may make sense too to make PluginPreview, PluginPreviewMenuItem under @wordpress/edit-site/edit-post. I guess we could implement the slot fills under WordPress/interface, and then on edit-site and edit-post, we would simply have wrappers that pass a specific scope. Similar to what we do for the sidebar and menu item slots.
The PreviewOptions component would have a prop for additional preview options that edit-site and edit-post use.

cc: @gziolo and @youknowriad In case you have a different option.

).__experimentalGetPreviewDeviceType(),
} ),
[]
);

if ( coreDeviceTypes.includes( previewId ) ) {
return null;
}

return (
<Fill name="core/block-editor/plugin-preview-menu" { ...props }>
<MenuItem
onClick={ () => setPreviewDeviceType( previewId ) }
icon={ deviceType === previewId && check }
>
{ children }
</MenuItem>
</Fill>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* WordPress dependencies
*/
import { Fill } from '@wordpress/components';

/**
* Component used by a plugin to define the contents of a "custom
* preview". The children of this component will be displayed in the main editor
* screen when this "custom preview" is chosen from the preview menu.
*
* @param {Object} props Component properties.
* @param {string} props.previewId The internal name of this custom preview. Must match the _previewId_ given to `PluginPreviewMenuItem`.
* @param {WPElement} props.children Children to be rendered.
*/
export default function PluginPreview( { children, previewId, ...props } ) {
return (
<Fill
name={ 'core/block-editor/plugin-preview/' + previewId }
{ ...props }
>
{ children }
</Fill>
);
}
3 changes: 3 additions & 0 deletions packages/block-editor/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ export * from './components';
export * from './utils';
export { storeConfig } from './store';
export { SETTINGS_DEFAULTS } from './store/defaults';
export { default as PluginPreviewMenuItem } from './components/preview-options/plugin-preview-menu-item';
export { default as PluginPreview } from './components/preview-options/plugin-preview';
export { coreDeviceTypes } from './components/preview-options';
4 changes: 2 additions & 2 deletions packages/edit-post/src/components/layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { close } from '@wordpress/icons';
* Internal dependencies
*/
import TextEditor from '../text-editor';
import VisualEditor from '../visual-editor';
import VisualEditorOrPluginPreview from '../visual-editor/visual-editor-or-plugin-preview';
import EditPostKeyboardShortcuts from '../keyboard-shortcuts';
import KeyboardShortcutHelpModal from '../keyboard-shortcut-help-modal';
import ManageBlocksModal from '../manage-blocks-modal';
Expand Down Expand Up @@ -250,7 +250,7 @@ function Layout() {
<TextEditor />
) }
{ isRichEditingEnabled && mode === 'visual' && (
<VisualEditor />
<VisualEditorOrPluginPreview />
) }
<div className="edit-post-layout__metaboxes">
<MetaBoxes location="normal" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';
import { Slot } from '@wordpress/components';
import { coreDeviceTypes } from '@wordpress/block-editor';

/**
* Internal dependencies
*/
import VisualEditor from './index';

function VisualEditorOrPluginPreview() {
const deviceType = useSelect( ( select ) => {
return select( 'core/edit-post' ).__experimentalGetPreviewDeviceType();
}, [] );

if ( ! coreDeviceTypes.includes( deviceType ) ) {
return (
<Slot name={ 'core/block-editor/plugin-preview/' + deviceType } />
);
}
return <VisualEditor />;
}
export default VisualEditorOrPluginPreview;