diff --git a/assets/stylesheets/_z-index.scss b/assets/stylesheets/_z-index.scss index 7b7e0aedd55301..698398ec9f83e3 100644 --- a/assets/stylesheets/_z-index.scss +++ b/assets/stylesheets/_z-index.scss @@ -24,6 +24,7 @@ $z-layers: ( ".block-editor-warning": 5, ".block-library-gallery-item__inline-menu": 20, ".block-editor-url-input__suggestions": 30, + ".edit-post-layout__footer": 30, ".edit-post-header": 30, ".edit-widgets-header": 30, ".block-library-button__inline-link .block-editor-url-input__suggestions": 6, // URL suggestions for button block above sibling inserter diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index d9c7818065c0b5..7e32a9dfbabe75 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -82,6 +82,20 @@ _Related_ Undocumented declaration. +# **BlockBreadcrumb** + +Block breadcrumb component, displaying the label of the block. If the block +descends from a root block, a button is displayed enabling the user to select +the root block. + +_Parameters_ + +- _props.clientId_ `string`: Client ID of block. + +_Returns_ + +- `WPElement`: Block Breadcrumb. + # **BlockControls** Undocumented declaration. diff --git a/packages/block-editor/src/components/block-breadcrumb/index.js b/packages/block-editor/src/components/block-breadcrumb/index.js new file mode 100644 index 00000000000000..57b46acafe7416 --- /dev/null +++ b/packages/block-editor/src/components/block-breadcrumb/index.js @@ -0,0 +1,52 @@ +/** + * WordPress dependencies + */ +import { Button } from '@wordpress/components'; +import { useSelect, useDispatch } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import BlockTitle from '../block-title'; + +/** + * Block breadcrumb component, displaying the label of the block. If the block + * descends from a root block, a button is displayed enabling the user to select + * the root block. + * + * @param {string} props.clientId Client ID of block. + * @return {WPElement} Block Breadcrumb. + */ +const BlockBreadcrumb = function() { + const { selectBlock } = useDispatch( 'core/block-editor' ); + const { clientId, parents } = useSelect( ( select ) => { + const selectedBlockClientId = select( 'core/block-editor' ).getSelectedBlockClientId(); + return { + parents: select( 'core/block-editor' ).getBlockParents( selectedBlockClientId ), + clientId: selectedBlockClientId, + }; + }, [] ); + + return ( + + ); +}; + +export default BlockBreadcrumb; diff --git a/packages/block-editor/src/components/block-breadcrumb/style.scss b/packages/block-editor/src/components/block-breadcrumb/style.scss new file mode 100644 index 00000000000000..fa71051fee331b --- /dev/null +++ b/packages/block-editor/src/components/block-breadcrumb/style.scss @@ -0,0 +1,24 @@ +.block-editor-block-breadcrumb { + list-style: none; + padding: 0; + margin: 0; + + li { + display: inline-block; + margin: 0; + + &:not(.block-editor-block-breadcrumb__current)::after { + content: "▸"; + } + } +} + +.block-editor-block-breadcrumb__button.components-button { + color: inherit; + font-size: inherit; +} + +.block-editor-block-breadcrumb__current { + padding: 0 10px; + font-size: inherit; +} diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index 6e9bb592378678..89de32071c330f 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -7,6 +7,7 @@ export * from './font-sizes'; export { default as AlignmentToolbar } from './alignment-toolbar'; export { default as Autocomplete } from './autocomplete'; export { default as BlockAlignmentToolbar } from './block-alignment-toolbar'; +export { default as BlockBreadcrumb } from './block-breadcrumb'; export { default as BlockControls } from './block-controls'; export { default as BlockEdit } from './block-edit'; export { default as BlockFormatControls } from './block-format-controls'; diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index d0dd7a69a15973..7b52e58cdade06 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -418,6 +418,22 @@ export function getBlockRootClientId( state, clientId ) { null; } +export const getBlockParents = createSelector( + ( state, clientId ) => { + const parents = []; + let current = clientId; + while ( !! state.blocks.parents[ current ] ) { + current = state.blocks.parents[ current ]; + parents.push( current ); + } + + return parents.reverse(); + }, + ( state ) => [ + state.blocks.parents, + ] +); + /** * Given a block client ID, returns the root of the hierarchy from which the block is nested, return the block itself for root level blocks. * diff --git a/packages/block-editor/src/style.scss b/packages/block-editor/src/style.scss index 8ebb2e487a4f29..7296c0fa788620 100644 --- a/packages/block-editor/src/style.scss +++ b/packages/block-editor/src/style.scss @@ -3,6 +3,7 @@ @import "./components/block-inspector/style.scss"; @import "./components/block-list/style.scss"; @import "./components/block-list-appender/style.scss"; +@import "./components/block-breadcrumb/style.scss"; @import "./components/block-card/style.scss"; @import "./components/block-compare/style.scss"; @import "./components/block-mover/style.scss"; diff --git a/packages/edit-post/src/components/layout/index.js b/packages/edit-post/src/components/layout/index.js index e29011c8cec529..22e570423c4493 100644 --- a/packages/edit-post/src/components/layout/index.js +++ b/packages/edit-post/src/components/layout/index.js @@ -21,6 +21,7 @@ import { EditorNotices, PostPublishPanel, } from '@wordpress/editor'; +import { BlockBreadcrumb } from '@wordpress/block-editor'; import { withDispatch, withSelect } from '@wordpress/data'; import { PluginArea } from '@wordpress/plugins'; import { withViewportMatch } from '@wordpress/viewport'; @@ -56,6 +57,7 @@ function Layout( { isSaving, isMobileViewport, isRichEditingEnabled, + showFooter, } ) { const sidebarIsOpened = editorSidebarOpened || pluginSidebarOpened || publishSidebarOpened; @@ -92,7 +94,16 @@ function Layout( { { ( mode === 'text' || ! isRichEditingEnabled ) && } - { isRichEditingEnabled && mode === 'visual' && } + { isRichEditingEnabled && mode === 'visual' && ( + <> + + { showFooter && ( +
+ +
+ ) } + + ) }
@@ -145,6 +156,7 @@ export default compose( hasActiveMetaboxes: select( 'core/edit-post' ).hasMetaBoxes(), isSaving: select( 'core/edit-post' ).isSavingMetaBoxes(), isRichEditingEnabled: select( 'core/editor' ).getEditorSettings().richEditingEnabled, + showFooter: !! select( 'core/block-editor' ).getSelectedBlockClientId(), } ) ), withDispatch( ( dispatch ) => { const { closePublishSidebar, togglePublishSidebar } = dispatch( 'core/edit-post' ); diff --git a/packages/edit-post/src/components/layout/style.scss b/packages/edit-post/src/components/layout/style.scss index 43996d98f8c8f0..7e3d4cf30e5320 100644 --- a/packages/edit-post/src/components/layout/style.scss +++ b/packages/edit-post/src/components/layout/style.scss @@ -234,3 +234,28 @@ } } } + +.edit-post-layout__footer { + display: none; + z-index: z-index(".edit-post-layout__footer"); + + // Stretch to mimic outline padding on desktop. + @include break-medium() { + display: inline-flex; + position: fixed; + bottom: 0; + right: 0; + background: $white; + height: 30px; + padding: 0 10px; + align-items: center; + border-top: $border-width solid $light-gray-500; + font-size: 12px; + + .edit-post-layout.is-sidebar-opened & { + right: $sidebar-width; + } + } +} +@include editor-left(".edit-post-layout__footer"); +