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

Post content block: create content select pattern placeholder #57572

Closed
wants to merge 10 commits into from
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ _Parameters_
- _value_ `boolean|Object`: Whether the inserter should be opened (true) or closed (false). To specify an insertion point, use an object.
- _value.rootClientId_ `string`: The root client ID to insert at.
- _value.insertionIndex_ `number`: The index to insert at.
- _value.initialTab_ `string`: The id of the tab to display first when the block editor inserter is opened. A category corresponds to one of the tab ids defined in packages/block-editor/src/components/inserter/tabs.js.

_Returns_

Expand Down
1 change: 1 addition & 0 deletions docs/reference-guides/data/data-core-edit-widgets.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ _Parameters_
- _value_ `boolean|Object`: Whether the inserter should be opened (true) or closed (false). To specify an insertion point, use an object.
- _value.rootClientId_ `string`: The root client ID to insert at.
- _value.insertionIndex_ `number`: The index to insert at.
- _value.initialTab_ `string`: The id of the tab to display first when the block editor inserter is opened. A category corresponds to one of the tab ids defined in packages/block-editor/src/components/inserter/tabs.js.

_Returns_

Expand Down
1 change: 1 addition & 0 deletions docs/reference-guides/data/data-core-editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -1382,6 +1382,7 @@ _Parameters_
- _value_ `boolean|Object`: Whether the inserter should be opened (true) or closed (false). To specify an insertion point, use an object.
- _value.rootClientId_ `string`: The root client ID to insert at.
- _value.insertionIndex_ `number`: The index to insert at.
- _value.initialTab_ `string`: The id of the tab to display first when the block editor inserter is opened. A category corresponds to one of the tab ids defined in packages/block-editor/src/components/inserter/tabs.js.

_Returns_

