diff --git a/packages/block-editor/src/private-apis.js b/packages/block-editor/src/private-apis.js index b34f35adc5c911..75a92c4ee4f11b 100644 --- a/packages/block-editor/src/private-apis.js +++ b/packages/block-editor/src/private-apis.js @@ -7,6 +7,11 @@ import { lock } from './lock-unlock'; import OffCanvasEditor from './components/off-canvas-editor'; import LeafMoreMenu from './components/off-canvas-editor/leaf-more-menu'; import { ComposedPrivateInserter as PrivateInserter } from './components/inserter'; +import { default as useConvertToGroupButtonProps } from './components/convert-to-group-buttons/use-convert-to-group-button-props'; +import { + hasStickyPositionSupport, + useIsPositionDisabled, +} from './hooks/position'; /** * Private @wordpress/block-editor APIs. @@ -18,4 +23,7 @@ lock( privateApis, { LeafMoreMenu, OffCanvasEditor, PrivateInserter, + useConvertToGroupButtonProps, + hasStickyPositionSupport, + useIsPositionDisabled, } ); diff --git a/packages/edit-site/src/components/template-part-converter/convert-to-sticky-group.js b/packages/edit-site/src/components/template-part-converter/convert-to-sticky-group.js new file mode 100644 index 00000000000000..ffdea304ba2968 --- /dev/null +++ b/packages/edit-site/src/components/template-part-converter/convert-to-sticky-group.js @@ -0,0 +1,97 @@ +/** + * WordPress dependencies + */ +import { switchToBlockType } from '@wordpress/blocks'; +import { MenuItem } from '@wordpress/components'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { + store as blockEditorStore, + privateApis as blockEditorPrivateApis, +} from '@wordpress/block-editor'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import { unlock } from '../../private-apis'; + +const { + hasStickyPositionSupport, + useConvertToGroupButtonProps, + useIsPositionDisabled, +} = unlock( blockEditorPrivateApis ); + +export default function ConvertToStickyGroup( { selectedClientIds, onClose } ) { + const { replaceBlocks } = useDispatch( blockEditorStore ); + const { clientIds, isGroupable, blocksSelection, groupingBlockName } = + useConvertToGroupButtonProps( selectedClientIds ); + + const { canRemove, hasParents } = useSelect( + ( select ) => { + const { getBlockParents, canRemoveBlocks } = + select( blockEditorStore ); + return { + canRemove: canRemoveBlocks( clientIds ), + hasParents: !! getBlockParents( clientIds[ 0 ] ).length, + }; + }, + [ clientIds ] + ); + + const isPositionDisabled = useIsPositionDisabled( { + name: groupingBlockName, + } ); + const isStickySupported = hasStickyPositionSupport( groupingBlockName ); + + const onConvertToGroup = () => { + const newBlocks = switchToBlockType( + blocksSelection, + groupingBlockName + ); + + if ( newBlocks && newBlocks.length > 0 ) { + // Because the block is not in the store yet we can't use + // updateBlockAttributes so need to manually update attributes. + newBlocks[ 0 ].attributes.layout = { + type: 'default', + }; + newBlocks[ 0 ].attributes.style = { + ...( newBlocks[ 0 ].attributes.style || {} ), + position: { + type: 'sticky', + top: '0px', + }, + }; + replaceBlocks( clientIds, newBlocks ); + } + }; + + // For the button to be visible, the following conditions must be met: + // - The block is groupable. + // - The block can be removed. + // - A grouping block is available. + // - The block and theme both support sticky position. + // - The block has no parents, so is at the root of the template. + if ( + ! isGroupable || + ! canRemove || + ! groupingBlockName || + ! isStickySupported || + hasParents || + isPositionDisabled + ) { + return null; + } + + // Allow converting a single template part block to a group. + return ( + { + onConvertToGroup(); + onClose(); + } } + > + { __( 'Make sticky' ) } + + ); +} diff --git a/packages/edit-site/src/components/template-part-converter/index.js b/packages/edit-site/src/components/template-part-converter/index.js index 7694735cbb3025..02fb5e91703308 100644 --- a/packages/edit-site/src/components/template-part-converter/index.js +++ b/packages/edit-site/src/components/template-part-converter/index.js @@ -12,6 +12,7 @@ import { */ import ConvertToRegularBlocks from './convert-to-regular'; import ConvertToTemplatePart from './convert-to-template-part'; +import { default as ConvertToStickyGroup } from './convert-to-sticky-group'; export default function TemplatePartConverter() { return ( @@ -36,10 +37,16 @@ function TemplatePartConverterMenuItem( { clientIds, onClose } ) { // Allow converting a single template part to standard blocks. if ( blocks.length === 1 && blocks[ 0 ]?.name === 'core/template-part' ) { return ( - + <> + + + ); } return ;