diff --git a/packages/block-editor/src/components/block-parent-selector/index.js b/packages/block-editor/src/components/block-parent-selector/index.js index bd75159b0869e1..ead1b6c1941edc 100644 --- a/packages/block-editor/src/components/block-parent-selector/index.js +++ b/packages/block-editor/src/components/block-parent-selector/index.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { getBlockType, store as blocksStore } from '@wordpress/blocks'; -import { ToolbarButton } from '@wordpress/components'; +import { ToolbarButton, Slot } from '@wordpress/components'; import { useSelect, useDispatch } from '@wordpress/data'; import { __, sprintf } from '@wordpress/i18n'; import { useRef } from '@wordpress/element'; @@ -78,6 +78,7 @@ export default function BlockParentSelector() { ref={ nodeRef } { ...showMoversGestures } > + selectBlock( firstParentClientId ) } diff --git a/packages/block-editor/src/components/block-parent-selector/style.scss b/packages/block-editor/src/components/block-parent-selector/style.scss index c5a1869835188c..9757cefcc726f7 100644 --- a/packages/block-editor/src/components/block-parent-selector/style.scss +++ b/packages/block-editor/src/components/block-parent-selector/style.scss @@ -9,3 +9,31 @@ border-radius: $radius-block-ui; } } + +// styles for parent block selector when parent block has changes +.block-editor-block-parent-selector.parent-block-has-changes { + left: calc(-#{$grid-unit-60} - #{$grid-unit-30} - #{$border-width}); + + // increase the width of parent selector to make room for the dot + .block-editor-block-parent-selector__button { + width: $grid-unit-60 + $grid-unit-20; + } + + // move the parent selector icon to right side to make room for the dot + .block-editor-block-icon { + margin-right: -15px; + } + + // add the dot before the parent selector icon + .parent-block-selector-unsaved-changes-indicator { + position: absolute; + top: 50%; + transform: translateY(-50%); + background: var(--wp-admin-theme-color); + border-radius: 4px; + height: 8px; + width: 8px; + margin: 0 12px; + } +} + diff --git a/packages/block-editor/src/components/block-switcher/index.js b/packages/block-editor/src/components/block-switcher/index.js index 7c580817f8370f..5210ed0ba82876 100644 --- a/packages/block-editor/src/components/block-switcher/index.js +++ b/packages/block-editor/src/components/block-switcher/index.js @@ -12,6 +12,7 @@ import { ToolbarButton, ToolbarGroup, ToolbarItem, + Slot, } from '@wordpress/components'; import { switchToBlockType, @@ -147,6 +148,7 @@ export const BlockSwitcherDropdownMenu = ( { clientIds, blocks } ) => { } } icon={ <> + { + // add class to the parent selector to increase it's width + const parentSelectorBtn = document.querySelector( + '.block-editor-block-parent-selector' + ); + parentSelectorBtn.classList.add( 'parent-block-has-changes' ); + // add class to the contextual toolbar to move it to the right side + const contextualToolBar = document.querySelector( + '.block-editor-block-contextual-toolbar' + ); + contextualToolBar.classList.add( 'parent-block-has-changes' ); + + return () => { + // remove classes from the parent selector and contextual toolbar when component unmounts + parentSelectorBtn.classList.remove( 'parent-block-has-changes' ); + contextualToolBar.classList.remove( 'parent-block-has-changes' ); + }; + }, [] ); + + return ( + + ); +} + +function ParentBlockSelectorUnsavedChangesIndicator() { + return ( + <> + + + + > + ); +} + +export default ParentBlockSelectorUnsavedChangesIndicator; diff --git a/packages/block-editor/src/components/block-unsaved-changes-indicator/selected-block-unsaved-changes-indicator.js b/packages/block-editor/src/components/block-unsaved-changes-indicator/selected-block-unsaved-changes-indicator.js new file mode 100644 index 00000000000000..4c0d5168ee3d14 --- /dev/null +++ b/packages/block-editor/src/components/block-unsaved-changes-indicator/selected-block-unsaved-changes-indicator.js @@ -0,0 +1,20 @@ +/** + * WordPress dependencies + */ +import { Fill } from '@wordpress/components'; + +function UnsavedChangesIndicator() { + return ; +} + +function SelectedBlockUnsavedChangesIndicator() { + return ( + <> + + + + > + ); +} + +export default SelectedBlockUnsavedChangesIndicator; diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index 3cfa70c4b9f408..54d8787b4bc5d1 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -110,6 +110,8 @@ export { default as BlockSettingsMenuControls } from './block-settings-menu-cont export { default as BlockTitle } from './block-title'; export { default as BlockToolbar } from './block-toolbar'; export { default as BlockTools } from './block-tools'; +export { default as __experimentalParentBlockSelectorUnsavedChangesIndicator } from './block-unsaved-changes-indicator/parent-block-selector-unsaved-changes-indicator'; +export { default as __experimentalSelectedBlockUnsavedChangesIndicator } from './block-unsaved-changes-indicator/selected-block-unsaved-changes-indicator'; export { default as CopyHandler, useClipboardHandler as __unstableUseClipboardHandler, diff --git a/packages/block-library/src/block/edit.js b/packages/block-library/src/block/edit.js index bb556b4731a83c..994bdf86992971 100644 --- a/packages/block-library/src/block/edit.js +++ b/packages/block-library/src/block/edit.js @@ -21,11 +21,14 @@ import { __experimentalUseInnerBlocksProps as useInnerBlocksProps, __experimentalUseNoRecursiveRenders as useNoRecursiveRenders, __experimentalBlockContentOverlay as BlockContentOverlay, + __experimentalParentBlockSelectorUnsavedChangesIndicator as ParentBlockSelectorUnsavedChangesIndicator, + __experimentalSelectedBlockUnsavedChangesIndicator as SelectedBlockUnsavedChangesIndicator, InnerBlocks, BlockControls, InspectorControls, useBlockProps, Warning, + store as blockEditorStore, } from '@wordpress/block-editor'; import { store as reusableBlocksStore } from '@wordpress/reusable-blocks'; import { ungroup } from '@wordpress/icons'; @@ -68,6 +71,23 @@ export default function ReusableBlockEdit( { attributes: { ref }, clientId } ) { [ ref, clientId ] ); + const { isChildSelected, isSelected } = useSelect( ( select ) => { + const { getBlockParents, getSelectedBlockClientId } = select( + blockEditorStore + ); + const selectedBlockClientId = getSelectedBlockClientId(); + const _isSelected = selectedBlockClientId === clientId; + + const parents = getBlockParents( selectedBlockClientId ); + const firstParentClientId = parents[ parents.length - 1 ]; + const _isChildSelected = firstParentClientId === clientId; + + return { + isChildSelected: _isChildSelected, + isSelected: _isSelected, + }; + }, [] ); + const { __experimentalConvertBlockToStatic: convertBlockToStatic, } = useDispatch( reusableBlocksStore ); @@ -156,6 +176,14 @@ export default function ReusableBlockEdit( { attributes: { ref }, clientId } ) { return ( + { isSelected && hasEdits && ( + + ) } + + { isChildSelected && hasEdits && ( + + ) } + - - - { __( 'Save' ) } - - + { hasEdits && ( + + + { __( 'Save' ) } + + + ) }