UNPKG

@wordpress/block-library

Version:
905 lines (903 loc) 35 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // packages/block-library/src/image/image.js var image_exports = {}; __export(image_exports, { default: () => Image }); module.exports = __toCommonJS(image_exports); var import_blob = require("@wordpress/blob"); var import_components = require("@wordpress/components"); var import_compose = require("@wordpress/compose"); var import_data = require("@wordpress/data"); var import_block_editor = require("@wordpress/block-editor"); var import_element = require("@wordpress/element"); var import_i18n = require("@wordpress/i18n"); var import_url = require("@wordpress/url"); var import_blocks = require("@wordpress/blocks"); var import_icons = require("@wordpress/icons"); var import_notices = require("@wordpress/notices"); var import_core_data = require("@wordpress/core-data"); var import_lock_unlock = require("../lock-unlock"); var import_util = require("../embed/util"); var import_edit = require("./edit"); var import_caption = require("../utils/caption"); var import_hooks = require("../utils/hooks"); var import_constants = require("./constants"); var import_utils = require("./utils"); var import_jsx_runtime = require("react/jsx-runtime"); var { DimensionsTool, ResolutionTool } = (0, import_lock_unlock.unlock)(import_block_editor.privateApis); var scaleOptions = [ { value: "cover", label: (0, import_i18n._x)("Cover", "Scale option for dimensions control"), help: (0, import_i18n.__)("Image covers the space evenly.") }, { value: "contain", label: (0, import_i18n._x)("Contain", "Scale option for dimensions control"), help: (0, import_i18n.__)("Image is contained without distortion.") } ]; var WRITEMODE_POPOVER_PROPS = { placement: "bottom-start" }; var ImageWrapper = ({ href, children }) => { if (!href) { return children; } return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( "a", { href, onClick: (event) => event.preventDefault(), "aria-disabled": true, style: { // When the Image block is linked, // it's wrapped with a disabled <a /> tag. // Restore cursor style so it doesn't appear 'clickable' // and remove pointer events. Safari needs the display property. pointerEvents: "none", cursor: "default", display: "inline" }, children } ); }; function ContentOnlyControls({ attributes, setAttributes, lockAltControls, lockAltControlsMessage, lockTitleControls, lockTitleControlsMessage }) { const [popoverAnchor, setPopoverAnchor] = (0, import_element.useState)(null); const [isAltDialogOpen, setIsAltDialogOpen] = (0, import_element.useState)(false); const [isTitleDialogOpen, setIsTitleDialogOpen] = (0, import_element.useState)(false); return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.ToolbarItem, { ref: setPopoverAnchor, children: (toggleProps) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.DropdownMenu, { icon: import_icons.chevronDown, label: (0, import_i18n.__)("More"), toggleProps: { ...toggleProps, description: (0, import_i18n.__)("Displays more controls.") }, popoverProps: WRITEMODE_POPOVER_PROPS, children: ({ onClose }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.MenuItem, { onClick: () => { setIsAltDialogOpen(true); onClose(); }, "aria-haspopup": "dialog", children: (0, import_i18n._x)( "Alternative text", "Alternative text for an image. Block toolbar label, a low character count is preferred." ) } ), /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.MenuItem, { onClick: () => { setIsTitleDialogOpen(true); onClose(); }, "aria-haspopup": "dialog", children: (0, import_i18n.__)("Title text") } ) ] }) } ) }), isAltDialogOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.Popover, { placement: "bottom-start", anchor: popoverAnchor, onClose: () => setIsAltDialogOpen(false), offset: 13, variant: "toolbar", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "wp-block-image__toolbar_content_textarea__container", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.TextareaControl, { className: "wp-block-image__toolbar_content_textarea", label: (0, import_i18n.__)("Alternative text"), value: attributes.alt || "", onChange: (value) => setAttributes({ alt: value }), disabled: lockAltControls, help: lockAltControls ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: lockAltControlsMessage }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.ExternalLink, { href: ( // translators: Localized tutorial, if one exists. W3C Web Accessibility Initiative link has list of existing translations. (0, import_i18n.__)( "https://www.w3.org/WAI/tutorials/images/decision-tree/" ) ), children: (0, import_i18n.__)( "Describe the purpose of the image." ) } ), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {}), (0, import_i18n.__)("Leave empty if decorative.") ] }), __nextHasNoMarginBottom: true } ) }) } ), isTitleDialogOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.Popover, { placement: "bottom-start", anchor: popoverAnchor, onClose: () => setIsTitleDialogOpen(false), offset: 13, variant: "toolbar", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "wp-block-image__toolbar_content_textarea__container", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.TextControl, { __next40pxDefaultSize: true, className: "wp-block-image__toolbar_content_textarea", __nextHasNoMarginBottom: true, label: (0, import_i18n.__)("Title attribute"), value: attributes.title || "", onChange: (value) => setAttributes({ title: value }), disabled: lockTitleControls, help: lockTitleControls ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: lockTitleControlsMessage }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ (0, import_i18n.__)( "Describe the role of this image on the page." ), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.ExternalLink, { href: "https://www.w3.org/TR/html52/dom.html#the-title-attribute", children: (0, import_i18n.__)( "(Note: many devices and browsers do not display this text.)" ) }) ] }) } ) }) } ) ] }); } function Image({ temporaryURL, attributes, setAttributes, isSingleSelected, insertBlocksAfter, onReplace, onSelectImage, onSelectURL, onUploadError, context, clientId, blockEditingMode, parentLayoutType, maxContentWidth }) { const { url = "", alt, align, id, href, rel, linkClass, linkDestination, title, width, height, aspectRatio, scale, linkTarget, sizeSlug, lightbox, metadata } = attributes; const [imageElement, setImageElement] = (0, import_element.useState)(); const [resizeDelta, setResizeDelta] = (0, import_element.useState)(null); const [pixelSize, setPixelSize] = (0, import_element.useState)({}); const [offsetTop, setOffsetTop] = (0, import_element.useState)(0); const setResizeObserved = (0, import_compose.useResizeObserver)(([entry]) => { if (!resizeDelta) { const [box] = entry.borderBoxSize; setPixelSize({ width: box.inlineSize, height: box.blockSize }); } setOffsetTop(entry.target.offsetTop); }); const effectResizeableBoxPlacement = (0, import_element.useCallback)(() => { setOffsetTop(imageElement?.offsetTop ?? 0); }, [imageElement]); const setRefs = (0, import_compose.useMergeRefs)([setImageElement, setResizeObserved]); const { allowResize = true } = context; const image = (0, import_data.useSelect)( (select) => id && isSingleSelected ? select(import_core_data.store).getEntityRecord( "postType", "attachment", id, { context: "view" } ) : null, [id, isSingleSelected] ); const { canInsertCover, imageEditing, imageSizes, maxWidth } = (0, import_data.useSelect)( (select) => { const { getBlockRootClientId, canInsertBlockType, getSettings: getSettings2 } = select(import_block_editor.store); const rootClientId = getBlockRootClientId(clientId); const settings = getSettings2(); return { imageEditing: settings.imageEditing, imageSizes: settings.imageSizes, maxWidth: settings.maxWidth, canInsertCover: canInsertBlockType( "core/cover", rootClientId ) }; }, [clientId] ); const { getBlock, getSettings } = (0, import_data.useSelect)(import_block_editor.store); const { replaceBlocks, toggleSelection } = (0, import_data.useDispatch)(import_block_editor.store); const { createErrorNotice, createSuccessNotice } = (0, import_data.useDispatch)(import_notices.store); const { editEntityRecord } = (0, import_data.useDispatch)(import_core_data.store); const isLargeViewport = (0, import_compose.useViewportMatch)("medium"); const isWideAligned = ["wide", "full"].includes(align); const [ { loadedNaturalWidth, loadedNaturalHeight }, setLoadedNaturalSize ] = (0, import_element.useState)({}); const [isEditingImage, setIsEditingImage] = (0, import_element.useState)(false); const [externalBlob, setExternalBlob] = (0, import_element.useState)(); const [hasImageErrored, setHasImageErrored] = (0, import_element.useState)(false); const hasNonContentControls = blockEditingMode === "default"; const isContentOnlyMode = blockEditingMode === "contentOnly"; const isResizable = allowResize && hasNonContentControls && !isWideAligned && isLargeViewport; const imageSizeOptions = imageSizes.filter( ({ slug }) => image?.media_details?.sizes?.[slug]?.source_url ).map(({ name, slug }) => ({ value: slug, label: name })); (0, import_element.useEffect)(() => { if (!(0, import_edit.isExternalImage)(id, url) || !isSingleSelected || !getSettings().mediaUpload) { setExternalBlob(); return; } if (externalBlob) { return; } window.fetch(url.includes("?") ? url : url + "?").then((response) => response.blob()).then((blob) => setExternalBlob(blob)).catch(() => { }); }, [id, url, isSingleSelected, externalBlob, getSettings]); const { naturalWidth, naturalHeight } = (0, import_element.useMemo)(() => { return { naturalWidth: imageElement?.naturalWidth || loadedNaturalWidth || void 0, naturalHeight: imageElement?.naturalHeight || loadedNaturalHeight || void 0 }; }, [loadedNaturalWidth, loadedNaturalHeight, imageElement?.complete]); function onImageError() { setHasImageErrored(true); const embedBlock = (0, import_util.createUpgradedEmbedBlock)({ attributes: { url } }); if (void 0 !== embedBlock) { onReplace(embedBlock); } } function onImageLoad(event) { setHasImageErrored(false); setLoadedNaturalSize({ loadedNaturalWidth: event.target?.naturalWidth, loadedNaturalHeight: event.target?.naturalHeight }); } function onSetHref(props) { setAttributes(props); } function onSetLightbox(enable) { if (enable && !lightboxSetting?.enabled) { setAttributes({ lightbox: { enabled: true } }); } else if (!enable && lightboxSetting?.enabled) { setAttributes({ lightbox: { enabled: false } }); } else { setAttributes({ lightbox: void 0 }); } } function resetLightbox() { if (lightboxSetting?.enabled && lightboxSetting?.allowEditing) { setAttributes({ lightbox: { enabled: false } }); } else { setAttributes({ lightbox: void 0 }); } } function onSetTitle(value) { setAttributes({ title: value }); } function updateAlt(newAlt) { setAttributes({ alt: newAlt }); } function updateImage(newSizeSlug) { const newUrl = image?.media_details?.sizes?.[newSizeSlug]?.source_url; if (!newUrl) { return null; } setAttributes({ url: newUrl, sizeSlug: newSizeSlug }); } function uploadExternal() { const { mediaUpload } = getSettings(); if (!mediaUpload) { return; } mediaUpload({ filesList: [externalBlob], onFileChange([img2]) { onSelectImage(img2); if ((0, import_blob.isBlobURL)(img2.url)) { return; } setExternalBlob(); createSuccessNotice((0, import_i18n.__)("Image uploaded."), { type: "snackbar" }); }, allowedTypes: import_constants.ALLOWED_MEDIA_TYPES, onError(message) { createErrorNotice(message, { type: "snackbar" }); } }); } (0, import_element.useEffect)(() => { if (!isSingleSelected) { setIsEditingImage(false); } }, [isSingleSelected]); const canEditImage = id && naturalWidth && naturalHeight && imageEditing; const allowCrop = isSingleSelected && canEditImage && !isEditingImage && !isContentOnlyMode; function switchToCover() { replaceBlocks( clientId, (0, import_blocks.switchToBlockType)(getBlock(clientId), "core/cover") ); } const dimensionsUnitsOptions = (0, import_components.__experimentalUseCustomUnits)({ availableUnits: ["px"] }); const [lightboxSetting] = (0, import_block_editor.useSettings)("lightbox"); const showLightboxSetting = ( // If a block-level override is set, we should give users the option to // remove that override, even if the lightbox UI is disabled in the settings. !!lightbox && lightbox?.enabled !== lightboxSetting?.enabled || lightboxSetting?.allowEditing ); const lightboxChecked = !!lightbox?.enabled || !lightbox && !!lightboxSetting?.enabled; const dropdownMenuProps = (0, import_hooks.useToolsPanelDropdownMenuProps)(); const dimensionsControl = isResizable && (import_constants.SIZED_LAYOUTS.includes(parentLayoutType) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)( DimensionsTool, { value: { aspectRatio }, onChange: ({ aspectRatio: newAspectRatio }) => { setAttributes({ aspectRatio: newAspectRatio, scale: "cover" }); }, defaultAspectRatio: "auto", tools: ["aspectRatio"] } ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)( DimensionsTool, { value: { width, height, scale, aspectRatio }, onChange: ({ width: newWidth, height: newHeight, scale: newScale, aspectRatio: newAspectRatio }) => { setAttributes({ // CSS includes `height: auto`, but we need // `width: auto` to fix the aspect ratio when // only height is set due to the width and // height attributes set via the server. width: !newWidth && newHeight ? "auto" : newWidth, height: newHeight, scale: newScale, aspectRatio: newAspectRatio }); }, defaultScale: "cover", defaultAspectRatio: "auto", scaleOptions, unitsOptions: dimensionsUnitsOptions } )); const resetAll = () => { setAttributes({ alt: void 0, width: void 0, height: void 0, scale: void 0, aspectRatio: void 0, lightbox: void 0 }); updateImage(import_constants.DEFAULT_MEDIA_SIZE_SLUG); }; const sizeControls = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_block_editor.InspectorControls, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.__experimentalToolsPanel, { label: (0, import_i18n.__)("Settings"), resetAll, dropdownMenuProps, children: dimensionsControl } ) }); const arePatternOverridesEnabled = metadata?.bindings?.__default?.source === "core/pattern-overrides"; const { lockUrlControls = false, lockHrefControls = false, lockAltControls = false, lockAltControlsMessage, lockTitleControls = false, lockTitleControlsMessage, hideCaptionControls = false } = (0, import_data.useSelect)( (select) => { if (!isSingleSelected) { return {}; } const { url: urlBinding, alt: altBinding, title: titleBinding, caption: captionBinding } = metadata?.bindings || {}; const hasParentPattern = !!context["pattern/overrides"]; const urlBindingSource = (0, import_blocks.getBlockBindingsSource)( urlBinding?.source ); const altBindingSource = (0, import_blocks.getBlockBindingsSource)( altBinding?.source ); const titleBindingSource = (0, import_blocks.getBlockBindingsSource)( titleBinding?.source ); return { lockUrlControls: !!urlBinding && !urlBindingSource?.canUserEditValue?.({ select, context, args: urlBinding?.args }), lockHrefControls: ( // Disable editing the link of the URL if the image is inside a pattern instance. // This is a temporary solution until we support overriding the link on the frontend. hasParentPattern || arePatternOverridesEnabled ), hideCaptionControls: !!captionBinding, lockAltControls: !!altBinding && !altBindingSource?.canUserEditValue?.({ select, context, args: altBinding?.args }), lockAltControlsMessage: altBindingSource?.label ? (0, import_i18n.sprintf)( /* translators: %s: Label of the bindings source. */ (0, import_i18n.__)("Connected to %s"), altBindingSource.label ) : (0, import_i18n.__)("Connected to dynamic data"), lockTitleControls: !!titleBinding && !titleBindingSource?.canUserEditValue?.({ select, context, args: titleBinding?.args }), lockTitleControlsMessage: titleBindingSource?.label ? (0, import_i18n.sprintf)( /* translators: %s: Label of the bindings source. */ (0, import_i18n.__)("Connected to %s"), titleBindingSource.label ) : (0, import_i18n.__)("Connected to dynamic data") }; }, [ arePatternOverridesEnabled, context, isSingleSelected, metadata?.bindings ] ); const showUrlInput = isSingleSelected && !isEditingImage && !lockHrefControls && !lockUrlControls; const showCoverControls = isSingleSelected && canInsertCover && !isContentOnlyMode; const showBlockControls = showUrlInput || allowCrop || showCoverControls; const mediaReplaceFlow = isSingleSelected && !isEditingImage && !lockUrlControls && // For contentOnly mode, put this button in its own area so it has borders around it. /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_block_editor.BlockControls, { group: isContentOnlyMode ? "inline" : "other", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_block_editor.MediaReplaceFlow, { mediaId: id, mediaURL: url, allowedTypes: import_constants.ALLOWED_MEDIA_TYPES, onSelect: onSelectImage, onSelectURL, onError: onUploadError, name: !url ? (0, import_i18n.__)("Add image") : (0, import_i18n.__)("Replace"), onReset: () => onSelectImage(void 0) } ) }); const controls = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ showBlockControls && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_block_editor.BlockControls, { group: "block", children: [ showUrlInput && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_block_editor.__experimentalImageURLInputUI, { url: href || "", onChangeUrl: onSetHref, linkDestination, mediaUrl: image && image.source_url || url, mediaLink: image && image.link, linkTarget, linkClass, rel, showLightboxSetting, lightboxEnabled: lightboxChecked, onSetLightbox, resetLightbox } ), allowCrop && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.ToolbarButton, { onClick: () => setIsEditingImage(true), icon: import_icons.crop, label: (0, import_i18n.__)("Crop") } ), showCoverControls && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.ToolbarButton, { icon: import_icons.overlayText, label: (0, import_i18n.__)("Add text over image"), onClick: switchToCover } ) ] }), isSingleSelected && externalBlob && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_block_editor.BlockControls, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.ToolbarGroup, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.ToolbarButton, { onClick: uploadExternal, icon: import_icons.upload, label: (0, import_i18n.__)("Upload to Media Library") } ) }) }), isContentOnlyMode && // Add some extra controls for content attributes when content only mode is active. // With content only mode active, the inspector is hidden, so users need another way // to edit these attributes. /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_block_editor.BlockControls, { group: "block", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( ContentOnlyControls, { attributes, setAttributes, lockAltControls, lockAltControlsMessage, lockTitleControls, lockTitleControlsMessage } ) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_block_editor.InspectorControls, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)( import_components.__experimentalToolsPanel, { label: (0, import_i18n.__)("Settings"), resetAll, dropdownMenuProps, children: [ isSingleSelected && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.__experimentalToolsPanelItem, { label: (0, import_i18n.__)("Alternative text"), isShownByDefault: true, hasValue: () => !!alt, onDeselect: () => setAttributes({ alt: void 0 }), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.TextareaControl, { label: (0, import_i18n.__)("Alternative text"), value: alt || "", onChange: updateAlt, readOnly: lockAltControls, help: lockAltControls ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: lockAltControlsMessage }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.ExternalLink, { href: ( // translators: Localized tutorial, if one exists. W3C Web Accessibility Initiative link has list of existing translations. (0, import_i18n.__)( "https://www.w3.org/WAI/tutorials/images/decision-tree/" ) ), children: (0, import_i18n.__)( "Describe the purpose of the image." ) } ), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {}), (0, import_i18n.__)( "Leave empty if decorative." ) ] }), __nextHasNoMarginBottom: true } ) } ), dimensionsControl, !!imageSizeOptions.length && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( ResolutionTool, { value: sizeSlug, defaultValue: import_constants.DEFAULT_MEDIA_SIZE_SLUG, onChange: updateImage, options: imageSizeOptions } ) ] } ) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_block_editor.InspectorControls, { group: "advanced", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.TextControl, { __nextHasNoMarginBottom: true, __next40pxDefaultSize: true, label: (0, import_i18n.__)("Title attribute"), value: title || "", onChange: onSetTitle, readOnly: lockTitleControls, help: lockTitleControls ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: lockTitleControlsMessage }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ (0, import_i18n.__)( "Describe the role of this image on the page." ), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.ExternalLink, { href: "https://www.w3.org/TR/html52/dom.html#the-title-attribute", children: (0, import_i18n.__)( "(Note: many devices and browsers do not display this text.)" ) }) ] }) } ) }) ] }); const filename = (0, import_url.getFilename)(url); let defaultedAlt; if (alt) { defaultedAlt = alt; } else if (filename) { defaultedAlt = (0, import_i18n.sprintf)( /* translators: %s: file name */ (0, import_i18n.__)("This image has an empty alt attribute; its file name is %s"), filename ); } else { defaultedAlt = (0, import_i18n.__)("This image has an empty alt attribute"); } const borderProps = (0, import_block_editor.__experimentalUseBorderProps)(attributes); const shadowProps = (0, import_block_editor.__experimentalGetShadowClassesAndStyles)(attributes); const isRounded = attributes.className?.includes("is-style-rounded"); const { postType, postId, queryId } = context; const isDescendentOfQueryLoop = Number.isFinite(queryId); let img = temporaryURL && hasImageErrored ? ( // Show a placeholder during upload when the blob URL can't be loaded. This can // happen when the user uploads a HEIC image in a browser that doesn't support them. /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.Placeholder, { className: "wp-block-image__placeholder", withIllustration: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Spinner, {}) } ) ) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ /* @__PURE__ */ (0, import_jsx_runtime.jsx)( "img", { src: temporaryURL || url, alt: defaultedAlt, onError: onImageError, onLoad: onImageLoad, ref: setRefs, className: borderProps.className, width: naturalWidth, height: naturalHeight, style: { aspectRatio, ...resizeDelta ? { width: pixelSize.width + resizeDelta.width, height: pixelSize.height + resizeDelta.height } : { width, height }, objectFit: scale, ...borderProps.style, ...shadowProps.style } } ), temporaryURL && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Spinner, {}) ] }); if (canEditImage && isEditingImage) { img = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ImageWrapper, { href, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_block_editor.__experimentalImageEditor, { id, url, ...pixelSize, naturalHeight, naturalWidth, onSaveImage: (imageAttributes) => setAttributes(imageAttributes), onFinishEditing: () => { setIsEditingImage(false); }, borderProps: isRounded ? void 0 : borderProps } ) }); } else { img = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ImageWrapper, { href, children: img }); } let resizableBox; if (isResizable && isSingleSelected && !isEditingImage && !import_constants.SIZED_LAYOUTS.includes(parentLayoutType)) { const numericRatio = aspectRatio && (0, import_utils.evalAspectRatio)(aspectRatio); const customRatio = pixelSize.width / pixelSize.height; const naturalRatio = naturalWidth / naturalHeight; const ratio = numericRatio || customRatio || naturalRatio || 1; const minWidth = naturalWidth < naturalHeight ? import_constants.MIN_SIZE : import_constants.MIN_SIZE * ratio; const minHeight = naturalHeight < naturalWidth ? import_constants.MIN_SIZE : import_constants.MIN_SIZE / ratio; const maxWidthBuffer = maxWidth * 2.5; const maxResizeWidth = maxContentWidth || maxWidthBuffer; let showRightHandle = false; let showLeftHandle = false; if (align === "center") { showRightHandle = true; showLeftHandle = true; } else if ((0, import_i18n.isRTL)()) { if (align === "left") { showRightHandle = true; } else { showLeftHandle = true; } } else { if (align === "right") { showLeftHandle = true; } else { showRightHandle = true; } } resizableBox = /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_components.ResizableBox, { ref: effectResizeableBoxPlacement, style: { position: "absolute", // To match the vertical-align: bottom of the img (from style.scss) // syncs the top with the img. This matters when the img height is // less than the line-height. inset: `${offsetTop}px 0 0 0` }, size: pixelSize, minWidth, maxWidth: maxResizeWidth, minHeight, maxHeight: maxResizeWidth / ratio, lockAspectRatio: ratio, enable: { top: false, right: showRightHandle, bottom: true, left: showLeftHandle }, onResizeStart: () => { toggleSelection(false); }, onResize: (event, direction, elt, delta) => { setResizeDelta(delta); }, onResizeStop: (event, direction, elt, delta) => { toggleSelection(true); setResizeDelta(null); setPixelSize((current) => ({ width: current.width + delta.width, height: current.height + delta.height })); if (maxContentWidth && // Only do this if the image is bigger than the container to prevent it from being squished. // TODO: Remove this check if the image support setting 100% width. naturalWidth >= maxContentWidth && Math.abs(elt.offsetWidth - maxContentWidth) < 10) { setAttributes({ width: void 0, height: void 0 }); return; } setAttributes({ width: `${elt.offsetWidth}px`, height: "auto", aspectRatio: ratio === naturalRatio ? void 0 : String(ratio) }); }, resizeRatio: align === "center" ? 2 : 1 } ); } if (!url && !temporaryURL) { return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ mediaReplaceFlow, metadata?.bindings ? controls : sizeControls ] }); } const setPostFeatureImage = () => { editEntityRecord("postType", postType, postId, { featured_media: id }); createSuccessNotice((0, import_i18n.__)("Post featured image updated."), { type: "snackbar" }); }; const featuredImageControl = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_block_editor.BlockSettingsMenuControls, { children: ({ selectedClientIds }) => selectedClientIds.length === 1 && !isDescendentOfQueryLoop && postId && id && clientId === selectedClientIds[0] && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.MenuItem, { onClick: setPostFeatureImage, children: (0, import_i18n.__)("Set as featured image") }) }); return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ mediaReplaceFlow, controls, featuredImageControl, img, resizableBox, /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_caption.Caption, { attributes, setAttributes, isSelected: isSingleSelected, insertBlocksAfter, label: (0, import_i18n.__)("Image caption text"), showToolbarButton: isSingleSelected && (hasNonContentControls || isContentOnlyMode) && !hideCaptionControls } ) ] }); } //# sourceMappingURL=image.js.map