UNPKG

@gechiui/block-editor

Version:
201 lines (189 loc) 5.26 kB
/** * External dependencies */ import { uniqueId, noop } from 'lodash'; /** * GeChiUI dependencies */ import { useState, createRef, renderToString } from '@gechiui/element'; import { __ } from '@gechiui/i18n'; import { speak } from '@gechiui/a11y'; import { FormFileUpload, NavigableMenu, MenuItem, ToolbarButton, Dropdown, withFilters, } from '@gechiui/components'; import { withDispatch, useSelect } from '@gechiui/data'; import { DOWN } from '@gechiui/keycodes'; import { compose } from '@gechiui/compose'; import { upload, media as mediaIcon } from '@gechiui/icons'; import { store as noticesStore } from '@gechiui/notices'; /** * Internal dependencies */ import MediaUpload from '../media-upload'; import MediaUploadCheck from '../media-upload/check'; import LinkControl from '../link-control'; import { store as blockEditorStore } from '../../store'; const MediaReplaceFlow = ( { mediaURL, mediaId, allowedTypes, accept, onSelect, onSelectURL, onFilesUpload = noop, name = __( '替换' ), createNotice, removeNotice, children, } ) => { const [ mediaURLValue, setMediaURLValue ] = useState( mediaURL ); const mediaUpload = useSelect( ( select ) => { return select( blockEditorStore ).getSettings().mediaUpload; }, [] ); const editMediaButtonRef = createRef(); const errorNoticeID = uniqueId( 'block-editor/media-replace-flow/error-notice/' ); const onError = ( message ) => { const errorElement = document.createElement( 'div' ); errorElement.innerHTML = renderToString( message ); // The default error contains some HTML that, // for example, makes the filename bold. // The notice, by default, accepts strings only and so // we need to remove the html from the error. const renderMsg = errorElement.textContent || errorElement.innerText || ''; // We need to set a timeout for showing the notice // so that VoiceOver and possibly other screen readers // can announce the error afer the toolbar button // regains focus once the upload dialog closes. // Otherwise VO simply skips over the notice and announces // the focused element and the open menu. setTimeout( () => { createNotice( 'error', renderMsg, { speak: true, id: errorNoticeID, isDismissible: true, } ); }, 1000 ); }; const selectMedia = ( media ) => { setMediaURLValue( media.url ); // Calling `onSelect` after the state update since it might unmount the component. onSelect( media ); speak( __( '此媒体文件已被替换' ) ); removeNotice( errorNoticeID ); }; const selectURL = ( newURL ) => { onSelectURL( newURL ); }; const uploadFiles = ( event ) => { const files = event.target.files; onFilesUpload( files ); const setMedia = ( [ media ] ) => { selectMedia( media ); }; mediaUpload( { allowedTypes, filesList: files, onFileChange: setMedia, onError, } ); }; const openOnArrowDown = ( event ) => { if ( event.keyCode === DOWN ) { event.preventDefault(); event.target.click(); } }; const POPOVER_PROPS = { isAlternate: true, }; return ( <Dropdown popoverProps={ POPOVER_PROPS } contentClassName="block-editor-media-replace-flow__options" renderToggle={ ( { isOpen, onToggle } ) => ( <ToolbarButton ref={ editMediaButtonRef } aria-expanded={ isOpen } aria-haspopup="true" onClick={ onToggle } onKeyDown={ openOnArrowDown } > { name } </ToolbarButton> ) } renderContent={ ( { onClose } ) => ( <> <NavigableMenu className="block-editor-media-replace-flow__media-upload-menu"> <MediaUpload value={ mediaId } onSelect={ ( media ) => selectMedia( media ) } allowedTypes={ allowedTypes } render={ ( { open } ) => ( <MenuItem icon={ mediaIcon } onClick={ open }> { __( '打开媒体库' ) } </MenuItem> ) } /> <MediaUploadCheck> <FormFileUpload onChange={ ( event ) => { uploadFiles( event, onClose ); } } accept={ accept } render={ ( { openFileDialog } ) => { return ( <MenuItem icon={ upload } onClick={ () => { openFileDialog(); } } > { __( '上传' ) } </MenuItem> ); } } /> </MediaUploadCheck> { children } </NavigableMenu> { onSelectURL && ( // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions <form className="block-editor-media-flow__url-input"> <span className="block-editor-media-replace-flow__image-url-label"> { __( '当前媒体网址:' ) } </span> <LinkControl value={ { url: mediaURLValue } } settings={ [] } showSuggestions={ false } onChange={ ( { url } ) => { setMediaURLValue( url ); selectURL( url ); editMediaButtonRef.current.focus(); } } /> </form> ) } </> ) } /> ); }; export default compose( [ withDispatch( ( dispatch ) => { const { createNotice, removeNotice } = dispatch( noticesStore ); return { createNotice, removeNotice, }; } ), withFilters( 'editor.MediaReplaceFlow' ), ] )( MediaReplaceFlow );