diff --git a/packages/editor/src/components/post-featured-image/index.js b/packages/editor/src/components/post-featured-image/index.js index cabd791e938bf5..46a194f311a5e7 100644 --- a/packages/editor/src/components/post-featured-image/index.js +++ b/packages/editor/src/components/post-featured-image/index.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import clsx from 'clsx'; + /** * WordPress dependencies */ @@ -10,9 +15,10 @@ import { withNotices, withFilters, __experimentalHStack as HStack, + Notice, } from '@wordpress/components'; import { isBlobURL } from '@wordpress/blob'; -import { useState, useRef } from '@wordpress/element'; +import { useState, useRef, useEffect } from '@wordpress/element'; import { compose } from '@wordpress/compose'; import { useSelect, withDispatch, withSelect } from '@wordpress/data'; import { @@ -94,11 +100,19 @@ function PostFeaturedImage( { postType, noticeUI, noticeOperations, + isRequestingFeaturedImageMedia, } ) { const toggleRef = useRef(); const [ isLoading, setIsLoading ] = useState( false ); const { getSettings } = useSelect( blockEditorStore ); const { mediaSourceUrl } = getMediaDetails( media, currentPostId ); + const toggleFocusTimerRef = useRef(); + + useEffect( () => { + return () => { + clearTimeout( toggleFocusTimerRef.current ); + }; + }, [] ); function onDropFiles( filesList ) { getSettings().mediaUpload( { @@ -150,6 +164,9 @@ function PostFeaturedImage( { ); } + const isMissingMedia = + ! isRequestingFeaturedImageMedia && !! featuredImageId && ! media; + return ( { noticeUI } @@ -174,52 +191,83 @@ function PostFeaturedImage( { modalClass="editor-post-featured-image__media-modal" render={ ( { open } ) => (
- + { isMissingMedia ? ( + + { __( + 'Could not retrieve the featured image data.' + ) } + + ) : ( + + ) } { !! featuredImageId && ( - + @@ -228,8 +276,19 @@ function PostFeaturedImage( { className="editor-post-featured-image__action" onClick={ () => { onRemoveImage(); - toggleRef.current.focus(); + // The toggle button is rendered conditionally, we need + // to wait it is rendered before moving focus to it. + toggleFocusTimerRef.current = + setTimeout( () => { + toggleRef.current?.focus(); + } ); } } + variant={ + isMissingMedia + ? 'secondary' + : undefined + } + isDestructive={ isMissingMedia } > { __( 'Remove' ) } @@ -247,7 +306,8 @@ function PostFeaturedImage( { } const applyWithSelect = withSelect( ( select ) => { - const { getMedia, getPostType } = select( coreStore ); + const { getMedia, getPostType, hasFinishedResolution } = + select( coreStore ); const { getCurrentPostId, getEditedPostAttribute } = select( editorStore ); const featuredImageId = getEditedPostAttribute( 'featured_media' ); @@ -258,6 +318,12 @@ const applyWithSelect = withSelect( ( select ) => { currentPostId: getCurrentPostId(), postType: getPostType( getEditedPostAttribute( 'type' ) ), featuredImageId, + isRequestingFeaturedImageMedia: + !! featuredImageId && + ! hasFinishedResolution( 'getMedia', [ + featuredImageId, + { context: 'view' }, + ] ), }; } ); diff --git a/packages/editor/src/components/post-featured-image/style.scss b/packages/editor/src/components/post-featured-image/style.scss index 30d5cb43403cdf..bf9433faa662d4 100644 --- a/packages/editor/src/components/post-featured-image/style.scss +++ b/packages/editor/src/components/post-featured-image/style.scss @@ -16,11 +16,16 @@ &:hover, &:focus, &:focus-within { - .editor-post-featured-image__actions { + .editor-post-featured-image__actions:not(.editor-post-featured-image__actions-is-requesting-image) { opacity: 1; } } + .editor-post-featured-image__actions.editor-post-featured-image__actions-missing-image { + opacity: 1; + margin-top: $grid-unit-20; + } + .components-drop-zone__content { border-radius: $radius-small; } @@ -72,17 +77,22 @@ } .editor-post-featured-image__actions { - @include reduce-motion("transition"); - bottom: 0; - opacity: 0; // Use opacity instead of visibility so that the buttons remain in the tab order. - padding: $grid-unit-10; - position: absolute; - transition: opacity 50ms ease-out; -} + &:not(.editor-post-featured-image__actions-missing-image) { + @include reduce-motion("transition"); + bottom: 0; + opacity: 0; // Use opacity instead of visibility so that the buttons remain in the tab order. + padding: $grid-unit-10; + position: absolute; + transition: opacity 50ms ease-out; -.editor-post-featured-image__action { - backdrop-filter: blur(16px) saturate(180%); - background: rgba(255, 255, 255, 0.75); - flex-grow: 1; - justify-content: center; + .editor-post-featured-image__action { + backdrop-filter: blur(16px) saturate(180%); + background: rgba(255, 255, 255, 0.75); + } + } + + .editor-post-featured-image__action { + flex-grow: 1; + justify-content: center; + } }