Expand Down
2 changes: 2 additions & 0 deletions packages/block-editor/src/components/inserter/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function InserterLibrary(
showMostUsedBlocks = false,
__experimentalInsertionIndex,
__experimentalFilterValue,
initialInserterTab,
onSelect = noop,
shouldFocusBlock = false,
},
Expand All @@ -46,6 +47,7 @@ function InserterLibrary(
isAppender={ isAppender }
showInserterHelpPanel={ showInserterHelpPanel }
showMostUsedBlocks={ showMostUsedBlocks }
initialInserterTab={ initialInserterTab }
__experimentalInsertionIndex={ __experimentalInsertionIndex }
__experimentalFilterValue={ __experimentalFilterValue }
shouldFocusBlock={ shouldFocusBlock }
Expand Down
7 changes: 5 additions & 2 deletions packages/block-editor/src/components/inserter/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ function InserterMenu(
showMostUsedBlocks,
__experimentalFilterValue = '',
shouldFocusBlock = true,
initialInserterTab,
},
ref
) {
Expand All @@ -56,8 +57,9 @@ function InserterMenu(
const [ patternFilter, setPatternFilter ] = useState( 'all' );
const [ selectedMediaCategory, setSelectedMediaCategory ] =
useState( null );
const [ selectedTab, setSelectedTab ] = useState( null );

const [ selectedTab, setSelectedTab ] = useState(
initialInserterTab || null
);
const [ destinationRootClientId, onInsertBlocks, onToggleInsertionPoint ] =
useInsertionPoint( {
rootClientId,
Expand Down Expand Up @@ -259,6 +261,7 @@ function InserterMenu(
showMedia={ showMedia }
onSelect={ handleSetSelectedTab }
tabsContents={ inserterTabsContents }
initialTabId={ initialInserterTab }
/>
) }
{ ! delayedFilterValue && ! showAsTabs && (
Expand Down
7 changes: 6 additions & 1 deletion packages/block-editor/src/components/inserter/tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,21 @@ function InserterTabs( {
showMedia = false,
onSelect,
tabsContents,
initialTabId,
} ) {
const tabs = [
blocksTab,
showPatterns && patternsTab,
showMedia && mediaTab,
].filter( Boolean );

initialTabId = !! tabs.find( ( { name } ) => initialTabId === name )
? initialTabId
: 'blocks';

return (
<div className="block-editor-inserter__tabs">
<Tabs onSelect={ onSelect }>
<Tabs initialTabId={ initialTabId } onSelect={ onSelect }>
<Tabs.TabList>
{ tabs.map( ( tab ) => (
<Tabs.Tab key={ tab.name } tabId={ tab.name }>
Expand Down
1 change: 1 addition & 0 deletions packages/block-library/src/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
@import "./nextpage/editor.scss";
@import "./page-list/editor.scss";
@import "./paragraph/editor.scss";
@import "./post-content/editor.scss";
@import "./post-excerpt/editor.scss";
@import "./pullquote/editor.scss";
@import "./rss/editor.scss";
Expand Down
143 changes: 96 additions & 47 deletions packages/block-library/src/post-content/edit.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
Expand All @@ -8,13 +13,14 @@ import {
__experimentalRecursionProvider as RecursionProvider,
__experimentalUseHasRecursion as useHasRecursion,
Warning,
store as blockEditorStore,
} from '@wordpress/block-editor';
import {
useEntityProp,
useEntityBlockEditor,
store as coreStore,
} from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import { useEntityProp, useEntityBlockEditor } from '@wordpress/core-data';
import { useSelect, useDispatch } from '@wordpress/data';
import { Placeholder, Button } from '@wordpress/components';
import { postContent as icon } from '@wordpress/icons';
import { createBlock } from '@wordpress/blocks';

/**
* Internal dependencies
*/
Expand Down Expand Up @@ -45,40 +51,104 @@ function ReadOnlyContent( {
);
}

function EditableContent( { context = {} } ) {
const { postType, postId } = context;
function EmptyContentPlaceholder( { context, onClose, openInserter } ) {
const { postType } = context;
const label =
'page' === postType
? __( 'This page’s content is empty' )
: __( 'This post’s content is empty' );
Comment on lines +56 to +59
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we have a fallback string for when the post type is neither a post nor a page? I.e. something like:

let label = __( 'This content is empty' );
if ( 'page' === postType ) {
    label = __( 'This page’s content is empty' );
} else if ( 'post' === postType ) {
    label = __( 'This post’s content is empty' );
}

return (
<Placeholder
icon={ icon }
label={ label }
instructions={ __(
'Add your first block or pattern to get started.'
) }
>
<Button variant="primary" onClick={ openInserter }>
{ __( 'Choose a pattern' ) }
</Button>

<Button variant="secondary" onClick={ onClose }>
{ __( 'Start blank' ) }
</Button>
</Placeholder>
);
}

function PostContentPlaceholder( { layoutClassNames } ) {
const blockProps = useBlockProps( { className: layoutClassNames } );
return (
<div { ...blockProps }>
<Placeholder
className="wp-block-post-content__content-placeholder"
withIllustration
>
<p>
{ __( 'This block will be replaced with your content.' ) }
</p>
</Placeholder>
</div>
);
}

function EditableContent( { context = {}, clientId } ) {
const { postType, postId } = context;
const { selectBlock, insertBlock } = useDispatch( blockEditorStore );
const [ blocks, onInput, onChange ] = useEntityBlockEditor(
'postType',
postType,
{ id: postId }
);

const entityRecord = useSelect(
( select ) => {
return select( coreStore ).getEntityRecord(
'postType',
postType,
postId
);
},
const setInserterIsOpened = useSelect(
( select ) =>
select( blockEditorStore ).getSettings()
.__experimentalSetIsInserterOpened,
[ postType, postId ]
);

const hasInnerBlocks = !! entityRecord?.content?.raw || blocks?.length;

const initialInnerBlocks = [ [ 'core/paragraph' ] ];
const hasInnerBlocks = blocks?.length;

const props = useInnerBlocksProps(
useBlockProps( { className: 'entry-content' } ),
const { children, ...props } = useInnerBlocksProps(
useBlockProps( {
className: classnames( 'entry-content', {
'wp-block-post-content__placeholder': ! hasInnerBlocks,
} ),
} ),
{
value: blocks,
onInput,
onChange,
template: ! hasInnerBlocks ? initialInnerBlocks : undefined,
}
);
return <div { ...props } />;

const onClose = () => {
const initialBlock = createBlock( 'core/paragraph' );
insertBlock( initialBlock, 0, clientId );
selectBlock( initialBlock.clientId );
};

const openInserter = () => {
setInserterIsOpened( {
initialTab: 'patterns',
rootClientId: clientId,
insertionIndex: 0,
} );
};

return (
<div { ...props }>
{ children }
{ ! hasInnerBlocks && (
<EmptyContentPlaceholder
context={ context }
onClose={ onClose }
openInserter={ openInserter }
/>
) }
</div>
);
}

function Content( props ) {
Expand All @@ -104,29 +174,6 @@ function Content( props ) {
);
}

function Placeholder( { layoutClassNames } ) {
const blockProps = useBlockProps( { className: layoutClassNames } );
return (
<div { ...blockProps }>
<p>
{ __(
'This is the Content block, it will display all the blocks in any single post or page.'
) }
</p>
<p>
{ __(
'That might be a simple arrangement like consecutive paragraphs in a blog post, or a more elaborate composition that includes image galleries, videos, tables, columns, and any other block types.'
) }
</p>
<p>
{ __(
'If there are any Custom Post Types registered at your site, the Content block can display the contents of those entries as well.'
) }
</p>
</div>
);
}

function RecursionError() {
const blockProps = useBlockProps();
return (
Expand All @@ -139,6 +186,7 @@ function RecursionError() {
}

export default function PostContentEdit( {
clientId,
context,
__unstableLayoutClassNames: layoutClassNames,
} ) {
Expand All @@ -153,11 +201,12 @@ export default function PostContentEdit( {
<RecursionProvider uniqueId={ contextPostId }>
{ contextPostId && contextPostType ? (
<Content
clientId={ clientId }
ramonjd marked this conversation as resolved.
Show resolved Hide resolved
context={ context }
layoutClassNames={ layoutClassNames }
/>
) : (
<Placeholder layoutClassNames={ layoutClassNames } />
<PostContentPlaceholder layoutClassNames={ layoutClassNames } />
) }
</RecursionProvider>
);
Expand Down
26 changes: 26 additions & 0 deletions packages/block-library/src/post-content/editor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.wp-block-post-content__placeholder {
.components-placeholder {
min-height: auto;
box-shadow: none;
padding: $grid-unit-30;
}
}

.wp-block-post-content__content-placeholder {
&.has-illustration::before {
border: 1px solid currentColor;
background: none;
}
.components-placeholder__illustration {
opacity: 0.1;
}
.components-placeholder__fieldset {
font-size: inherit;
font-family: inherit;
align-self: center;
p {
font-size: inherit;
font-family: inherit;
}
}
}
2 changes: 2 additions & 0 deletions packages/customize-widgets/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* use an object.
* @param {string} value.rootClientId The root client ID to insert at.
* @param {number} value.insertionIndex The index to insert at.
* @param {string} value.initialTab The id of the tab to display first when the block editor inserter is opened.
* A category corresponds to one of the tab ids defined in packages/block-editor/src/components/inserter/tabs.js.
*
* @example
* ```js
Expand Down
2 changes: 2 additions & 0 deletions packages/edit-widgets/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,8 @@ export function setIsWidgetAreaOpen( clientId, isOpen ) {
* use an object.
* @param {string} value.rootClientId The root client ID to insert at.
* @param {number} value.insertionIndex The index to insert at.
* @param {string} value.initialTab The id of the tab to display first when the block editor inserter is opened.
* A category corresponds to one of the tab ids defined in packages/block-editor/src/components/inserter/tabs.js.
*
* @return {Object} Action object.
*/
Expand Down
21 changes: 13 additions & 8 deletions packages/editor/src/components/inserter-sidebar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ import { unlock } from '../../lock-unlock';
import { store as editorStore } from '../../store';

export default function InserterSidebar() {
const { insertionPoint, showMostUsedBlocks } = useSelect( ( select ) => {
const { getInsertionPoint } = unlock( select( editorStore ) );
const { get } = select( preferencesStore );
return {
insertionPoint: getInsertionPoint(),
showMostUsedBlocks: get( 'core', 'mostUsedBlocks' ),
};
}, [] );
const { insertionPoint, initialInserterTab, showMostUsedBlocks } =
useSelect( ( select ) => {
const { getInsertionPoint, getInserterInitialTab } = unlock(
select( editorStore )
);
const { get } = select( preferencesStore );
return {
insertionPoint: getInsertionPoint(),
initialInserterTab: getInserterInitialTab(),
showMostUsedBlocks: get( 'core', 'mostUsedBlocks' ),
};
}, [] );
const { setIsInserterOpened } = useDispatch( editorStore );

const isMobileViewport = useViewportMatch( 'medium', '<' );
Expand Down Expand Up @@ -64,6 +68,7 @@ export default function InserterSidebar() {
__experimentalInsertionIndex={
insertionPoint.insertionIndex
}
initialInserterTab={ initialInserterTab }
__experimentalFilterValue={ insertionPoint.filterValue }
ref={ libraryRef }
/>
Expand Down
2 changes: 2 additions & 0 deletions packages/editor/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,8 @@ export function removeEditorPanel( panelName ) {
* use an object.
* @param {string} value.rootClientId The root client ID to insert at.
* @param {number} value.insertionIndex The index to insert at.
* @param {string} value.initialTab The id of the tab to display first when the block editor inserter is opened.
* A category corresponds to one of the tab ids defined in packages/block-editor/src/components/inserter/tabs.js.
*
* @return {Object} Action object.
*/
Expand Down
Loading
Loading