Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 62 additions & 17 deletions packages/block-library/src/utils/poster-image.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,73 @@ import clsx from 'clsx';
/**
* WordPress dependencies
*/
import { MediaUpload, MediaUploadCheck } from '@wordpress/block-editor';
import {
MediaUpload,
MediaUploadCheck,
store as blockEditorStore,
} from '@wordpress/block-editor';
import { store as noticesStore } from '@wordpress/notices';
import {
Button,
BaseControl,
DropZone,
Spinner,
__experimentalHStack as HStack,
__experimentalToolsPanelItem as ToolsPanelItem,
} from '@wordpress/components';
import { isBlobURL } from '@wordpress/blob';
import { __, sprintf } from '@wordpress/i18n';
import { useRef } from '@wordpress/element';
import { useRef, useState } from '@wordpress/element';
import { useInstanceId } from '@wordpress/compose';
import { useSelect, useDispatch } from '@wordpress/data';

const POSTER_IMAGE_ALLOWED_MEDIA_TYPES = [ 'image' ];

function PosterImage( { poster, onChange } ) {
const posterButtonRef = useRef();
const [ isLoading, setIsLoading ] = useState( false );
const descriptionId = useInstanceId(
PosterImage,
'block-library-poster-image-description'
);

const { getSettings } = useSelect( blockEditorStore );
const { createErrorNotice } = useDispatch( noticesStore );

const onDropFiles = ( filesList ) => {
getSettings().mediaUpload( {
allowedTypes: POSTER_IMAGE_ALLOWED_MEDIA_TYPES,
filesList,
onFileChange: ( [ image ] ) => {
if ( isBlobURL( image?.url ) ) {
setIsLoading( true );
return;
}

if ( image ) {
onChange( image );
}
setIsLoading( false );
},
onError: ( message ) => {
createErrorNotice( message, {
id: 'poster-image-upload-notice',
type: 'snackbar',
} );
setIsLoading( false );
},
multiple: false,
} );
};

const getPosterButtonContent = () => {
if ( ! poster && isLoading ) {
return <Spinner />;
}

return ! poster ? __( 'Set poster image' ) : __( 'Replace' );
};

return (
<MediaUploadCheck>
<ToolsPanelItem
Expand All @@ -48,24 +95,19 @@ function PosterImage( { poster, onChange } ) {
__next40pxDefaultSize
onClick={ open }
aria-haspopup="dialog"
aria-label={
! poster
? null
: __(
'Edit or replace the poster image.'
)
}
className={
poster
? 'block-library-poster-image__preview'
: 'block-library-poster-image__toggle'
}
aria-label={ __(
'Edit or replace the poster image.'
) }
className="block-library-poster-image__preview"
disabled={ isLoading }
accessibleWhenDisabled
>
<img
src={ poster }
alt={ __( 'Poster image preview' ) }
className="block-library-poster-image__preview-image"
/>
{ isLoading && <Spinner /> }
</Button>
) }
<HStack
Expand All @@ -87,10 +129,10 @@ function PosterImage( { poster, onChange } ) {
variant={
! poster ? 'secondary' : undefined
}
disabled={ isLoading }
accessibleWhenDisabled
>
{ ! poster
? __( 'Set poster image' )
: __( 'Replace' ) }
{ getPosterButtonContent() }
</Button>
<p id={ descriptionId } hidden>
{ poster
Expand All @@ -115,11 +157,14 @@ function PosterImage( { poster, onChange } ) {
posterButtonRef.current.focus();
} }
className="block-library-poster-image__action"
disabled={ isLoading }
accessibleWhenDisabled
>
{ __( 'Remove' ) }
</Button>
) }
</HStack>
<DropZone onFilesDrop={ onDropFiles } />
</div>
) }
/>
Expand Down
39 changes: 23 additions & 16 deletions packages/block-library/src/utils/poster-image.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,31 @@
opacity: 1;
margin-top: $grid-unit-20;
}

.components-drop-zone__content {
border-radius: $radius-small;
}

// Align text and icons horizontally to avoid clipping when the poster image is not set.
.components-drop-zone .components-drop-zone__content-inner {
display: flex;
align-items: center;
gap: $grid-unit-10;

.components-drop-zone__content-icon {
margin: 0;
}
}

.components-spinner {
position: absolute;
top: 50%;
left: 50%;
margin-top: -9px;
margin-left: -9px;
}
}

.block-library-poster-image__toggle,
.block-library-poster-image__preview {
width: 100%;
padding: 0;
Expand All @@ -25,9 +47,6 @@

display: flex;
justify-content: center;
}

.block-library-poster-image__preview {
height: auto !important;
outline: $border-width solid rgba($black, 0.1);

Expand All @@ -39,18 +58,6 @@
}
}

.block-library-poster-image__toggle {
box-shadow: inset 0 0 0 $border-width $gray-400;

&:focus:not(:disabled) {
// Allow smooth transition between focused and unfocused box-shadow states.
box-shadow:
0 0 0 currentColor inset,
0 0 0 var(--wp-admin-border-width-focus)
var(--wp-admin-theme-color);
}
}

.block-library-poster-image__actions {
&:not(.block-library-poster-image__actions-select) {
bottom: 0;
Expand Down
Loading