"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = Image;
var _blob = require("@wordpress/blob");
var _components = require("@wordpress/components");
var _compose = require("@wordpress/compose");
var _data = require("@wordpress/data");
var _blockEditor = require("@wordpress/block-editor");
var _element = require("@wordpress/element");
var _i18n = require("@wordpress/i18n");
var _keycodes = require("@wordpress/keycodes");
var _url = require("@wordpress/url");
var _blocks = require("@wordpress/blocks");
var _icons = require("@wordpress/icons");
var _notices = require("@wordpress/notices");
var _coreData = require("@wordpress/core-data");
var _lockUnlock = require("../lock-unlock");
var _util = require("../embed/util");
var _edit = require("./edit");
var _caption = require("../utils/caption");
var _hooks = require("../utils/hooks");
var _constants = require("./constants");
var _utils = require("./utils");
var _jsxRuntime = require("react/jsx-runtime");
/**
 * WordPress dependencies
 */

/**
 * Internal dependencies
 */

/**
 * Module constants
 */

const {
  DimensionsTool,
  ResolutionTool
} = (0, _lockUnlock.unlock)(_blockEditor.privateApis);
const scaleOptions = [{
  value: 'cover',
  label: (0, _i18n._x)('Cover', 'Scale option for dimensions control'),
  help: (0, _i18n.__)('Image covers the space evenly.')
}, {
  value: 'contain',
  label: (0, _i18n._x)('Contain', 'Scale option for dimensions control'),
  help: (0, _i18n.__)('Image is contained without distortion.')
}];

