UNPKG

@wordpress/block-editor

Version:
447 lines (441 loc) 15.7 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.MediaPlaceholder = MediaPlaceholder; exports.default = void 0; var _clsx = _interopRequireDefault(require("clsx")); var _components = require("@wordpress/components"); var _i18n = require("@wordpress/i18n"); var _element = require("@wordpress/element"); var _data = require("@wordpress/data"); var _icons = require("@wordpress/icons"); var _deprecated = _interopRequireDefault(require("@wordpress/deprecated")); var _mediaUpload = _interopRequireDefault(require("../media-upload")); var _check = _interopRequireDefault(require("../media-upload/check")); var _urlPopover = _interopRequireDefault(require("../url-popover")); var _store = require("../../store"); var _useOnBlockDrop = require("../use-on-block-drop"); var _jsxRuntime = require("react/jsx-runtime"); /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ const noop = () => {}; const InsertFromURLPopover = ({ src, onChange, onSubmit, onClose, popoverAnchor }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_urlPopover.default, { anchor: popoverAnchor, onClose: onClose, children: /*#__PURE__*/(0, _jsxRuntime.jsx)("form", { className: "block-editor-media-placeholder__url-input-form", onSubmit: onSubmit, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalInputControl, { __next40pxDefaultSize: true, label: (0, _i18n.__)('URL'), type: "url", hideLabelFromVision: true, placeholder: (0, _i18n.__)('Paste or type URL'), onChange: onChange, value: src, suffix: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalInputControlSuffixWrapper, { variant: "control", children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Button, { size: "small", icon: _icons.keyboardReturn, label: (0, _i18n.__)('Apply'), type: "submit" }) }) }) }) }); const URLSelectionUI = ({ src, onChangeSrc, onSelectURL }) => { // Use internal state instead of a ref to make sure that the component // re-renders when the popover's anchor updates. const [popoverAnchor, setPopoverAnchor] = (0, _element.useState)(null); const [isURLInputVisible, setIsURLInputVisible] = (0, _element.useState)(false); const openURLInput = () => { setIsURLInputVisible(true); }; const closeURLInput = () => { setIsURLInputVisible(false); popoverAnchor?.focus(); }; const onSubmitSrc = event => { event.preventDefault(); if (src && onSelectURL) { onSelectURL(src); closeURLInput(); } }; return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", { className: "block-editor-media-placeholder__url-input-container", children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Button, { __next40pxDefaultSize: true, className: "block-editor-media-placeholder__button", onClick: openURLInput, isPressed: isURLInputVisible, variant: "secondary", "aria-haspopup": "dialog", ref: setPopoverAnchor, children: (0, _i18n.__)('Insert from URL') }), isURLInputVisible && /*#__PURE__*/(0, _jsxRuntime.jsx)(InsertFromURLPopover, { src: src, onChange: onChangeSrc, onSubmit: onSubmitSrc, onClose: closeURLInput, popoverAnchor: popoverAnchor })] }); }; function MediaPlaceholder({ value = {}, allowedTypes, className, icon, labels = {}, mediaPreview, notices, isAppender, accept, addToGallery, multiple = false, handleUpload = true, disableDropZone, disableMediaButtons, onError, onSelect, onCancel, onSelectURL, onToggleFeaturedImage, onDoubleClick, onFilesPreUpload = noop, onHTMLDrop: deprecatedOnHTMLDrop, children, mediaLibraryButton, placeholder, style }) { if (deprecatedOnHTMLDrop) { (0, _deprecated.default)('wp.blockEditor.MediaPlaceholder onHTMLDrop prop', { since: '6.2', version: '6.4' }); } const mediaUpload = (0, _data.useSelect)(select => { const { getSettings } = select(_store.store); return getSettings().mediaUpload; }, []); const [src, setSrc] = (0, _element.useState)(''); (0, _element.useEffect)(() => { var _value$src; setSrc((_value$src = value?.src) !== null && _value$src !== void 0 ? _value$src : ''); }, [value?.src]); const onlyAllowsImages = () => { if (!allowedTypes || allowedTypes.length === 0) { return false; } return allowedTypes.every(allowedType => allowedType === 'image' || allowedType.startsWith('image/')); }; const onFilesUpload = files => { if (!handleUpload || typeof handleUpload === 'function' && !handleUpload(files)) { return onSelect(files); } onFilesPreUpload(files); let setMedia; if (multiple) { if (addToGallery) { // Since the setMedia function runs multiple times per upload group // and is passed newMedia containing every item in its group each time, we must // filter out whatever this upload group had previously returned to the // gallery before adding and returning the image array with replacement newMedia // values. // Define an array to store urls from newMedia between subsequent function calls. let lastMediaPassed = []; setMedia = newMedia => { // Remove any images this upload group is responsible for (lastMediaPassed). // Their replacements are contained in newMedia. const filteredMedia = (value !== null && value !== void 0 ? value : []).filter(item => { // If Item has id, only remove it if lastMediaPassed has an item with that id. if (item.id) { return !lastMediaPassed.some( // Be sure to convert to number for comparison. ({ id }) => Number(id) === Number(item.id)); } // Compare transient images via .includes since gallery may append extra info onto the url. return !lastMediaPassed.some(({ urlSlug }) => item.url.includes(urlSlug)); }); // Return the filtered media array along with newMedia. onSelect(filteredMedia.concat(newMedia)); // Reset lastMediaPassed and set it with ids and urls from newMedia. lastMediaPassed = newMedia.map(media => { // Add everything up to '.fileType' to compare via .includes. const cutOffIndex = media.url.lastIndexOf('.'); const urlSlug = media.url.slice(0, cutOffIndex); return { id: media.id, urlSlug }; }); }; } else { setMedia = onSelect; } } else { setMedia = ([media]) => onSelect(media); } mediaUpload({ allowedTypes, filesList: files, onFileChange: setMedia, onError, multiple }); }; async function handleBlocksDrop(event) { const { blocks } = (0, _useOnBlockDrop.parseDropEvent)(event); if (!blocks?.length) { return; } const uploadedMediaList = await Promise.all(blocks.map(block => { const blockType = block.name.split('/')[1]; if (block.attributes.id) { block.attributes.type = blockType; return block.attributes; } return new Promise((resolve, reject) => { window.fetch(block.attributes.url).then(response => response.blob()).then(blob => mediaUpload({ filesList: [blob], additionalData: { title: block.attributes.title, alt_text: block.attributes.alt, caption: block.attributes.caption, type: blockType }, onFileChange: ([media]) => { if (media.id) { resolve(media); } }, allowedTypes, onError: reject })).catch(() => resolve(block.attributes.url)); }); })).catch(err => onError(err)); if (multiple) { onSelect(uploadedMediaList); } else { onSelect(uploadedMediaList[0]); } } const onUpload = event => { onFilesUpload(event.target.files); }; const defaultRenderPlaceholder = content => { let { instructions, title } = labels; if (!mediaUpload && !onSelectURL) { instructions = (0, _i18n.__)('To edit this block, you need permission to upload media.'); } if (instructions === undefined || title === undefined) { const typesAllowed = allowedTypes !== null && allowedTypes !== void 0 ? allowedTypes : []; const [firstAllowedType] = typesAllowed; const isOneType = 1 === typesAllowed.length; const isAudio = isOneType && 'audio' === firstAllowedType; const isImage = isOneType && 'image' === firstAllowedType; const isVideo = isOneType && 'video' === firstAllowedType; if (instructions === undefined && mediaUpload) { instructions = (0, _i18n.__)('Drag and drop an image or video, upload, or choose from your library.'); if (isAudio) { instructions = (0, _i18n.__)('Drag and drop an audio file, upload, or choose from your library.'); } else if (isImage) { instructions = (0, _i18n.__)('Drag and drop an image, upload, or choose from your library.'); } else if (isVideo) { instructions = (0, _i18n.__)('Drag and drop a video, upload, or choose from your library.'); } } if (title === undefined) { title = (0, _i18n.__)('Media'); if (isAudio) { title = (0, _i18n.__)('Audio'); } else if (isImage) { title = (0, _i18n.__)('Image'); } else if (isVideo) { title = (0, _i18n.__)('Video'); } } } const placeholderClassName = (0, _clsx.default)('block-editor-media-placeholder', className, { 'is-appender': isAppender }); return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.Placeholder, { icon: icon, label: title, instructions: instructions, className: placeholderClassName, notices: notices, onDoubleClick: onDoubleClick, preview: mediaPreview, style: style, children: [content, children] }); }; const renderPlaceholder = placeholder !== null && placeholder !== void 0 ? placeholder : defaultRenderPlaceholder; const renderDropZone = () => { if (disableDropZone) { return null; } return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.DropZone, { onFilesDrop: onFilesUpload, onDrop: handleBlocksDrop, isEligible: dataTransfer => { const prefix = 'wp-block:core/'; const types = []; for (const type of dataTransfer.types) { if (type.startsWith(prefix)) { types.push(type.slice(prefix.length)); } } return types.every(type => allowedTypes.includes(type)) && (multiple ? true : types.length === 1); } }); }; const renderCancelLink = () => { return onCancel && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Button, { __next40pxDefaultSize: true, className: "block-editor-media-placeholder__cancel-button", title: (0, _i18n.__)('Cancel'), variant: "link", onClick: onCancel, children: (0, _i18n.__)('Cancel') }); }; const renderUrlSelectionUI = () => { return onSelectURL && /*#__PURE__*/(0, _jsxRuntime.jsx)(URLSelectionUI, { src: src, onChangeSrc: setSrc, onSelectURL: onSelectURL }); }; const renderFeaturedImageToggle = () => { return onToggleFeaturedImage && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", { className: "block-editor-media-placeholder__url-input-container", children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Button, { __next40pxDefaultSize: true, className: "block-editor-media-placeholder__button", onClick: onToggleFeaturedImage, variant: "secondary", children: (0, _i18n.__)('Use featured image') }) }); }; const renderMediaUploadChecked = () => { const defaultButton = ({ open }) => { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Button, { __next40pxDefaultSize: true, variant: "secondary", onClick: () => { open(); }, children: (0, _i18n.__)('Media Library') }); }; const libraryButton = mediaLibraryButton !== null && mediaLibraryButton !== void 0 ? mediaLibraryButton : defaultButton; const uploadMediaLibraryButton = /*#__PURE__*/(0, _jsxRuntime.jsx)(_mediaUpload.default, { addToGallery: addToGallery, gallery: multiple && onlyAllowsImages(), multiple: multiple, onSelect: onSelect, allowedTypes: allowedTypes, mode: "browse", value: Array.isArray(value) ? value.map(({ id }) => id) : value.id, render: libraryButton }); if (mediaUpload && isAppender) { return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [renderDropZone(), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.FormFileUpload, { onChange: onUpload, accept: accept, multiple: !!multiple, render: ({ openFileDialog }) => { const content = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Button, { __next40pxDefaultSize: true, variant: "primary", className: (0, _clsx.default)('block-editor-media-placeholder__button', 'block-editor-media-placeholder__upload-button'), onClick: openFileDialog, children: (0, _i18n._x)('Upload', 'verb') }), uploadMediaLibraryButton, renderUrlSelectionUI(), renderFeaturedImageToggle(), renderCancelLink()] }); return renderPlaceholder(content); } })] }); } if (mediaUpload) { const content = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, { children: [renderDropZone(), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.FormFileUpload, { render: ({ openFileDialog }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Button, { __next40pxDefaultSize: true, onClick: openFileDialog, variant: "primary", className: (0, _clsx.default)('block-editor-media-placeholder__button', 'block-editor-media-placeholder__upload-button'), children: (0, _i18n._x)('Upload', 'verb') }), onChange: onUpload, accept: accept, multiple: !!multiple }), uploadMediaLibraryButton, renderUrlSelectionUI(), renderFeaturedImageToggle(), renderCancelLink()] }); return renderPlaceholder(content); } return renderPlaceholder(uploadMediaLibraryButton); }; if (disableMediaButtons) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_check.default, { children: renderDropZone() }); } return /*#__PURE__*/(0, _jsxRuntime.jsx)(_check.default, { fallback: renderPlaceholder(renderUrlSelectionUI()), children: renderMediaUploadChecked() }); } /** * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/media-placeholder/README.md */ var _default = exports.default = (0, _components.withFilters)('editor.MediaPlaceholder')(MediaPlaceholder); //# sourceMappingURL=index.js.map