diff --git a/packages/block-editor/src/components/block-toolbar/index.js b/packages/block-editor/src/components/block-toolbar/index.js
index cffb46413c5bbb..6c6acd662ed962 100644
--- a/packages/block-editor/src/components/block-toolbar/index.js
+++ b/packages/block-editor/src/components/block-toolbar/index.js
@@ -35,9 +35,8 @@ import { store as blockEditorStore } from '../../store';
import __unstableBlockNameContext from './block-name-context';
import NavigableToolbar from '../navigable-toolbar';
import Shuffle from './shuffle';
-import PatternOverridesToolbarIndicator from '../pattern-overrides-toolbar-indicator';
import { useHasBlockToolbar } from './use-has-block-toolbar';
-import { canBindBlock } from '../../hooks/use-bindings-attributes';
+
/**
* Renders the block toolbar.
*
@@ -62,18 +61,15 @@ export function PrivateBlockToolbar( {
blockClientIds,
isDefaultEditingMode,
blockType,
- blockName,
toolbarKey,
shouldShowVisualToolbar,
showParentSelector,
isUsingBindings,
- hasParentPattern,
} = useSelect( ( select ) => {
const {
getBlockName,
getBlockMode,
getBlockParents,
- getBlockParentsByBlockName,
getSelectedBlockClientIds,
isBlockValid,
getBlockRootClientId,
@@ -96,18 +92,14 @@ export function PrivateBlockToolbar( {
const isVisual = selectedBlockClientIds.every(
( id ) => getBlockMode( id ) === 'visual'
);
- const bindings = getBlockAttributes( selectedBlockClientId )?.metadata
- ?.bindings;
- const parentPatternClientId = getBlockParentsByBlockName(
- selectedBlockClientId,
- 'core/block',
- true
- )[ 0 ];
+ const _isUsingBindings = selectedBlockClientIds.every(
+ ( clientId ) =>
+ !! getBlockAttributes( clientId )?.metadata?.bindings
+ );
return {
blockClientId: selectedBlockClientId,
blockClientIds: selectedBlockClientIds,
isDefaultEditingMode: _isDefaultEditingMode,
- blockName: _blockName,
blockType: selectedBlockClientId && getBlockType( _blockName ),
shouldShowVisualToolbar: isValid && isVisual,
rootClientId: blockRootClientId,
@@ -122,8 +114,7 @@ export function PrivateBlockToolbar( {
) &&
selectedBlockClientIds.length === 1 &&
_isDefaultEditingMode,
- isUsingBindings: !! bindings,
- hasParentPattern: !! parentPatternClientId,
+ isUsingBindings: _isUsingBindings,
};
}, [] );
@@ -176,13 +167,6 @@ export function PrivateBlockToolbar( {
{ ! isMultiToolbar &&
isLargeViewport &&
isDefaultEditingMode && }
- { isUsingBindings &&
- hasParentPattern &&
- canBindBlock( blockName ) && (
-
- ) }
{ ( shouldShowVisualToolbar || isMultiToolbar ) &&
( isDefaultEditingMode || isSynced ) && (
{
- const { getBlockAttributes, getBlockNamesByClientId } =
- select( blockEditorStore );
- const { getBlockType, getActiveBlockVariation } =
- select( blocksStore );
- const blockTypeNames = getBlockNamesByClientId( clientIds );
- const _firstBlockTypeName = blockTypeNames[ 0 ];
- const firstBlockType = getBlockType( _firstBlockTypeName );
- let _icon;
- if ( isSingleBlockSelected ) {
- const match = getActiveBlockVariation(
- _firstBlockTypeName,
- getBlockAttributes( clientIds[ 0 ] )
- );
- // Take into account active block variations.
- _icon = match?.icon || firstBlockType.icon;
- } else {
- const isSelectionOfSameType =
- new Set( blockTypeNames ).size === 1;
- // When selection consists of blocks of multiple types, display an
- // appropriate icon to communicate the non-uniformity.
- _icon = isSelectionOfSameType ? firstBlockType.icon : copy;
- }
-
- return {
- icon: _icon,
- firstBlockName: getBlockAttributes( clientIds[ 0 ] ).metadata
- .name,
- };
- },
- [ clientIds, isSingleBlockSelected ]
- );
- const firstBlockTitle = useBlockDisplayTitle( {
- clientId: clientIds[ 0 ],
- maximumLength: 35,
- } );
-
- const blockDescription = isSingleBlockSelected
- ? sprintf(
- /* translators: %1s: The block type's name; %2s: The block's user-provided name (the same as the override name). */
- __( 'This %1$s is editable using the "%2$s" override.' ),
- firstBlockTitle.toLowerCase(),
- firstBlockName
- )
- : __( 'These blocks are editable using overrides.' );
-
- const descriptionId = useId();
-
- return (
-
-
- { ( toggleProps ) => (
-
-
- >
- }
- toggleProps={ {
- describedBy: blockDescription,
- ...toggleProps,
- } }
- menuProps={ {
- orientation: 'both',
- 'aria-describedby': descriptionId,
- } }
- >
- { () => (
-
- { blockDescription }
-
- ) }
-
- ) }
-
-
- );
-}
diff --git a/packages/block-editor/src/components/pattern-overrides-toolbar-indicator/style.scss b/packages/block-editor/src/components/pattern-overrides-toolbar-indicator/style.scss
deleted file mode 100644
index 90b2c1cdd79a5e..00000000000000
--- a/packages/block-editor/src/components/pattern-overrides-toolbar-indicator/style.scss
+++ /dev/null
@@ -1,12 +0,0 @@
-.block-editor-pattern-overrides-toolbar-indicator__popover .components-popover__content {
- min-width: 260px;
- padding: $grid-unit-20;
-}
-
-.block-editor-pattern-overrides-toolbar-indicator .block-editor-pattern-overrides-toolbar-indicator-icon.has-colors svg {
- fill: var(--wp-block-synced-color);
-}
-
-.editor-collapsible-block-toolbar .block-editor-pattern-overrides-toolbar-indicator {
- height: 32px;
-}
diff --git a/packages/block-editor/src/private-apis.js b/packages/block-editor/src/private-apis.js
index 848a3ee49251bd..e6f3fc4cc39d6a 100644
--- a/packages/block-editor/src/private-apis.js
+++ b/packages/block-editor/src/private-apis.js
@@ -43,6 +43,7 @@ import { PrivateBlockPopover } from './components/block-popover';
import { PrivateInserterLibrary } from './components/inserter/library';
import { PrivatePublishDateTimePicker } from './components/publish-date-time-picker';
import useSpacingSizes from './components/spacing-sizes-control/hooks/use-spacing-sizes';
+import useBlockDisplayTitle from './components/block-title/use-block-display-title';
/**
* Private @wordpress/block-editor APIs.
@@ -86,4 +87,5 @@ lock( privateApis, {
PrivateBlockPopover,
PrivatePublishDateTimePicker,
useSpacingSizes,
+ useBlockDisplayTitle,
} );
diff --git a/packages/block-editor/src/style.scss b/packages/block-editor/src/style.scss
index d22ea9b3d0a283..cf4683b02c707d 100644
--- a/packages/block-editor/src/style.scss
+++ b/packages/block-editor/src/style.scss
@@ -1,6 +1,5 @@
@import "./autocompleters/style.scss";
@import "./components/block-alignment-control/style.scss";
-@import "./components/pattern-overrides-toolbar-indicator/style.scss";
@import "./components/block-canvas/style.scss";
@import "./components/block-icon/style.scss";
@import "./components/block-inspector/style.scss";
diff --git a/packages/editor/src/hooks/pattern-overrides.js b/packages/editor/src/hooks/pattern-overrides.js
index cd5f07aa8f48d1..485cc3725d8d71 100644
--- a/packages/editor/src/hooks/pattern-overrides.js
+++ b/packages/editor/src/hooks/pattern-overrides.js
@@ -17,6 +17,7 @@ import { unlock } from '../lock-unlock';
const {
PatternOverridesControls,
ResetOverridesControl,
+ PatternOverridesBlockControls,
PATTERN_TYPES,
PARTIAL_SYNCING_SUPPORTED_BLOCKS,
PATTERN_SYNC_TYPES,
@@ -43,6 +44,7 @@ const withPatternOverrideControls = createHigherOrderComponent(
{ props.isSelected && isSupportedBlock && (
) }
+ { isSupportedBlock &&
}
>
);
}
diff --git a/packages/patterns/src/components/pattern-overrides-block-controls.js b/packages/patterns/src/components/pattern-overrides-block-controls.js
new file mode 100644
index 00000000000000..ae8ef5e1bb7da9
--- /dev/null
+++ b/packages/patterns/src/components/pattern-overrides-block-controls.js
@@ -0,0 +1,155 @@
+/**
+ * WordPress dependencies
+ */
+import { useId } from '@wordpress/element';
+import { __, sprintf } from '@wordpress/i18n';
+import {
+ DropdownMenu,
+ ToolbarItem,
+ __experimentalText as Text,
+} from '@wordpress/components';
+import { store as blocksStore } from '@wordpress/blocks';
+import { useSelect } from '@wordpress/data';
+import { copy } from '@wordpress/icons';
+import {
+ store as blockEditorStore,
+ BlockIcon,
+ privateApis as blockEditorPrivateApis,
+ BlockControls,
+} from '@wordpress/block-editor';
+
+/**
+ * Internal dependencies
+ */
+import { unlock } from '../lock-unlock';
+import { PATTERN_OVERRIDES_BINDING_SOURCE } from '../constants';
+
+const { useBlockDisplayTitle } = unlock( blockEditorPrivateApis );
+
+function PatternOverridesToolbarIndicator( { clientIds } ) {
+ const isSingleBlockSelected = clientIds.length === 1;
+ const { icon, firstBlockName } = useSelect(
+ ( select ) => {
+ const { getBlockAttributes, getBlockNamesByClientId } =
+ select( blockEditorStore );
+ const { getBlockType, getActiveBlockVariation } =
+ select( blocksStore );
+ const blockTypeNames = getBlockNamesByClientId( clientIds );
+ const _firstBlockTypeName = blockTypeNames[ 0 ];
+ const firstBlockType = getBlockType( _firstBlockTypeName );
+ let _icon;
+ if ( isSingleBlockSelected ) {
+ const match = getActiveBlockVariation(
+ _firstBlockTypeName,
+ getBlockAttributes( clientIds[ 0 ] )
+ );
+ // Take into account active block variations.
+ _icon = match?.icon || firstBlockType.icon;
+ } else {
+ const isSelectionOfSameType =
+ new Set( blockTypeNames ).size === 1;
+ // When selection consists of blocks of multiple types, display an
+ // appropriate icon to communicate the non-uniformity.
+ _icon = isSelectionOfSameType ? firstBlockType.icon : copy;
+ }
+
+ return {
+ icon: _icon,
+ firstBlockName: getBlockAttributes( clientIds[ 0 ] ).metadata
+ .name,
+ };
+ },
+ [ clientIds, isSingleBlockSelected ]
+ );
+ const firstBlockTitle = useBlockDisplayTitle( {
+ clientId: clientIds[ 0 ],
+ maximumLength: 35,
+ } );
+
+ const blockDescription = isSingleBlockSelected
+ ? sprintf(
+ /* translators: %1s: The block type's name; %2s: The block's user-provided name (the same as the override name). */
+ __( 'This %1$s is editable using the "%2$s" override.' ),
+ firstBlockTitle.toLowerCase(),
+ firstBlockName
+ )
+ : __( 'These blocks are editable using overrides.' );
+
+ const descriptionId = useId();
+
+ return (
+
+ { ( toggleProps ) => (
+
+
+ >
+ }
+ toggleProps={ {
+ describedBy: blockDescription,
+ ...toggleProps,
+ } }
+ menuProps={ {
+ orientation: 'both',
+ 'aria-describedby': descriptionId,
+ } }
+ >
+ { () => (
+ { blockDescription }
+ ) }
+
+ ) }
+
+ );
+}
+
+export default function PatternOverridesBlockControls() {
+ const { clientIds, hasPatternOverrides, hasParentPattern } = useSelect(
+ ( select ) => {
+ const {
+ getBlockAttributes,
+ getSelectedBlockClientIds,
+ getBlockParentsByBlockName,
+ } = select( blockEditorStore );
+ const selectedClientIds = getSelectedBlockClientIds();
+ const _hasPatternOverrides = selectedClientIds.every(
+ ( clientId ) =>
+ Object.values(
+ getBlockAttributes( clientId )?.metadata?.bindings ?? {}
+ ).some(
+ ( binding ) =>
+ binding?.source === PATTERN_OVERRIDES_BINDING_SOURCE
+ )
+ );
+ const _hasParentPattern = selectedClientIds.every(
+ ( clientId ) =>
+ getBlockParentsByBlockName( clientId, 'core/block', true )
+ .length > 0
+ );
+ return {
+ clientIds: selectedClientIds,
+ hasPatternOverrides: _hasPatternOverrides,
+ hasParentPattern: _hasParentPattern,
+ };
+ },
+ []
+ );
+
+ return hasPatternOverrides && hasParentPattern ? (
+
+
+
+ ) : null;
+}
diff --git a/packages/patterns/src/components/style.scss b/packages/patterns/src/components/style.scss
index 86af3df7ff3b90..30fe0300503c48 100644
--- a/packages/patterns/src/components/style.scss
+++ b/packages/patterns/src/components/style.scss
@@ -44,3 +44,16 @@
justify-content: center;
}
+
+.patterns-pattern-overrides-toolbar-indicator__popover .components-popover__content {
+ min-width: 260px;
+ padding: $grid-unit-20;
+}
+
+.patterns-pattern-overrides-toolbar-indicator .patterns-pattern-overrides-toolbar-indicator-icon.has-colors svg {
+ fill: var(--wp-block-synced-color);
+}
+
+.editor-collapsible-block-toolbar .patterns-pattern-overrides-toolbar-indicator {
+ height: 32px;
+}
diff --git a/packages/patterns/src/private-apis.js b/packages/patterns/src/private-apis.js
index 0553378cb56043..8893b3c57d7360 100644
--- a/packages/patterns/src/private-apis.js
+++ b/packages/patterns/src/private-apis.js
@@ -17,6 +17,7 @@ import PatternsMenuItems from './components';
import RenamePatternCategoryModal from './components/rename-pattern-category-modal';
import PatternOverridesControls from './components/pattern-overrides-controls';
import ResetOverridesControl from './components/reset-overrides-control';
+import PatternOverridesBlockControls from './components/pattern-overrides-block-controls';
import { useAddPatternCategory } from './private-hooks';
import {
PATTERN_TYPES,
@@ -41,6 +42,7 @@ lock( privateApis, {
RenamePatternCategoryModal,
PatternOverridesControls,
ResetOverridesControl,
+ PatternOverridesBlockControls,
useAddPatternCategory,
PATTERN_TYPES,
PATTERN_DEFAULT_CATEGORY,