UNPKG

@wordpress/block-library

Version:
172 lines (166 loc) 4.53 kB
/** * WordPress dependencies */ import { Button, DropZone, FlexBlock, Spinner, __experimentalItemGroup as ItemGroup, __experimentalHStack as HStack, __experimentalTruncate as Truncate, } from '@wordpress/components'; import { MediaReplaceFlow, store as blockEditorStore, } from '@wordpress/block-editor'; import { focus } from '@wordpress/dom'; import { useRef } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { useSelect } from '@wordpress/data'; import { reset as resetIcon } from '@wordpress/icons'; import { getFilename } from '@wordpress/url'; /** * Focuses the toggle button. * * @param {Object} containerRef - ref object containing current element */ const focusToggleButton = ( containerRef ) => { // Use requestAnimationFrame to ensure DOM updates are complete. window.requestAnimationFrame( () => { const [ toggleButton ] = focus.tabbable.find( containerRef?.current ); if ( ! toggleButton ) { return; } toggleButton.focus(); } ); }; /** * MediaControlPreview - Preview component showing media thumbnail and filename * * @param {Object} props * @param {string} props.url Media URL for thumbnail * @param {string} props.filename Filename to display * @param {Object} props.itemGroupProps Optional props to pass to ItemGroup * @param {string} props.className Optional className for Truncate * @param {string} props.label Optional label for accessibility * @return {Element} Preview component */ export function MediaControlPreview( { url, filename, itemGroupProps, className, label, } ) { return ( <ItemGroup { ...itemGroupProps } as="span"> <HStack justify="flex-start"> <span className="block-library-utils__media-control__inspector-image-indicator" style={ { backgroundImage: url ? `url(${ url })` : undefined, } } /> <FlexBlock> <Truncate numberOfLines={ 1 } className={ className }> { filename ?? label } </Truncate> </FlexBlock> </HStack> </ItemGroup> ); } /** * MediaControl - Complete media selection control for inspector panels * * @param {Object} props * @param {number} props.mediaId Media attachment ID * @param {string} props.mediaUrl Media URL * @param {string} props.filename Filename to display * @param {Array} props.allowedTypes Allowed media types * @param {Function} props.onSelect Callback when media selected * @param {Function} props.onSelectURL Callback when URL entered * @param {Function} props.onError Error callback * @param {Function} props.onReset Reset/remove callback * @param {boolean} props.isUploading Whether upload in progress * @param {string} props.emptyLabel Label when no media (default: 'Add media') * @return {Element} Media control component */ export function MediaControl( { mediaId, mediaUrl, filename, allowedTypes, onSelect, onSelectURL, onError, onReset, isUploading = false, emptyLabel = __( 'Media' ), } ) { const { getSettings } = useSelect( blockEditorStore ); const onFilesDrop = ( filesList ) => { const { mediaUpload } = getSettings(); if ( ! mediaUpload ) { return; } mediaUpload( { allowedTypes, filesList, onFileChange( [ media ] ) { onSelect( media ); }, onError, multiple: false, } ); }; const containerRef = useRef(); return ( <div ref={ containerRef } className="block-library-utils__media-control" > <MediaReplaceFlow className="block-library-utils__media-control__replace-flow" mediaId={ mediaId } mediaURL={ mediaUrl } allowedTypes={ allowedTypes } onSelect={ onSelect } onSelectURL={ onSelectURL } onError={ onError } name={ <MediaControlPreview url={ mediaUrl } filename={ filename } className="block-library-utils__media-control__inspector-media-replace-title" label={ mediaUrl ? getFilename( filename ) || emptyLabel : emptyLabel } /> } renderToggle={ ( props ) => ( <Button { ...props } __next40pxDefaultSize> { isUploading ? <Spinner /> : props.children } </Button> ) } onReset={ onReset } /> { mediaUrl && onReset && ( <Button label={ __( 'Reset' ) } className="block-library-utils__media-control__reset" size="small" icon={ resetIcon } onClick={ () => { onReset(); focusToggleButton( containerRef ); } } /> ) } <DropZone onFilesDrop={ onFilesDrop } /> </div> ); }