Skip to content

Commit

Permalink
BlockEditor: Add BlockCanvas component = Iframe + BlockList + Writing…
Browse files Browse the repository at this point in the history
…Flow (#54149)
  • Loading branch information
youknowriad authored Sep 6, 2023
1 parent e4e4845 commit ccd4320
Show file tree
Hide file tree
Showing 16 changed files with 265 additions and 181 deletions.
32 changes: 2 additions & 30 deletions docs/how-to-guides/platform/custom-block-editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,12 +332,7 @@ return (
<Sidebar.InspectorFill>
<BlockInspector />
</Sidebar.InspectorFill>
<div className="editor-styles-wrapper">
<BlockEditorKeyboardShortcuts />
<WritingFlow>
<BlockList className="getdavesbe-block-editor__block-list" />
</WritingFlow>
</div>
<BlockCanvas height="400px" />
</BlockEditorProvider>
</div>
);
Expand Down Expand Up @@ -419,27 +414,6 @@ Here is roughly how this works together to render the list of blocks:

The `@wordpress/block-editor` package components are among the most complex and involved. Understanding them is crucial if you want to grasp how the editor functions at a fundamental level. Studying these components is strongly advised.

### Utility components in the custom block editor

Jumping back to your custom `<BlockEditor>` component, it is also worth noting the following "utility" components:

```js
// File: src/components/block-editor/index.js

<div className="editor-styles-wrapper">
<BlockEditorKeyboardShortcuts /> /* 1. */
<WritingFlow>
/* 2. */
<BlockList className="getdavesbe-block-editor__block-list" />
</WritingFlow>
</div>
```

These provide other important elements of functionality for the editor instance.

1. [`<BlockEditorKeyboardShortcuts />`](https://github.com/WordPress/gutenberg/blob/e38dbe958c04d8089695eb686d4f5caff2707505/packages/block-editor/src/components/keyboard-shortcuts/index.js) – Enables and usage of keyboard shortcuts within the editor
2. [`<WritingFlow>`](https://github.com/WordPress/gutenberg/blob/e38dbe958c04d8089695eb686d4f5caff2707505/packages/block-editor/src/components/writing-flow/index.js) – Handles selection, focus management, and navigation across blocks

## Reviewing the sidebar

Also within the render of the `<BlockEditor>`, is the `<Sidebar>` component.
Expand All @@ -453,9 +427,7 @@ return (
<Sidebar.InspectorFill> /* <-- SIDEBAR */
<BlockInspector />
</Sidebar.InspectorFill>
<div className="editor-styles-wrapper">
// snip
</div>
<BlockCanvas height="400px" />
</BlockEditorProvider>
</div>
);
Expand Down
36 changes: 33 additions & 3 deletions packages/block-editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ function MyEditorComponent() {
onChange={ ( blocks ) => updateBlocks( blocks ) }
>
<BlockTools>
<WritingFlow>
<BlockList />
</WritingFlow>
<BlockCanvas height="400px" />
</BlockTools>
</BlockEditorProvider>
);
Expand Down Expand Up @@ -118,6 +116,38 @@ _Returns_

- `WPElement`: Block Breadcrumb.

### BlockCanvas

BlockCanvas component is a component used to display the canvas of the block editor. What we call the canvas is an iframe containing the block list that you can manipulate. The component is also responsible of wiring up all the necessary hooks to enable the keyboard navigation across blocks in the editor and inject content styles into the iframe.

_Usage_

```jsx
function MyBlockEditor() {
const [ blocks, updateBlocks ] = useState( [] );
return (
<BlockEditorProvider
value={ blocks }
onInput={ updateBlocks }
onChange={ persistBlocks }
>
<BlockCanvas height="400px" />
</BlockEditorProvider>
);
}
```

_Parameters_

- _props_ `Object`: Component props.
- _props.height_ `string`: Canvas height, defaults to 300px.
- _props.styles_ `Array`: Content styles to inject into the iframe.
- _props.children_ `WPElement`: Content of the canvas, defaults to the BlockList component.

_Returns_

- `WPElement`: Block Breadcrumb.

### BlockColorsStyleSelector

Undocumented declaration.
Expand Down
91 changes: 91 additions & 0 deletions packages/block-editor/src/components/block-canvas/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/**
* Internal dependencies
*/
import BlockList from '../block-list';
import EditorStyles from '../editor-styles';
import Iframe from '../iframe';
import WritingFlow from '../writing-flow';
import { useMouseMoveTypingReset } from '../observe-typing';

export function ExperimentalBlockCanvas( {
shouldIframe = true,
height = '300px',
children = <BlockList />,
styles,
contentRef,
iframeProps,
} ) {
const resetTypingRef = useMouseMoveTypingReset();

if ( ! shouldIframe ) {
return (
<>
<EditorStyles styles={ styles } />
<WritingFlow
ref={ contentRef }
className="editor-styles-wrapper"
tabIndex={ -1 }
style={ { height } }
>
{ children }
</WritingFlow>
</>
);
}

return (
<Iframe
{ ...iframeProps }
ref={ resetTypingRef }
contentRef={ contentRef }
style={ {
width: '100%',
height,
...iframeProps?.style,
} }
name="editor-canvas"
>
<EditorStyles styles={ styles } />
{ children }
</Iframe>
);
}

/**
* BlockCanvas component is a component used to display the canvas of the block editor.
* What we call the canvas is an iframe containing the block list that you can manipulate.
* The component is also responsible of wiring up all the necessary hooks to enable
* the keyboard navigation across blocks in the editor and inject content styles into the iframe.
*
* @example
*
* ```jsx
* function MyBlockEditor() {
* const [ blocks, updateBlocks ] = useState([]);
* return (
* <BlockEditorProvider
* value={ blocks }
* onInput={ updateBlocks }
* onChange={ persistBlocks }
* >
* <BlockCanvas height="400px" />
* </BlockEditorProvider>
* );
* }
* ```
*
* @param {Object} props Component props.
* @param {string} props.height Canvas height, defaults to 300px.
* @param {Array} props.styles Content styles to inject into the iframe.
* @param {WPElement} props.children Content of the canvas, defaults to the BlockList component.
* @return {WPElement} Block Breadcrumb.
*/
function BlockCanvas( { children, height, styles } ) {
return (
<ExperimentalBlockCanvas height={ height } styles={ styles }>
{ children }
</ExperimentalBlockCanvas>
);
}

export default BlockCanvas;
1 change: 1 addition & 0 deletions packages/block-editor/src/components/iframe/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ function Iframe( {
<iframe
{ ...props }
style={ {
border: 0,
...props.style,
height: expand ? contentHeight : props.style?.height,
marginTop:
Expand Down
1 change: 1 addition & 0 deletions packages/block-editor/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export { default as __experimentalBlockAlignmentMatrixControl } from './block-al
export { default as BlockBreadcrumb } from './block-breadcrumb';
export { default as __experimentalUseBlockOverlayActive } from './block-content-overlay';
export { BlockContextProvider } from './block-context';
export { default as BlockCanvas } from './block-canvas';
export {
default as BlockControls,
BlockFormatControls,
Expand Down
2 changes: 2 additions & 0 deletions packages/block-editor/src/private-apis.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ import {
useReusableBlocksRenameHint,
} from './components/inserter/reusable-block-rename-hint';
import { usesContextKey } from './components/rich-text/format-edit';
import { ExperimentalBlockCanvas } from './components/block-canvas';

/**
* Private @wordpress/block-editor APIs.
*/
export const privateApis = {};
lock( privateApis, {
...globalStyles,
ExperimentalBlockCanvas,
ExperimentalBlockEditorProvider,
getRichTextValues,
kebabCase,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ import {
BlockSelectionClearer,
BlockInspector,
CopyHandler,
WritingFlow,
privateApis as blockEditorPrivateApis,
__unstableBlockSettingsMenuFirstItem,
__unstableEditorStyles as EditorStyles,
} from '@wordpress/block-editor';
import { uploadMedia } from '@wordpress/media-utils';
import { store as preferencesStore } from '@wordpress/preferences';
Expand All @@ -27,6 +26,11 @@ import SidebarEditorProvider from './sidebar-editor-provider';
import WelcomeGuide from '../welcome-guide';
import KeyboardShortcuts from '../keyboard-shortcuts';
import BlockAppender from '../block-appender';
import { unlock } from '../../lock-unlock';

const { ExperimentalBlockCanvas: BlockCanvas } = unlock(
blockEditorPrivateApis
);

export default function SidebarBlockEditor( {
blockEditorSettings,
Expand Down Expand Up @@ -112,11 +116,14 @@ export default function SidebarBlockEditor( {

<CopyHandler>
<BlockTools>
<EditorStyles styles={ settings.defaultEditorStyles } />
<BlockSelectionClearer>
<WritingFlow className="editor-styles-wrapper">
<BlockCanvas
shouldIframe={ false }
styles={ settings.defaultEditorStyles }
height="100%"
>
<BlockList renderAppender={ BlockAppender } />
</WritingFlow>
</BlockCanvas>
</BlockSelectionClearer>
</BlockTools>
</CopyHandler>
Expand Down
50 changes: 9 additions & 41 deletions packages/edit-post/src/components/visual-editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import classnames from 'classnames';
*/
import { PostTitle, store as editorStore } from '@wordpress/editor';
import {
WritingFlow,
BlockList,
BlockTools,
store as blockEditorStore,
Expand All @@ -17,10 +16,7 @@ import {
__unstableUseClipboardHandler as useClipboardHandler,
__unstableUseTypingObserver as useTypingObserver,
__experimentalUseResizeCanvas as useResizeCanvas,
__unstableEditorStyles as EditorStyles,
useSetting,
__unstableUseMouseMoveTypingReset as useMouseMoveTypingReset,
__unstableIframe as Iframe,
__experimentalRecursionProvider as RecursionProvider,
privateApis as blockEditorPrivateApis,
} from '@wordpress/block-editor';
Expand All @@ -37,44 +33,15 @@ import { store as coreStore } from '@wordpress/core-data';
import { store as editPostStore } from '../../store';
import { unlock } from '../../lock-unlock';

const { LayoutStyle, useLayoutClasses, useLayoutStyles } = unlock(
blockEditorPrivateApis
);
const {
LayoutStyle,
useLayoutClasses,
useLayoutStyles,
ExperimentalBlockCanvas: BlockCanvas,
} = unlock( blockEditorPrivateApis );

const isGutenbergPlugin = process.env.IS_GUTENBERG_PLUGIN ? true : false;

function MaybeIframe( { children, contentRef, shouldIframe, styles, style } ) {
const ref = useMouseMoveTypingReset();

if ( ! shouldIframe ) {
return (
<>
<EditorStyles styles={ styles } />
<WritingFlow
ref={ contentRef }
className="editor-styles-wrapper"
style={ { flex: '1', ...style } }
tabIndex={ -1 }
>
{ children }
</WritingFlow>
</>
);
}

return (
<Iframe
ref={ ref }
contentRef={ contentRef }
style={ { width: '100%', height: '100%', display: 'block' } }
name="editor-canvas"
>
<EditorStyles styles={ styles } />
{ children }
</Iframe>
);
}

/**
* Given an array of nested blocks, find the first Post Content
* block inside it, recursing through any nesting levels,
Expand Down Expand Up @@ -364,10 +331,11 @@ export default function VisualEditor( { styles } ) {
initial={ desktopCanvasStyles }
className={ previewMode }
>
<MaybeIframe
<BlockCanvas
shouldIframe={ isToBeIframed }
contentRef={ contentRef }
styles={ styles }
height="100%"
>
{ themeSupportsLayout &&
! themeHasDisabledLayoutStyles &&
Expand Down Expand Up @@ -421,7 +389,7 @@ export default function VisualEditor( { styles } ) {
layout={ blockListLayout }
/>
</RecursionProvider>
</MaybeIframe>
</BlockCanvas>
</motion.div>
</motion.div>
</BlockTools>
Expand Down
Loading

0 comments on commit ccd4320

Please sign in to comment.