@wordpress/block-editor
Version:
266 lines (265 loc) • 8.88 kB
JavaScript
// packages/block-editor/src/components/inserter/media-tab/media-preview.js
import clsx from "clsx";
import {
Tooltip,
DropdownMenu,
MenuGroup,
MenuItem,
Spinner,
Modal,
Flex,
FlexItem,
Button,
Composite,
__experimentalVStack as VStack
} from "@wordpress/components";
import { __, sprintf } from "@wordpress/i18n";
import { useMemo, useCallback, useState } from "@wordpress/element";
import { cloneBlock } from "@wordpress/blocks";
import { moreVertical, external } from "@wordpress/icons";
import { useSelect, useDispatch } from "@wordpress/data";
import { store as noticesStore } from "@wordpress/notices";
import { isBlobURL } from "@wordpress/blob";
import { getFilename } from "@wordpress/url";
import InserterDraggableBlocks from "../../inserter-draggable-blocks/index.mjs";
import { getBlockAndPreviewFromMedia } from "./utils.mjs";
import { store as blockEditorStore } from "../../../store/index.mjs";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
var ALLOWED_MEDIA_TYPES = ["image"];
var MEDIA_OPTIONS_POPOVER_PROPS = {
placement: "bottom-end",
className: "block-editor-inserter__media-list__item-preview-options__popover"
};
function MediaPreviewOptions({ category, media }) {
if (!category.getReportUrl) {
return null;
}
const reportUrl = category.getReportUrl(media);
return /* @__PURE__ */ jsx(
DropdownMenu,
{
className: "block-editor-inserter__media-list__item-preview-options",
label: __("Options"),
popoverProps: MEDIA_OPTIONS_POPOVER_PROPS,
icon: moreVertical,
children: () => /* @__PURE__ */ jsx(MenuGroup, { children: /* @__PURE__ */ jsx(
MenuItem,
{
onClick: () => window.open(reportUrl, "_blank").focus(),
icon: external,
children: sprintf(
/* translators: %s: The media type to report e.g: "image", "video", "audio" */
__("Report %s"),
category.mediaType
)
}
) })
}
);
}
function InsertExternalImageModal({ onClose, onSubmit }) {
return /* @__PURE__ */ jsxs(
Modal,
{
title: __("Insert external image"),
onRequestClose: onClose,
className: "block-editor-inserter-media-tab-media-preview-inserter-external-image-modal",
children: [
/* @__PURE__ */ jsxs(VStack, { spacing: 3, children: [
/* @__PURE__ */ jsx("p", { children: __(
"This image cannot be uploaded to your Media Library, but it can still be inserted as an external image."
) }),
/* @__PURE__ */ jsx("p", { children: __(
"External images can be removed by the external provider without warning and could even have legal compliance issues related to privacy legislation."
) })
] }),
/* @__PURE__ */ jsxs(
Flex,
{
className: "block-editor-block-lock-modal__actions",
justify: "flex-end",
expanded: false,
children: [
/* @__PURE__ */ jsx(FlexItem, { children: /* @__PURE__ */ jsx(
Button,
{
__next40pxDefaultSize: true,
variant: "tertiary",
onClick: onClose,
children: __("Cancel")
}
) }),
/* @__PURE__ */ jsx(FlexItem, { children: /* @__PURE__ */ jsx(
Button,
{
__next40pxDefaultSize: true,
variant: "primary",
onClick: onSubmit,
children: __("Insert")
}
) })
]
}
)
]
}
);
}
function MediaPreview({ media, onClick, category }) {
const [showExternalUploadModal, setShowExternalUploadModal] = useState(false);
const [isHovered, setIsHovered] = useState(false);
const [isInserting, setIsInserting] = useState(false);
const [block, preview] = useMemo(
() => getBlockAndPreviewFromMedia(media, category.mediaType),
[media, category.mediaType]
);
const { createErrorNotice, createSuccessNotice } = useDispatch(noticesStore);
const { getSettings, getBlock } = useSelect(blockEditorStore);
const { updateBlockAttributes } = useDispatch(blockEditorStore);
const onMediaInsert = useCallback(
(previewBlock) => {
if (isInserting) {
return;
}
const settings = getSettings();
const clonedBlock = cloneBlock(previewBlock);
const { id, url, caption } = clonedBlock.attributes;
if (!id && !settings.mediaUpload) {
setShowExternalUploadModal(true);
return;
}
if (!!id) {
onClick(clonedBlock);
return;
}
setIsInserting(true);
window.fetch(url).then((response) => response.blob()).then((blob) => {
const fileName = getFilename(url) || "image.jpg";
const file = new File([blob], fileName, {
type: blob.type
});
settings.mediaUpload({
filesList: [file],
additionalData: { caption },
onFileChange([img]) {
if (isBlobURL(img.url)) {
return;
}
if (!getBlock(clonedBlock.clientId)) {
onClick({
...clonedBlock,
attributes: {
...clonedBlock.attributes,
id: img.id,
url: img.url
}
});
createSuccessNotice(
__("Image uploaded and inserted."),
{ type: "snackbar", id: "inserter-notice" }
);
} else {
updateBlockAttributes(clonedBlock.clientId, {
...clonedBlock.attributes,
id: img.id,
url: img.url
});
}
setIsInserting(false);
},
allowedTypes: ALLOWED_MEDIA_TYPES,
onError(message) {
createErrorNotice(message, {
type: "snackbar",
id: "inserter-notice"
});
setIsInserting(false);
}
});
}).catch(() => {
setShowExternalUploadModal(true);
setIsInserting(false);
});
},
[
isInserting,
getSettings,
onClick,
createSuccessNotice,
updateBlockAttributes,
createErrorNotice,
getBlock
]
);
const title = typeof media.title === "string" ? media.title : media.title?.rendered || __("no title");
const onMouseEnter = useCallback(() => setIsHovered(true), []);
const onMouseLeave = useCallback(() => setIsHovered(false), []);
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(InserterDraggableBlocks, { isEnabled: true, blocks: [block], children: ({ draggable, onDragStart, onDragEnd }) => /* @__PURE__ */ jsx(
"div",
{
className: clsx(
"block-editor-inserter__media-list__list-item",
{
"is-hovered": isHovered
}
),
draggable,
onDragStart,
onDragEnd,
children: /* @__PURE__ */ jsxs(
"div",
{
onMouseEnter,
onMouseLeave,
children: [
/* @__PURE__ */ jsx(Tooltip, { text: title, children: /* @__PURE__ */ jsx(
Composite.Item,
{
render: /* @__PURE__ */ jsx(
"div",
{
"aria-label": title,
role: "option",
className: "block-editor-inserter__media-list__item"
}
),
onClick: () => onMediaInsert(block),
children: /* @__PURE__ */ jsxs("div", { className: "block-editor-inserter__media-list__item-preview", children: [
preview,
isInserting && /* @__PURE__ */ jsx("div", { className: "block-editor-inserter__media-list__item-preview-spinner", children: /* @__PURE__ */ jsx(Spinner, {}) })
] })
}
) }),
!isInserting && /* @__PURE__ */ jsx(
MediaPreviewOptions,
{
category,
media
}
)
]
}
)
}
) }),
showExternalUploadModal && /* @__PURE__ */ jsx(
InsertExternalImageModal,
{
onClose: () => setShowExternalUploadModal(false),
onSubmit: () => {
onClick(cloneBlock(block));
createSuccessNotice(__("Image inserted."), {
type: "snackbar",
id: "inserter-notice"
});
setShowExternalUploadModal(false);
}
}
)
] });
}
export {
MediaPreview
};
//# sourceMappingURL=media-preview.mjs.map