// If the image has a href, wrap in an <a /> tag to trigger any inherited link element styles.
const ImageWrapper = ({
  href,
  children
}) => {
  if (!href) {
    return children;
  }
  return /*#__PURE__*/(0, _jsxRuntime.jsx)("a", {
    href: 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: children
  });
};
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;

  // The only supported unit is px, so we can parseInt to strip the px here.
  const numericWidth = width ? parseInt(width, 10) : undefined;
  const numericHeight = height ? parseInt(height, 10) : undefined;
  const imageRef = (0, _element.useRef)();
  const {
    allowResize = true
  } = context;
  const {
    getBlock,
    getSettings
  } = (0, _data.useSelect)(_blockEditor.store);
  const image = (0, _data.useSelect)(select => id && isSingleSelected ? select(_coreData.store).getMedia(id, {
    context: 'view'
  }) : null, [id, isSingleSelected]);
  const {
    canInsertCover,
    imageEditing,
    imageSizes,
    maxWidth
  } = (0, _data.useSelect)(select => {
    const {
      getBlockRootClientId,
      canInsertBlockType
    } = select(_blockEditor.store);
    const rootClientId = getBlockRootClientId(clientId);
    const settings = getSettings();
    return {
      imageEditing: settings.imageEditing,
      imageSizes: settings.imageSizes,
      maxWidth: settings.maxWidth,
      canInsertCover: canInsertBlockType('core/cover', rootClientId)
    };
  }, [clientId]);
  const {
    replaceBlocks,
    toggleSelection
  } = (0, _data.useDispatch)(_blockEditor.store);
  const {
    createErrorNotice,
    createSuccessNotice
  } = (0, _data.useDispatch)(_notices.store);
  const isLargeViewport = (0, _compose.useViewportMatch)('medium');
  const isWideAligned = ['wide', 'full'].includes(align);
  const [{
    loadedNaturalWidth,
    loadedNaturalHeight
  }, setLoadedNaturalSize] = (0, _element.useState)({});
  const [isEditingImage, setIsEditingImage] = (0, _element.useState)(false);
  const [externalBlob, setExternalBlob] = (0, _element.useState)();
  const [hasImageErrored, setHasImageErrored] = (0, _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
  }));

  // If an image is externally hosted, try to fetch the image data. This may
  // fail if the image host doesn't allow CORS with the domain. If it works,
  // we can enable a button in the toolbar to upload the image.
  (0, _element.useEffect)(() => {
    if (!(0, _edit.isExternalImage)(id, url) || !isSingleSelected || !getSettings().mediaUpload) {
      setExternalBlob();
      return;
    }
    if (externalBlob) {
      return;
    }
    window
    // Avoid cache, which seems to help avoid CORS problems.
    .fetch(url.includes('?') ? url : url + '?').then(response => response.blob()).then(blob => setExternalBlob(blob))
    // Do nothing, cannot upload.
    .catch(() => {});
  }, [id, url, isSingleSelected, externalBlob]);

  // Get naturalWidth and naturalHeight from image ref, and fall back to loaded natural
  // width and height. This resolves an issue in Safari where the loaded natural
  // width and height is otherwise lost when switching between alignments.
  // See: https://github.com/WordPress/gutenberg/pull/37210.
  const {
    naturalWidth,
    naturalHeight
  } = (0, _element.useMemo)(() => {
    return {
      naturalWidth: imageRef.current?.naturalWidth || loadedNaturalWidth || undefined,
      naturalHeight: imageRef.current?.naturalHeight || loadedNaturalHeight || undefined
    };
  }, [loadedNaturalWidth, loadedNaturalHeight, imageRef.current?.complete]);
  function onResizeStart() {
    toggleSelection(false);
  }
  function onResizeStop() {
    toggleSelection(true);
  }
  function onImageError() {
    setHasImageErrored(true);

    // Check if there's an embed block that handles this URL, e.g., instagram URL.
    // See: https://github.com/WordPress/gutenberg/pull/11472
    const embedBlock = (0, _util.createUpgradedEmbedBlock)({
      attributes: {
        url
      }
    });
    if (undefined !== 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: undefined
      });
    }
  }
  function resetLightbox() {
    // When deleting a link from an image while lightbox settings
    // are enabled by default, we should disable the lightbox,
    // otherwise the resulting UX looks like a mistake.
    // See https://github.com/WordPress/gutenberg/pull/59890/files#r1532286123.
    if (lightboxSetting?.enabled && lightboxSetting?.allowEditing) {
      setAttributes({
        lightbox: {
          enabled: false
        }
      });
    } else {
      setAttributes({
        lightbox: undefined
      });
    }
  }
  function onSetTitle(value) {
    // This is the HTML title attribute, separate from the media object
    // title.
    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([img]) {
        onSelectImage(img);
        if ((0, _blob.isBlobURL)(img.url)) {
          return;
        }
        setExternalBlob();
        createSuccessNotice((0, _i18n.__)('Image uploaded.'), {
          type: 'snackbar'
        });
      },
      allowedTypes: _constants.ALLOWED_MEDIA_TYPES,
      onError(message) {
        createErrorNotice(message, {
          type: 'snackbar'
        });
      }
    });
  }
  (0, _element.useEffect)(() => {
    if (!isSingleSelected) {
      setIsEditingImage(false);
    }
  }, [isSingleSelected]);
  const canEditImage = id && naturalWidth && naturalHeight && imageEditing;
  const allowCrop = isSingleSelected && canEditImage && !isEditingImage && !isContentOnlyMode;
  function switchToCover() {
    replaceBlocks(clientId, (0, _blocks.switchToBlockType)(getBlock(clientId), 'core/cover'));
  }

  // TODO: Can allow more units after figuring out how they should interact
  // with the ResizableBox and ImageEditor components. Calculations later on
  // for those components are currently assuming px units.
  const dimensionsUnitsOptions = (0, _components.__experimentalUseCustomUnits)({
    availableUnits: ['px']
  });
  const [lightboxSetting] = (0, _blockEditor.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, _hooks.useToolsPanelDropdownMenuProps)();
  const dimensionsControl = /*#__PURE__*/(0, _jsxRuntime.jsx)(DimensionsTool, {
    value: {
      width,
      height,
      scale,
      aspectRatio
    },
    onChange: ({
      width: newWidth,
      height: newHeight,
      scale: newScale,
      aspectRatio: newAspectRatio
    }) => {
      // Rebuilding the object forces setting `undefined`
      // for values that are removed since setAttributes
      // doesn't do anything with keys that aren't set.
      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: scaleOptions,
    unitsOptions: dimensionsUnitsOptions
  });
  const aspectRatioControl = /*#__PURE__*/(0, _jsxRuntime.jsx)(DimensionsTool, {
    value: {
      aspectRatio
    },
    onChange: ({
      aspectRatio: newAspectRatio
    }) => {
      setAttributes({
        aspectRatio: newAspectRatio,
        scale: 'cover'
      });
    },
    defaultAspectRatio: "auto",
    tools: ['aspectRatio']
  });
  const resetAll = () => {
    setAttributes({
      alt: undefined,
      width: undefined,
      height: undefined,
      scale: undefined,
      aspectRatio: undefined,
      lightbox: undefined
    });
  };
  const sizeControls = /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.InspectorControls, {
    children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanel, {
      label: (0, _i18n.__)('Settings'),
      resetAll: resetAll,
      dropdownMenuProps: dropdownMenuProps,
      children: isResizable && (parentLayoutType === 'grid' ? aspectRatioControl : dimensionsControl)
    })
  });
  const arePatternOverridesEnabled = metadata?.bindings?.__default?.source === 'core/pattern-overrides';
  const {
    lockUrlControls = false,
    lockHrefControls = false,
    lockAltControls = false,
    lockAltControlsMessage,
    lockTitleControls = false,
    lockTitleControlsMessage,
    lockCaption = false
  } = (0, _data.useSelect)(select => {
    if (!isSingleSelected) {
      return {};
    }
    const {
      url: urlBinding,
      alt: altBinding,
      title: titleBinding
    } = metadata?.bindings || {};
    const hasParentPattern = !!context['pattern/overrides'];
    const urlBindingSource = (0, _blocks.getBlockBindingsSource)(urlBinding?.source);
    const altBindingSource = (0, _blocks.getBlockBindingsSource)(altBinding?.source);
    const titleBindingSource = (0, _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,
      lockCaption:
      // Disable editing the caption if the image is inside a pattern instance.
      // This is a temporary solution until we support overriding the caption on the frontend.
      hasParentPattern,
      lockAltControls: !!altBinding && !altBindingSource?.canUserEditValue?.({
        select,
        context,
        args: altBinding?.args
      }),
      lockAltControlsMessage: altBindingSource?.label ? (0, _i18n.sprintf)( /* translators: %s: Label of the bindings source. */
      (0, _i18n.__)('Connected to %s'), altBindingSource.label) : (0, _i18n.__)('Connected to dynamic data'),
      lockTitleControls: !!titleBinding && !titleBindingSource?.canUserEditValue?.({
        select,
        context,
        args: titleBinding?.args
      }),
      lockTitleControlsMessage: titleBindingSource?.label ? (0, _i18n.sprintf)( /* translators: %s: Label of the bindings source. */
      (0, _i18n.__)('Connected to %s'), titleBindingSource.label) : (0, _i18n.__)('Connected to dynamic data')
    };
  }, [arePatternOverridesEnabled, context, isSingleSelected, metadata?.bindings]);
  const showUrlInput = isSingleSelected && !isEditingImage && !lockHrefControls && !lockUrlControls;
  const showCoverControls = isSingleSelected && canInsertCover;
  const showBlockControls = showUrlInput || allowCrop || showCoverControls;
  const mediaReplaceFlow = isSingleSelected && !isEditingImage && !lockUrlControls &&
  /*#__PURE__*/
  // For contentOnly mode, put this button in its own area so it has borders around it.
  (0, _jsxRuntime.jsx)(_blockEditor.BlockControls, {
    group: isContentOnlyMode ? 'inline' : 'other',
    children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.MediaReplaceFlow, {
      mediaId: id,
      mediaURL: url,
      allowedTypes: _constants.ALLOWED_MEDIA_TYPES,
      accept: "image/*",
      onSelect: onSelectImage,
      onSelectURL: onSelectURL,
      onError: onUploadError,
      name: !url ? (0, _i18n.__)('Add image') : (0, _i18n.__)('Replace'),
      onReset: () => onSelectImage(undefined)
    })
  });
  const controls = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
    children: [showBlockControls && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_blockEditor.BlockControls, {
      group: "block",
      children: [showUrlInput && /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.__experimentalImageURLInputUI, {
        url: href || '',
        onChangeUrl: onSetHref,
        linkDestination: linkDestination,
        mediaUrl: image && image.source_url || url,
        mediaLink: image && image.link,
        linkTarget: linkTarget,
        linkClass: linkClass,
        rel: rel,
        showLightboxSetting: showLightboxSetting,
        lightboxEnabled: lightboxChecked,
        onSetLightbox: onSetLightbox,
        resetLightbox: resetLightbox
      }), allowCrop && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToolbarButton, {
        onClick: () => setIsEditingImage(true),
        icon: _icons.crop,
        label: (0, _i18n.__)('Crop')
      }), showCoverControls && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToolbarButton, {
        icon: _icons.overlayText,
        label: (0, _i18n.__)('Add text over image'),
        onClick: switchToCover
      })]
    }), isSingleSelected && externalBlob && /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.BlockControls, {
      children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToolbarGroup, {
        children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToolbarButton, {
          onClick: uploadExternal,
          icon: _icons.upload,
          label: (0, _i18n.__)('Upload to Media Library')
        })
      })
    }), isContentOnlyMode &&
    /*#__PURE__*/
    // 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.
    (0, _jsxRuntime.jsxs)(_blockEditor.BlockControls, {
      group: "other",
      children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Dropdown, {
        popoverProps: {
          position: 'bottom right'
        },
        renderToggle: ({
          isOpen,
          onToggle
        }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToolbarButton, {
          onClick: onToggle,
          "aria-haspopup": "true",
          "aria-expanded": isOpen,
          onKeyDown: event => {
            if (!isOpen && event.keyCode === _keycodes.DOWN) {
              event.preventDefault();
              onToggle();
            }
          },
          children: (0, _i18n._x)('Alternative text', 'Alternative text for an image. Block toolbar label, a low character count is preferred.')
        }),
        renderContent: () => /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.TextareaControl, {
          className: "wp-block-image__toolbar_content_textarea",
          label: (0, _i18n.__)('Alternative text'),
          value: alt || '',
          onChange: updateAlt,
          disabled: lockAltControls,
          help: lockAltControls ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
            children: lockAltControlsMessage
          }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
            children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ExternalLink, {
              href:
              // translators: Localized tutorial, if one exists. W3C Web Accessibility Initiative link has list of existing translations.
              (0, _i18n.__)('https://www.w3.org/WAI/tutorials/images/decision-tree/'),
              children: (0, _i18n.__)('Describe the purpose of the image.')
            }), /*#__PURE__*/(0, _jsxRuntime.jsx)("br", {}), (0, _i18n.__)('Leave empty if decorative.')]
          }),
          __nextHasNoMarginBottom: true
        })
      }), title && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Dropdown, {
        popoverProps: {
          position: 'bottom right'
        },
        renderToggle: ({
          isOpen,
          onToggle
        }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ToolbarButton, {
          onClick: onToggle,
          "aria-haspopup": "true",
          "aria-expanded": isOpen,
          onKeyDown: event => {
            if (!isOpen && event.keyCode === _keycodes.DOWN) {
              event.preventDefault();
              onToggle();
            }
          },
          children: (0, _i18n.__)('Title')
        }),
        renderContent: () => /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.TextControl, {
          __next40pxDefaultSize: true,
          className: "wp-block-image__toolbar_content_textarea",
          __nextHasNoMarginBottom: true,
          label: (0, _i18n.__)('Title attribute'),
          value: title || '',
          onChange: onSetTitle,
          disabled: lockTitleControls,
          help: lockTitleControls ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
            children: lockTitleControlsMessage
          }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
            children: [(0, _i18n.__)('Describe the role of this image on the page.'), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ExternalLink, {
              href: "https://www.w3.org/TR/html52/dom.html#the-title-attribute",
              children: (0, _i18n.__)('(Note: many devices and browsers do not display this text.)')
            })]
          })
        })
      })]
    }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.InspectorControls, {
      children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalToolsPanel, {
        label: (0, _i18n.__)('Settings'),
        resetAll: resetAll,
        dropdownMenuProps: dropdownMenuProps,
        children: [isSingleSelected && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
          label: (0, _i18n.__)('Alternative text'),
          isShownByDefault: true,
          hasValue: () => !!alt,
          onDeselect: () => setAttributes({
            alt: undefined
          }),
          children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.TextareaControl, {
            label: (0, _i18n.__)('Alternative text'),
            value: alt || '',
            onChange: updateAlt,
            readOnly: lockAltControls,
            help: lockAltControls ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
              children: lockAltControlsMessage
            }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
              children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ExternalLink, {
                href:
                // translators: Localized tutorial, if one exists. W3C Web Accessibility Initiative link has list of existing translations.
                (0, _i18n.__)('https://www.w3.org/WAI/tutorials/images/decision-tree/'),
                children: (0, _i18n.__)('Describe the purpose of the image.')
              }), /*#__PURE__*/(0, _jsxRuntime.jsx)("br", {}), (0, _i18n.__)('Leave empty if decorative.')]
            }),
            __nextHasNoMarginBottom: true
          })
        }), isResizable && (parentLayoutType === 'grid' ? aspectRatioControl : dimensionsControl), !!imageSizeOptions.length && /*#__PURE__*/(0, _jsxRuntime.jsx)(ResolutionTool, {
          value: sizeSlug,
          onChange: updateImage,
          options: imageSizeOptions
        })]
      })
    }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.InspectorControls, {
      group: "advanced",
      children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.TextControl, {
        __nextHasNoMarginBottom: true,
        __next40pxDefaultSize: true,
        label: (0, _i18n.__)('Title attribute'),
        value: title || '',
        onChange: onSetTitle,
        readOnly: lockTitleControls,
        help: lockTitleControls ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
          children: lockTitleControlsMessage
        }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
          children: [(0, _i18n.__)('Describe the role of this image on the page.'), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ExternalLink, {
            href: "https://www.w3.org/TR/html52/dom.html#the-title-attribute",
            children: (0, _i18n.__)('(Note: many devices and browsers do not display this text.)')
          })]
        })
      })
    })]
  });
  const filename = (0, _url.getFilename)(url);
  let defaultedAlt;
  if (alt) {
    defaultedAlt = alt;
  } else if (filename) {
    defaultedAlt = (0, _i18n.sprintf)( /* translators: %s: file name */
    (0, _i18n.__)('This image has an empty alt attribute; its file name is %s'), filename);
  } else {
    defaultedAlt = (0, _i18n.__)('This image has an empty alt attribute');
  }
  const borderProps = (0, _blockEditor.__experimentalUseBorderProps)(attributes);
  const shadowProps = (0, _blockEditor.__experimentalGetShadowClassesAndStyles)(attributes);
  const isRounded = attributes.className?.includes('is-style-rounded');
  let img = temporaryURL && hasImageErrored ?
  /*#__PURE__*/
  // 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.
  (0, _jsxRuntime.jsx)(_components.Placeholder, {
    className: "wp-block-image__placeholder",
    withIllustration: true,
    children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Spinner, {})
  }) :
  /*#__PURE__*/
  // Disable reason: Image itself is not meant to be interactive, but
  // should direct focus to block.
  /* eslint-disable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events */
  (0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
    children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("img", {
      src: temporaryURL || url,
      alt: defaultedAlt,
      onError: onImageError,
      onLoad: onImageLoad,
      ref: imageRef,
      className: borderProps.className,
      style: {
        width: width && height || aspectRatio ? '100%' : undefined,
        height: width && height || aspectRatio ? '100%' : undefined,
        objectFit: scale,
        ...borderProps.style,
        ...shadowProps.style
      }
    }), temporaryURL && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Spinner, {})]
  })
  /* eslint-enable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events */;
  if (canEditImage && isEditingImage) {
    img = /*#__PURE__*/(0, _jsxRuntime.jsx)(ImageWrapper, {
      href: href,
      children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_blockEditor.__experimentalImageEditor, {
        id: id,
        url: url,
        width: numericWidth,
        height: numericHeight,
        naturalHeight: naturalHeight,
        naturalWidth: naturalWidth,
        onSaveImage: imageAttributes => setAttributes(imageAttributes),
        onFinishEditing: () => {
          setIsEditingImage(false);
        },
        borderProps: isRounded ? undefined : borderProps
      })
    });
  } else if (!isResizable || parentLayoutType === 'grid') {
    img = /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
      style: {
        width,
        height,
        aspectRatio
      },
      children: /*#__PURE__*/(0, _jsxRuntime.jsx)(ImageWrapper, {
        href: href,
        children: img
      })
    });
  } else {
    const numericRatio = aspectRatio && (0, _utils.evalAspectRatio)(aspectRatio);
    const customRatio = numericWidth / numericHeight;
    const naturalRatio = naturalWidth / naturalHeight;
    const ratio = numericRatio || customRatio || naturalRatio || 1;
    const currentWidth = !numericWidth && numericHeight ? numericHeight * ratio : numericWidth;
    const currentHeight = !numericHeight && numericWidth ? numericWidth / ratio : numericHeight;
    const minWidth = naturalWidth < naturalHeight ? _constants.MIN_SIZE : _constants.MIN_SIZE * ratio;
    const minHeight = naturalHeight < naturalWidth ? _constants.MIN_SIZE : _constants.MIN_SIZE / ratio;

    // With the current implementation of ResizableBox, an image needs an
    // explicit pixel value for the max-width. In absence of being able to
    // set the content-width, this max-width is currently dictated by the
    // vanilla editor style. The following variable adds a buffer to this
    // vanilla style, so 3rd party themes have some wiggleroom. This does,
    // in most cases, allow you to scale the image beyond the width of the
    // main column, though not infinitely.
    // @todo It would be good to revisit this once a content-width variable
    // becomes available.
    const maxWidthBuffer = maxWidth * 2.5;
    const maxResizeWidth = maxContentWidth || maxWidthBuffer;
    let showRightHandle = false;
    let showLeftHandle = false;

    /* eslint-disable no-lonely-if */
    // See https://github.com/WordPress/gutenberg/issues/7584.
    if (align === 'center') {
      // When the image is centered, show both handles.
      showRightHandle = true;
      showLeftHandle = true;
    } else if ((0, _i18n.isRTL)()) {
      // In RTL mode the image is on the right by default.
      // Show the right handle and hide the left handle only when it is
      // aligned left. Otherwise always show the left handle.
      if (align === 'left') {
        showRightHandle = true;
      } else {
        showLeftHandle = true;
      }
    } else {
      // Show the left handle and hide the right handle only when the
      // image is aligned right. Otherwise always show the right handle.
      if (align === 'right') {
        showLeftHandle = true;
      } else {
        showRightHandle = true;
      }
    }
    /* eslint-enable no-lonely-if */
    img = /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.ResizableBox, {
      style: {
        display: 'block',
        objectFit: scale,
        aspectRatio: !width && !height && aspectRatio ? aspectRatio : undefined
      },
      size: {
        width: currentWidth !== null && currentWidth !== void 0 ? currentWidth : 'auto',
        height: currentHeight !== null && currentHeight !== void 0 ? currentHeight : 'auto'
      },
      showHandle: isSingleSelected,
      minWidth: minWidth,
      maxWidth: maxResizeWidth,
      minHeight: minHeight,
      maxHeight: maxResizeWidth / ratio,
      lockAspectRatio: ratio,
      enable: {
        top: false,
        right: showRightHandle,
        bottom: true,
        left: showLeftHandle
      },
      onResizeStart: onResizeStart,
      onResizeStop: (event, direction, elt) => {
        onResizeStop();

        // Clear hardcoded width if the resized width is close to the max-content width.
        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: undefined,
            height: undefined
          });
          return;
        }

        // Since the aspect ratio is locked when resizing, we can
        // use the width of the resized element to calculate the
        // height in CSS to prevent stretching when the max-width
        // is reached.
        setAttributes({
          width: `${elt.offsetWidth}px`,
          height: 'auto',
          aspectRatio: ratio === naturalRatio ? undefined : String(ratio)
        });
      },
      resizeRatio: align === 'center' ? 2 : 1,
      children: /*#__PURE__*/(0, _jsxRuntime.jsx)(ImageWrapper, {
        href: href,
        children: img
      })
    });
  }
  if (!url && !temporaryURL) {
    return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
      children: [mediaReplaceFlow, metadata?.bindings ? controls : sizeControls]
    });
  }
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
    children: [mediaReplaceFlow, controls, img, /*#__PURE__*/(0, _jsxRuntime.jsx)(_caption.Caption, {
      attributes: attributes,
      setAttributes: setAttributes,
      isSelected: isSingleSelected,
      insertBlocksAfter: insertBlocksAfter,
      label: (0, _i18n.__)('Image caption text'),
      showToolbarButton: isSingleSelected && hasNonContentControls && !arePatternOverridesEnabled,
      readOnly: lockCaption
    })]
  });
}
//# sourceMappingURL=image.js.map