diff --git a/packages/base-styles/_default-custom-properties.scss b/packages/base-styles/_default-custom-properties.scss index 52dfeb3899d77..5760753c48ce8 100644 --- a/packages/base-styles/_default-custom-properties.scss +++ b/packages/base-styles/_default-custom-properties.scss @@ -1,4 +1,3 @@ - // It is important to include these styles in all built stylesheets. // This allows to CSS variables post CSS plugin to generate fallbacks. // It also provides default CSS variables for npm package consumers. @@ -6,4 +5,5 @@ @include admin-scheme(#007cba); --wp-block-synced-color: #7a00df; --wp-block-synced-color--rgb: #{hex-to-rgb(#7a00df)}; + --wp-bound-block-color: #9747ff; } diff --git a/packages/block-editor/src/components/block-bindings-toolbar-indicator/index.js b/packages/block-editor/src/components/block-bindings-toolbar-indicator/index.js new file mode 100644 index 0000000000000..4b2d3df725a66 --- /dev/null +++ b/packages/block-editor/src/components/block-bindings-toolbar-indicator/index.js @@ -0,0 +1,20 @@ +/** + * WordPress dependencies + */ +import { ToolbarItem, ToolbarGroup, Icon } from '@wordpress/components'; +import { connection } from '@wordpress/icons'; +import { _x } from '@wordpress/i18n'; + +export default function BlockBindingsToolbarIndicator() { + return ( + + + + + + ); +} diff --git a/packages/block-editor/src/components/block-bindings-toolbar-indicator/style.scss b/packages/block-editor/src/components/block-bindings-toolbar-indicator/style.scss new file mode 100644 index 0000000000000..4aeabdf8acf6e --- /dev/null +++ b/packages/block-editor/src/components/block-bindings-toolbar-indicator/style.scss @@ -0,0 +1,14 @@ +.block-editor-block-bindings-toolbar-indicator { + display: inline-flex; + align-items: center; + height: 48px; + padding: 6px; + + svg g { + stroke: var(--wp-bound-block-color); + fill: transparent; + stroke-width: 1.5; + stroke-linecap: round; + stroke-linejoin: round; + } +} diff --git a/packages/block-editor/src/components/block-list/use-block-props/index.js b/packages/block-editor/src/components/block-list/use-block-props/index.js index 08b43fa46257e..c929c1014dc03 100644 --- a/packages/block-editor/src/components/block-list/use-block-props/index.js +++ b/packages/block-editor/src/components/block-list/use-block-props/index.js @@ -19,13 +19,17 @@ import useMovingAnimation from '../../use-moving-animation'; import { PrivateBlockContext } from '../private-block-context'; import { useFocusFirstElement } from './use-focus-first-element'; import { useIsHovered } from './use-is-hovered'; -import { useBlockEditContext } from '../../block-edit/context'; +import { + blockBindingsKey, + useBlockEditContext, +} from '../../block-edit/context'; import { useFocusHandler } from './use-focus-handler'; import { useEventHandlers } from './use-selected-block-event-handlers'; import { useNavModeExit } from './use-nav-mode-exit'; import { useBlockRefProvider } from './use-block-refs'; import { useIntersectionObserver } from './use-intersection-observer'; import { useFlashEditableBlocks } from '../../use-flash-editable-blocks'; +import { canBindBlock } from '../../../hooks/use-bindings-attributes'; /** * This hook is used to lightly mark an element as a block element. The element @@ -123,6 +127,12 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) { ] ); const blockEditContext = useBlockEditContext(); + const hasBlockBindings = !! blockEditContext[ blockBindingsKey ]; + const bindingsStyle = + hasBlockBindings && canBindBlock( name ) + ? { '--wp-admin-theme-color': 'var(--wp-bound-block-color)' } + : {}; + // Ensures it warns only inside the `edit` implementation for the block. if ( blockApiVersion < 2 && clientId === blockEditContext.clientId ) { warning( @@ -168,7 +178,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) { wrapperProps.className, defaultClassName ), - style: { ...wrapperProps.style, ...props.style }, + style: { ...wrapperProps.style, ...props.style, ...bindingsStyle }, }; } diff --git a/packages/block-editor/src/components/block-toolbar/index.js b/packages/block-editor/src/components/block-toolbar/index.js index a641df0f7e5cf..e566096d54f26 100644 --- a/packages/block-editor/src/components/block-toolbar/index.js +++ b/packages/block-editor/src/components/block-toolbar/index.js @@ -35,7 +35,9 @@ import { store as blockEditorStore } from '../../store'; import __unstableBlockNameContext from './block-name-context'; import NavigableToolbar from '../navigable-toolbar'; import Shuffle from './shuffle'; +import BlockBindingsIndicator from '../block-bindings-toolbar-indicator'; import { useHasBlockToolbar } from './use-has-block-toolbar'; +import { canBindBlock } from '../../hooks/use-bindings-attributes'; /** * Renders the block toolbar. * @@ -60,8 +62,10 @@ export function PrivateBlockToolbar( { blockClientIds, isDefaultEditingMode, blockType, + blockName, shouldShowVisualToolbar, showParentSelector, + isUsingBindings, } = useSelect( ( select ) => { const { getBlockName, @@ -71,6 +75,7 @@ export function PrivateBlockToolbar( { isBlockValid, getBlockRootClientId, getBlockEditingMode, + getBlockAttributes, } = select( blockEditorStore ); const selectedBlockClientIds = getSelectedBlockClientIds(); const selectedBlockClientId = selectedBlockClientIds[ 0 ]; @@ -81,20 +86,21 @@ export function PrivateBlockToolbar( { const parentBlockType = getBlockType( parentBlockName ); const _isDefaultEditingMode = getBlockEditingMode( selectedBlockClientId ) === 'default'; + const _blockName = getBlockName( selectedBlockClientId ); const isValid = selectedBlockClientIds.every( ( id ) => isBlockValid( id ) ); const isVisual = selectedBlockClientIds.every( ( id ) => getBlockMode( id ) === 'visual' ); + const _isUsingBindings = !! getBlockAttributes( selectedBlockClientId ) + ?.metadata?.bindings; return { blockClientId: selectedBlockClientId, blockClientIds: selectedBlockClientIds, isDefaultEditingMode: _isDefaultEditingMode, - blockType: - selectedBlockClientId && - getBlockType( getBlockName( selectedBlockClientId ) ), - + blockName: _blockName, + blockType: selectedBlockClientId && getBlockType( _blockName ), shouldShowVisualToolbar: isValid && isVisual, rootClientId: blockRootClientId, showParentSelector: @@ -107,6 +113,7 @@ export function PrivateBlockToolbar( { ) && selectedBlockClientIds.length === 1 && _isDefaultEditingMode, + isUsingBindings: _isUsingBindings, }; }, [] ); @@ -158,6 +165,9 @@ export function PrivateBlockToolbar( { { ! isMultiToolbar && isLargeViewport && isDefaultEditingMode && } + { isUsingBindings && canBindBlock( blockName ) && ( + + ) } { ( shouldShowVisualToolbar || isMultiToolbar ) && isDefaultEditingMode && (
) } + { isConnected && canBindBlock( blockName ) && ( + + + + ) } { positionLabel && isSticky && ( diff --git a/packages/block-editor/src/components/list-view/style.scss b/packages/block-editor/src/components/list-view/style.scss index 11cf1fafa0e14..1245bfbabcb7a 100644 --- a/packages/block-editor/src/components/list-view/style.scss +++ b/packages/block-editor/src/components/list-view/style.scss @@ -557,3 +557,11 @@ $block-navigation-max-indent: 8; .list-view-appender__description { display: none; } + +.block-editor-list-view-block-select-button__bindings svg g { + stroke: var(--wp-bound-block-color); + fill: transparent; + stroke-width: 1.5; + stroke-linecap: round; + stroke-linejoin: round; +} diff --git a/packages/block-editor/src/style.scss b/packages/block-editor/src/style.scss index 1cbc49f58551e..015cffde42a23 100644 --- a/packages/block-editor/src/style.scss +++ b/packages/block-editor/src/style.scss @@ -1,5 +1,6 @@ @import "./autocompleters/style.scss"; @import "./components/block-alignment-control/style.scss"; +@import "./components/block-bindings-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/icons/src/index.js b/packages/icons/src/index.js index 1d3c8c24c5cfd..788fc0152ba1d 100644 --- a/packages/icons/src/index.js +++ b/packages/icons/src/index.js @@ -59,6 +59,7 @@ export { default as commentAuthorName } from './library/comment-author-name'; export { default as commentContent } from './library/comment-content'; export { default as commentReplyLink } from './library/comment-reply-link'; export { default as commentEditLink } from './library/comment-edit-link'; +export { default as connection } from './library/connection'; export { default as cover } from './library/cover'; export { default as create } from './library/create'; export { default as crop } from './library/crop'; diff --git a/packages/icons/src/library/connection.js b/packages/icons/src/library/connection.js new file mode 100644 index 0000000000000..47cee6c66a3ef --- /dev/null +++ b/packages/icons/src/library/connection.js @@ -0,0 +1,25 @@ +/** + * WordPress dependencies + */ +import { SVG, Path, G } from '@wordpress/primitives'; + +const connection = ( + + + + + + + + + + +); + +export default connection;