UNPKG

@wordpress/block-library

Version:
921 lines (920 loc) 30.6 kB
// packages/block-library/src/image/image.js import { isBlobURL } from "@wordpress/blob"; import { ExternalLink, ResizableBox, Spinner, TextareaControl, TextControl, ToolbarButton, ToolbarGroup, __experimentalToolsPanel as ToolsPanel, __experimentalToolsPanelItem as ToolsPanelItem, __experimentalUseCustomUnits as useCustomUnits, Placeholder, MenuItem, ToolbarItem, DropdownMenu, Popover } from "@wordpress/components"; import { useMergeRefs, useResizeObserver, useViewportMatch } from "@wordpress/compose"; import { useSelect, useDispatch } from "@wordpress/data"; import { BlockControls, InspectorControls, __experimentalImageURLInputUI as ImageURLInputUI, MediaReplaceFlow, store as blockEditorStore, useSettings, __experimentalImageEditor as ImageEditor, __experimentalUseBorderProps as useBorderProps, __experimentalGetShadowClassesAndStyles as getShadowClassesAndStyles, privateApis as blockEditorPrivateApis, BlockSettingsMenuControls } from "@wordpress/block-editor"; import { useCallback, useEffect, useMemo, useState } from "@wordpress/element"; import { __, _x, sprintf, isRTL } from "@wordpress/i18n"; import { getFilename } from "@wordpress/url"; import { getBlockBindingsSource, switchToBlockType } from "@wordpress/blocks"; import { crop, overlayText, upload, chevronDown } from "@wordpress/icons"; import { store as noticesStore } from "@wordpress/notices"; import { store as coreStore } from "@wordpress/core-data"; import { unlock } from "../lock-unlock"; import { createUpgradedEmbedBlock } from "../embed/util"; import { isExternalImage } from "./edit"; import { Caption } from "../utils/caption"; import { useToolsPanelDropdownMenuProps } from "../utils/hooks"; import { MIN_SIZE, ALLOWED_MEDIA_TYPES, SIZED_LAYOUTS, DEFAULT_MEDIA_SIZE_SLUG } from "./constants"; import { evalAspectRatio } from "./utils"; import { Fragment, jsx, jsxs } from "react/jsx-runtime"; var { DimensionsTool, ResolutionTool } = unlock(blockEditorPrivateApis); var scaleOptions = [ { value: "cover", label: _x("Cover", "Scale option for dimensions control"), help: __("Image covers the space evenly.") }, { value: "contain", label: _x("Contain", "Scale option for dimensions control"), help: __("Image is contained without distortion.") } ]; var WRITEMODE_POPOVER_PROPS = { placement: "bottom-start" }; var ImageWrapper = ({ href, children }) => { if (!href) { return children; } return /* @__PURE__ */ 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] = useState(null); const [isAltDialogOpen, setIsAltDialogOpen] = useState(false); const [isTitleDialogOpen, setIsTitleDialogOpen] = useState(false); return /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx(ToolbarItem, { ref: setPopoverAnchor, children: (toggleProps) => /* @__PURE__ */ jsx( DropdownMenu, { icon: chevronDown, label: __("More"), toggleProps: { ...toggleProps, description: __("Displays more controls.") }, popoverProps: WRITEMODE_POPOVER_PROPS, children: ({ onClose }) => /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx( MenuItem, { onClick: () => { setIsAltDialogOpen(true); onClose(); }, "aria-haspopup": "dialog", children: _x( "Alternative text", "Alternative text for an image. Block toolbar label, a low character count is preferred." ) } ), /* @__PURE__ */ jsx( MenuItem, { onClick: () => { setIsTitleDialogOpen(true); onClose(); }, "aria-haspopup": "dialog", children: __("Title text") } ) ] }) } ) }), isAltDialogOpen && /* @__PURE__ */ jsx( Popover, { placement: "bottom-start", anchor: popoverAnchor, onClose: () => setIsAltDialogOpen(false), offset: 13, variant: "toolbar", children: /* @__PURE__ */ jsx("div", { className: "wp-block-image__toolbar_content_textarea__container", children: /* @__PURE__ */ jsx( TextareaControl, { className: "wp-block-image__toolbar_content_textarea", label: __("Alternative text"), value: attributes.alt || "", onChange: (value) => setAttributes({ alt: value }), disabled: lockAltControls, help: lockAltControls ? /* @__PURE__ */ jsx(Fragment, { children: lockAltControlsMessage }) : /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx( ExternalLink, { href: ( // translators: Localized tutorial, if one exists. W3C Web Accessibility Initiative link has list of existing translations. __( "https://www.w3.org/WAI/tutorials/images/decision-tree/" ) ), children: __( "Describe the purpose of the image." ) } ), /* @__PURE__ */ jsx("br", {}), __("Leave empty if decorative.") ] }), __nextHasNoMarginBottom: true } ) }) } ), isTitleDialogOpen && /* @__PURE__ */ jsx( Popover, { placement: "bottom-start", anchor: popoverAnchor, onClose: () => setIsTitleDialogOpen(false), offset: 13, variant: "toolbar", children: /* @__PURE__ */ jsx("div", { className: "wp-block-image__toolbar_content_textarea__container", children: /* @__PURE__ */ jsx( TextControl, { __next40pxDefaultSize: true, className: "wp-block-image__toolbar_content_textarea", __nextHasNoMarginBottom: true, label: __("Title attribute"), value: attributes.title || "", onChange: (value) => setAttributes({ title: value }), disabled: lockTitleControls, help: lockTitleControls ? /* @__PURE__ */ jsx(Fragment, { children: lockTitleControlsMessage }) : /* @__PURE__ */ jsxs(Fragment, { children: [ __( "Describe the role of this image on the page." ), /* @__PURE__ */ jsx(ExternalLink, { href: "https://www.w3.org/TR/html52/dom.html#the-title-attribute", children: __( "(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] = useState(); const [resizeDelta, setResizeDelta] = useState(null); const [pixelSize, setPixelSize] = useState({}); const [offsetTop, setOffsetTop] = useState(0); const setResizeObserved = useResizeObserver(([entry]) => { if (!resizeDelta) { const [box] = entry.borderBoxSize; setPixelSize({ width: box.inlineSize, height: box.blockSize }); } setOffsetTop(entry.target.offsetTop); }); const effectResizeableBoxPlacement = useCallback(() => { setOffsetTop(imageElement?.offsetTop ?? 0); }, [imageElement]); const setRefs = useMergeRefs([setImageElement, setResizeObserved]); const { allowResize = true } = context; const image = useSelect( (select) => id && isSingleSelected ? select(coreStore).getEntityRecord( "postType", "attachment", id, { context: "view" } ) : null, [id, isSingleSelected] ); const { canInsertCover, imageEditing, imageSizes, maxWidth } = useSelect( (select) => { const { getBlockRootClientId, canInsertBlockType, getSettings: getSettings2 } = select(blockEditorStore); 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 } = useSelect(blockEditorStore); const { replaceBlocks, toggleSelection } = useDispatch(blockEditorStore); const { createErrorNotice, createSuccessNotice } = useDispatch(noticesStore); const { editEntityRecord } = useDispatch(coreStore); const isLargeViewport = useViewportMatch("medium"); const isWideAligned = ["wide", "full"].includes(align); const [ { loadedNaturalWidth, loadedNaturalHeight }, setLoadedNaturalSize ] = useState({}); const [isEditingImage, setIsEditingImage] = useState(false); const [externalBlob, setExternalBlob] = useState(); const [hasImageErrored, setHasImageErrored] = 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 })); useEffect(() => { if (!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 } = useMemo(() => { return { naturalWidth: imageElement?.naturalWidth || loadedNaturalWidth || void 0, naturalHeight: imageElement?.naturalHeight || loadedNaturalHeight || void 0 }; }, [loadedNaturalWidth, loadedNaturalHeight, imageElement?.complete]); function onImageError() { setHasImageErrored(true); const embedBlock = 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 (isBlobURL(img2.url)) { return; } setExternalBlob(); createSuccessNotice(__("Image uploaded."), { type: "snackbar" }); }, allowedTypes: ALLOWED_MEDIA_TYPES, onError(message) { createErrorNotice(message, { type: "snackbar" }); } }); } useEffect(() => { if (!isSingleSelected) { setIsEditingImage(false); } }, [isSingleSelected]); const canEditImage = id && naturalWidth && naturalHeight && imageEditing; const allowCrop = isSingleSelected && canEditImage && !isEditingImage && !isContentOnlyMode; function switchToCover() { replaceBlocks( clientId, switchToBlockType(getBlock(clientId), "core/cover") ); } const dimensionsUnitsOptions = useCustomUnits({ availableUnits: ["px"] }); const [lightboxSetting] = 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 = useToolsPanelDropdownMenuProps(); const dimensionsControl = isResizable && (SIZED_LAYOUTS.includes(parentLayoutType) ? /* @__PURE__ */ jsx( DimensionsTool, { value: { aspectRatio }, onChange: ({ aspectRatio: newAspectRatio }) => { setAttributes({ aspectRatio: newAspectRatio, scale: "cover" }); }, defaultAspectRatio: "auto", tools: ["aspectRatio"] } ) : /* @__PURE__ */ 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(DEFAULT_MEDIA_SIZE_SLUG); }; const sizeControls = /* @__PURE__ */ jsx(InspectorControls, { children: /* @__PURE__ */ jsx( ToolsPanel, { label: __("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 } = useSelect( (select) => { if (!isSingleSelected) { return {}; } const { url: urlBinding, alt: altBinding, title: titleBinding, caption: captionBinding } = metadata?.bindings || {}; const hasParentPattern = !!context["pattern/overrides"]; const urlBindingSource = getBlockBindingsSource( urlBinding?.source ); const altBindingSource = getBlockBindingsSource( altBinding?.source ); const titleBindingSource = 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 ? sprintf( /* translators: %s: Label of the bindings source. */ __("Connected to %s"), altBindingSource.label ) : __("Connected to dynamic data"), lockTitleControls: !!titleBinding && !titleBindingSource?.canUserEditValue?.({ select, context, args: titleBinding?.args }), lockTitleControlsMessage: titleBindingSource?.label ? sprintf( /* translators: %s: Label of the bindings source. */ __("Connected to %s"), titleBindingSource.label ) : __("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__ */ jsx(BlockControls, { group: isContentOnlyMode ? "inline" : "other", children: /* @__PURE__ */ jsx( MediaReplaceFlow, { mediaId: id, mediaURL: url, allowedTypes: ALLOWED_MEDIA_TYPES, onSelect: onSelectImage, onSelectURL, onError: onUploadError, name: !url ? __("Add image") : __("Replace"), onReset: () => onSelectImage(void 0) } ) }); const controls = /* @__PURE__ */ jsxs(Fragment, { children: [ showBlockControls && /* @__PURE__ */ jsxs(BlockControls, { group: "block", children: [ showUrlInput && /* @__PURE__ */ jsx( ImageURLInputUI, { 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__ */ jsx( ToolbarButton, { onClick: () => setIsEditingImage(true), icon: crop, label: __("Crop") } ), showCoverControls && /* @__PURE__ */ jsx( ToolbarButton, { icon: overlayText, label: __("Add text over image"), onClick: switchToCover } ) ] }), isSingleSelected && externalBlob && /* @__PURE__ */ jsx(BlockControls, { children: /* @__PURE__ */ jsx(ToolbarGroup, { children: /* @__PURE__ */ jsx( ToolbarButton, { onClick: uploadExternal, icon: upload, label: __("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__ */ jsx(BlockControls, { group: "block", children: /* @__PURE__ */ jsx( ContentOnlyControls, { attributes, setAttributes, lockAltControls, lockAltControlsMessage, lockTitleControls, lockTitleControlsMessage } ) }), /* @__PURE__ */ jsx(InspectorControls, { children: /* @__PURE__ */ jsxs( ToolsPanel, { label: __("Settings"), resetAll, dropdownMenuProps, children: [ isSingleSelected && /* @__PURE__ */ jsx( ToolsPanelItem, { label: __("Alternative text"), isShownByDefault: true, hasValue: () => !!alt, onDeselect: () => setAttributes({ alt: void 0 }), children: /* @__PURE__ */ jsx( TextareaControl, { label: __("Alternative text"), value: alt || "", onChange: updateAlt, readOnly: lockAltControls, help: lockAltControls ? /* @__PURE__ */ jsx(Fragment, { children: lockAltControlsMessage }) : /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx( ExternalLink, { href: ( // translators: Localized tutorial, if one exists. W3C Web Accessibility Initiative link has list of existing translations. __( "https://www.w3.org/WAI/tutorials/images/decision-tree/" ) ), children: __( "Describe the purpose of the image." ) } ), /* @__PURE__ */ jsx("br", {}), __( "Leave empty if decorative." ) ] }), __nextHasNoMarginBottom: true } ) } ), dimensionsControl, !!imageSizeOptions.length && /* @__PURE__ */ jsx( ResolutionTool, { value: sizeSlug, defaultValue: DEFAULT_MEDIA_SIZE_SLUG, onChange: updateImage, options: imageSizeOptions } ) ] } ) }), /* @__PURE__ */ jsx(InspectorControls, { group: "advanced", children: /* @__PURE__ */ jsx( TextControl, { __nextHasNoMarginBottom: true, __next40pxDefaultSize: true, label: __("Title attribute"), value: title || "", onChange: onSetTitle, readOnly: lockTitleControls, help: lockTitleControls ? /* @__PURE__ */ jsx(Fragment, { children: lockTitleControlsMessage }) : /* @__PURE__ */ jsxs(Fragment, { children: [ __( "Describe the role of this image on the page." ), /* @__PURE__ */ jsx(ExternalLink, { href: "https://www.w3.org/TR/html52/dom.html#the-title-attribute", children: __( "(Note: many devices and browsers do not display this text.)" ) }) ] }) } ) }) ] }); const filename = getFilename(url); let defaultedAlt; if (alt) { defaultedAlt = alt; } else if (filename) { defaultedAlt = sprintf( /* translators: %s: file name */ __("This image has an empty alt attribute; its file name is %s"), filename ); } else { defaultedAlt = __("This image has an empty alt attribute"); } const borderProps = useBorderProps(attributes); const shadowProps = getShadowClassesAndStyles(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__ */ jsx( Placeholder, { className: "wp-block-image__placeholder", withIllustration: true, children: /* @__PURE__ */ jsx(Spinner, {}) } ) ) : /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ 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__ */ jsx(Spinner, {}) ] }); if (canEditImage && isEditingImage) { img = /* @__PURE__ */ jsx(ImageWrapper, { href, children: /* @__PURE__ */ jsx( ImageEditor, { id, url, ...pixelSize, naturalHeight, naturalWidth, onSaveImage: (imageAttributes) => setAttributes(imageAttributes), onFinishEditing: () => { setIsEditingImage(false); }, borderProps: isRounded ? void 0 : borderProps } ) }); } else { img = /* @__PURE__ */ jsx(ImageWrapper, { href, children: img }); } let resizableBox; if (isResizable && isSingleSelected && !isEditingImage && !SIZED_LAYOUTS.includes(parentLayoutType)) { const numericRatio = aspectRatio && evalAspectRatio(aspectRatio); const customRatio = pixelSize.width / pixelSize.height; const naturalRatio = naturalWidth / naturalHeight; const ratio = numericRatio || customRatio || naturalRatio || 1; const minWidth = naturalWidth < naturalHeight ? MIN_SIZE : MIN_SIZE * ratio; const minHeight = naturalHeight < naturalWidth ? MIN_SIZE : 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 (isRTL()) { if (align === "left") { showRightHandle = true; } else { showLeftHandle = true; } } else { if (align === "right") { showLeftHandle = true; } else { showRightHandle = true; } } resizableBox = /* @__PURE__ */ jsx( 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__ */ jsxs(Fragment, { children: [ mediaReplaceFlow, metadata?.bindings ? controls : sizeControls ] }); } const setPostFeatureImage = () => { editEntityRecord("postType", postType, postId, { featured_media: id }); createSuccessNotice(__("Post featured image updated."), { type: "snackbar" }); }; const featuredImageControl = /* @__PURE__ */ jsx(BlockSettingsMenuControls, { children: ({ selectedClientIds }) => selectedClientIds.length === 1 && !isDescendentOfQueryLoop && postId && id && clientId === selectedClientIds[0] && /* @__PURE__ */ jsx(MenuItem, { onClick: setPostFeatureImage, children: __("Set as featured image") }) }); return /* @__PURE__ */ jsxs(Fragment, { children: [ mediaReplaceFlow, controls, featuredImageControl, img, resizableBox, /* @__PURE__ */ jsx( Caption, { attributes, setAttributes, isSelected: isSingleSelected, insertBlocksAfter, label: __("Image caption text"), showToolbarButton: isSingleSelected && (hasNonContentControls || isContentOnlyMode) && !hideCaptionControls } ) ] }); } export { Image as default }; //# sourceMappingURL=image.js.map