@wordpress/block-editor
Version:
224 lines (202 loc) • 6.27 kB
JavaScript
import { createElement, Fragment } from "@wordpress/element";
/**
* External dependencies
*/
import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { useRef } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { speak } from '@wordpress/a11y';
import { FormFileUpload, NavigableMenu, MenuItem, ToolbarButton, Dropdown, withFilters, Tooltip } from '@wordpress/components';
import { useSelect, withDispatch } from '@wordpress/data';
import { DOWN } from '@wordpress/keycodes';
import { postFeaturedImage, upload, media as mediaIcon } from '@wordpress/icons';
import { compose } from '@wordpress/compose';
import { __unstableStripHTML as stripHTML } from '@wordpress/dom';
import { store as noticesStore } from '@wordpress/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 noop = () => {};
let uniqueId = 0;
const MediaReplaceFlow = ({
mediaURL,
mediaId,
mediaIds,
allowedTypes,
accept,
onError,
onSelect,
onSelectURL,
onToggleFeaturedImage,
useFeaturedImage,
onFilesUpload = noop,
name = __('Replace'),
createNotice,
removeNotice,
children,
multiple = false,
addToGallery,
handleUpload = true,
popoverProps = {
variant: 'toolbar'
}
}) => {
const mediaUpload = useSelect(select => {
return select(blockEditorStore).getSettings().mediaUpload;
}, []);
const canUpload = !!mediaUpload;
const editMediaButtonRef = useRef();
const errorNoticeID = `block-editor/media-replace-flow/error-notice/${++uniqueId}`;
const onUploadError = message => {
const safeMessage = stripHTML(message);
if (onError) {
onError(safeMessage);
return;
} // 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', safeMessage, {
speak: true,
id: errorNoticeID,
isDismissible: true
});
}, 1000);
};
const selectMedia = (media, closeMenu) => {
if (useFeaturedImage && onToggleFeaturedImage) {
onToggleFeaturedImage();
}
closeMenu(); // Calling `onSelect` after the state update since it might unmount the component.
onSelect(media);
speak(__('The media file has been replaced'));
removeNotice(errorNoticeID);
};
const uploadFiles = (event, closeMenu) => {
const files = event.target.files;
if (!handleUpload) {
closeMenu();
return onSelect(files);
}
onFilesUpload(files);
mediaUpload({
allowedTypes,
filesList: files,
onFileChange: ([media]) => {
selectMedia(media, closeMenu);
},
onError: onUploadError
});
};
const openOnArrowDown = event => {
if (event.keyCode === DOWN) {
event.preventDefault();
event.target.click();
}
};
const onlyAllowsImages = () => {
if (!allowedTypes || allowedTypes.length === 0) {
return false;
}
return allowedTypes.every(allowedType => allowedType === 'image' || allowedType.startsWith('image/'));
};
const gallery = multiple && onlyAllowsImages();
return createElement(Dropdown, {
popoverProps: popoverProps,
contentClassName: "block-editor-media-replace-flow__options",
renderToggle: ({
isOpen,
onToggle
}) => createElement(ToolbarButton, {
ref: editMediaButtonRef,
"aria-expanded": isOpen,
"aria-haspopup": "true",
onClick: onToggle,
onKeyDown: openOnArrowDown
}, name),
renderContent: ({
onClose
}) => createElement(Fragment, null, createElement(NavigableMenu, {
className: "block-editor-media-replace-flow__media-upload-menu"
}, createElement(MediaUploadCheck, null, createElement(MediaUpload, {
gallery: gallery,
addToGallery: addToGallery,
multiple: multiple,
value: multiple ? mediaIds : mediaId,
onSelect: media => selectMedia(media, onClose),
allowedTypes: allowedTypes,
render: ({
open
}) => createElement(MenuItem, {
icon: mediaIcon,
onClick: open
}, __('Open Media Library'))
}), createElement(FormFileUpload, {
onChange: event => {
uploadFiles(event, onClose);
},
accept: accept,
multiple: multiple,
render: ({
openFileDialog
}) => {
return createElement(MenuItem, {
icon: upload,
onClick: () => {
openFileDialog();
}
}, __('Upload'));
}
})), onToggleFeaturedImage && createElement(MenuItem, {
icon: postFeaturedImage,
onClick: onToggleFeaturedImage,
isPressed: useFeaturedImage
}, __('Use featured image')), children), onSelectURL && // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
createElement("form", {
className: classnames('block-editor-media-flow__url-input', {
'has-siblings': canUpload || onToggleFeaturedImage
})
}, createElement("span", {
className: "block-editor-media-replace-flow__image-url-label"
}, __('Current media URL:')), createElement(Tooltip, {
text: mediaURL,
position: "bottom"
}, createElement("div", null, createElement(LinkControl, {
value: {
url: mediaURL
},
settings: [],
showSuggestions: false,
onChange: ({
url
}) => {
onSelectURL(url);
editMediaButtonRef.current.focus();
}
})))))
});
};
/**
* @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/media-replace-flow/README.md
*/
export default compose([withDispatch(dispatch => {
const {
createNotice,
removeNotice
} = dispatch(noticesStore);
return {
createNotice,
removeNotice
};
}), withFilters('editor.MediaReplaceFlow')])(MediaReplaceFlow);
//# sourceMappingURL=index.js.map