Skip to content

Commit

Permalink
Add extensibility to PreviewOptions
Browse files Browse the repository at this point in the history
First pass at continuing work on extending preview menu in editors.

The work is entirely copied from #36119, which includes work from #31984

Tony Arcangelini <tony@arcangelini.com>
Piotr Delawski <piotr.delawski@gmail.com>
  • Loading branch information
simison committed May 12, 2023
1 parent 99c3dda commit 473fbf0
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 80 deletions.
1 change: 1 addition & 0 deletions packages/block-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@wordpress/html-entities": "file:../html-entities",
"@wordpress/i18n": "file:../i18n",
"@wordpress/icons": "file:../icons",
"@wordpress/interface": "file:../interface",
"@wordpress/is-shallow-equal": "file:../is-shallow-equal",
"@wordpress/keyboard-shortcuts": "file:../keyboard-shortcuts",
"@wordpress/keycodes": "file:../keycodes",
Expand Down
45 changes: 24 additions & 21 deletions packages/block-editor/src/components/preview-options/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useViewportMatch } from '@wordpress/compose';
import { DropdownMenu, MenuGroup, MenuItem } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { check, desktop, mobile, tablet } from '@wordpress/icons';
import { PluginPreview } from '@wordpress/interface';

export default function PreviewOptions( {
children,
Expand Down Expand Up @@ -45,6 +46,12 @@ export default function PreviewOptions( {
desktop,
};

const devices = [
{ type: 'Desktop', label: __( 'Desktop' ) },
{ type: 'Tablet', label: __( 'Tablet' ) },
{ type: 'Mobile', label: __( 'Mobile' ) },
];

return (
<DropdownMenu
className="block-editor-post-preview__dropdown"
Expand All @@ -56,28 +63,24 @@ export default function PreviewOptions( {
{ () => (
<>
<MenuGroup>
<MenuItem
className="block-editor-post-preview__button-resize"
onClick={ () => setDeviceType( 'Desktop' ) }
icon={ deviceType === 'Desktop' && check }
>
{ __( 'Desktop' ) }
</MenuItem>
<MenuItem
className="block-editor-post-preview__button-resize"
onClick={ () => setDeviceType( 'Tablet' ) }
icon={ deviceType === 'Tablet' && check }
>
{ __( 'Tablet' ) }
</MenuItem>
<MenuItem
className="block-editor-post-preview__button-resize"
onClick={ () => setDeviceType( 'Mobile' ) }
icon={ deviceType === 'Mobile' && check }
>
{ __( 'Mobile' ) }
</MenuItem>
{ devices.map( ( { type, label } ) => (
<MenuItem
key={ type }
className="block-editor-post-preview__button-resize"
onClick={ () => setDeviceType( type ) }
icon={ deviceType === type && check }
>
{ label }
</MenuItem>
) ) }
</MenuGroup>
<PluginPreview.Slot
devices={ devices }
fillProps={ {
deviceType,
setDeviceType,
} }
/>
{ children }
</>
) }
Expand Down
143 changes: 84 additions & 59 deletions packages/edit-post/src/components/visual-editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ import {
__experimentaluseLayoutStyles as useLayoutStyles,
} from '@wordpress/block-editor';
import { useEffect, useRef, useMemo } from '@wordpress/element';
import { Button, __unstableMotion as motion } from '@wordpress/components';
import {
__experimentalUseSlot as useSlot,
Slot,
Button,
__unstableMotion as motion,
} from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
import { useMergeRefs } from '@wordpress/compose';
import { arrowLeft } from '@wordpress/icons';
Expand Down Expand Up @@ -104,6 +109,24 @@ function getPostContentAttributes( blocks ) {
}
}

function PluginPreviewContent( { children } ) {
const previewContent = children;
const previewId = useSelect(
( select ) =>
select( editPostStore ).__experimentalGetPreviewDeviceType(),
[]
);
const previewSlotName = `PluginPreview/${ previewId }`;
const slot = useSlot( previewSlotName );
const hasFills = Boolean( slot.fills && slot.fills.length );

if ( ! hasFills ) {
return previewContent;
}

return <Slot name={ previewSlotName } fillProps={ { previewContent } } />;
}

export default function VisualEditor( { styles } ) {
const {
deviceType,
Expand Down Expand Up @@ -366,72 +389,74 @@ export default function VisualEditor( { styles } ) {
initial={ desktopCanvasStyles }
className={ previewMode }
>
<MaybeIframe
shouldIframe={
( isGutenbergPlugin &&
isBlockBasedTheme &&
! hasMetaBoxes ) ||
isTemplateMode ||
deviceType === 'Tablet' ||
deviceType === 'Mobile'
}
contentRef={ contentRef }
styles={ styles }
>
{ themeSupportsLayout &&
! themeHasDisabledLayoutStyles &&
! isTemplateMode && (
<>
<LayoutStyle
selector=".edit-post-visual-editor__post-title-wrapper, .block-editor-block-list__layout.is-root-container"
layout={ fallbackLayout }
layoutDefinitions={
globalLayoutSettings?.definitions
}
/>
{ align && (
<LayoutStyle css={ alignCSS } />
) }
{ postContentLayoutStyles && (
<PluginPreviewContent>
<MaybeIframe
shouldIframe={
( isGutenbergPlugin &&
isBlockBasedTheme &&
! hasMetaBoxes ) ||
isTemplateMode ||
deviceType === 'Tablet' ||
deviceType === 'Mobile'
}
contentRef={ contentRef }
styles={ styles }
>
{ themeSupportsLayout &&
! themeHasDisabledLayoutStyles &&
! isTemplateMode && (
<>
<LayoutStyle
layout={ postContentLayout }
css={ postContentLayoutStyles }
selector=".edit-post-visual-editor__post-title-wrapper, .block-editor-block-list__layout.is-root-container"
layout={ fallbackLayout }
layoutDefinitions={
globalLayoutSettings?.definitions
}
/>
{ align && (
<LayoutStyle css={ alignCSS } />
) }
{ postContentLayoutStyles && (
<LayoutStyle
layout={ postContentLayout }
css={ postContentLayoutStyles }
layoutDefinitions={
globalLayoutSettings?.definitions
}
/>
) }
</>
) }
{ ! isTemplateMode && (
<div
className={ classnames(
'edit-post-visual-editor__post-title-wrapper',
{
'is-focus-mode': isFocusMode,
'has-global-padding':
hasRootPaddingAwareAlignments,
}
) }
</>
contentEditable={ false }
>
<PostTitle ref={ titleRef } />
</div>
) }
{ ! isTemplateMode && (
<div
className={ classnames(
'edit-post-visual-editor__post-title-wrapper',
{
'is-focus-mode': isFocusMode,
'has-global-padding':
hasRootPaddingAwareAlignments,
}
) }
contentEditable={ false }
<RecursionProvider
blockName={ wrapperBlockName }
uniqueId={ wrapperUniqueId }
>
<PostTitle ref={ titleRef } />
</div>
) }
<RecursionProvider
blockName={ wrapperBlockName }
uniqueId={ wrapperUniqueId }
>
<BlockList
className={
isTemplateMode
? 'wp-site-blocks'
: `${ blockListLayoutClass } wp-block-post-content` // Ensure root level blocks receive default/flow blockGap styling rules.
}
__experimentalLayout={ blockListLayout }
/>
</RecursionProvider>
</MaybeIframe>
<BlockList
className={
isTemplateMode
? 'wp-site-blocks'
: `${ blockListLayoutClass } wp-block-post-content` // Ensure root level blocks receive default/flow blockGap styling rules.
}
__experimentalLayout={ blockListLayout }
/>
</RecursionProvider>
</MaybeIframe>
</PluginPreviewContent>
</motion.div>
</motion.div>
</BlockTools>
Expand Down
1 change: 1 addition & 0 deletions packages/interface/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export { default as PreferencesModalTabs } from './preferences-modal-tabs';
export { default as PreferencesModalSection } from './preferences-modal-section';
export { default as ___unstablePreferencesModalBaseOption } from './preferences-modal-base-option';
export { default as NavigableRegion } from './navigable-region';
export { default as PluginPreview } from './plugin-preview';
111 changes: 111 additions & 0 deletions packages/interface/src/components/plugin-preview/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* WordPress dependencies
*/
import {
__experimentalUseSlot as useSlot,
createSlotFill,
MenuItem,
MenuGroup,
Fill,
} from '@wordpress/components';
import { check } from '@wordpress/icons';

const { Fill: PluginPreviewMenuFill, Slot: PluginPreviewMenuSlot } =
createSlotFill( 'PluginPreviewMenu' );

/**
* Component used to define a custom preview menu item and optional content.
*
* The children of this component will be displayed in the main area of the
* block editor, instead of the `VisualEditor` component.
*
* The wrapper expects a function that returns an element. The `VisualEditor`
* component is fed in as a prop to be used.
*
* The `title` and `icon` are used to populate the Preview menu item.
*
* @param {Object} props Component properties.
* @param {WPElement} props.children Preview content.
* @param {WPIcon} props.icon Menu item icon to be rendered.
* @param {string} props.name A unique name of the custom preview.
* @param {Function} props.onClick Menu item click handler, e.g. for previews
* that provide no content (`children`).
* @param {Function} props.wrapper Wrapper for visual editor content.
* @param {string} props.title Menu item title.
*/
function PluginPreview( {
children,
icon,
name,
onClick,
title,
wrapper,
...props
} ) {
if ( ! name || ( ! children && ! wrapper ) ) {
name = 'Desktop';
}

return (
<>
<PluginPreviewMenuFill>
{ ( { deviceType, setDeviceType } ) => (
<MenuItem
className={ name }
onClick={ ( ...args ) => {
setDeviceType( name );
if ( onClick ) {
onClick( ...args );
}
} }
icon={ icon || ( deviceType === name && check ) }
{ ...props }
>
{ title }
</MenuItem>
) }
</PluginPreviewMenuFill>

{ children ? (
<Fill name={ `PluginPreview/${ name }` } { ...props }>
{ children }
</Fill>
) : (
typeof wrapper === 'function' && (
<Fill name={ `PluginPreview/${ name }` } { ...props }>
{ ( { previewContent } ) => wrapper( previewContent ) }
</Fill>
)
) }
</>
);
}

function PluginPreviewSlot( { devices, ...props } ) {
const slot = useSlot( PluginPreviewMenuSlot.__unstableName );
const hasFills = Boolean( slot.fills && slot.fills.length );

if ( ! hasFills ) {
return null;
}

function checkForDeviceNames( fill ) {
const { className } = fill[ 0 ].props;
if ( devices.includes( className ) ) {
return;
}
return fill;
}

return (
<MenuGroup>
<PluginPreviewMenuSlot { ...props }>
{ ( fills ) => <>{ fills.filter( checkForDeviceNames ) }</> }
</PluginPreviewMenuSlot>
</MenuGroup>
);
}

PluginPreview.Slot = PluginPreviewSlot;

export default PluginPreview;

0 comments on commit 473fbf0

Please sign in to comment.