// packages/block-library/src/cover/edit/index.js
import clsx from "clsx";
import { useEntityProp, store as coreStore } from "@wordpress/core-data";
import {
  useCallback,
  useEffect,
  useLayoutEffect,
  useMemo,
  useRef
} from "@wordpress/element";
import { Placeholder, SandBox, Spinner } from "@wordpress/components";
import { compose, useResizeObserver } from "@wordpress/compose";
import {
  withColors,
  ColorPalette,
  useBlockProps,
  useSettings,
  useInnerBlocksProps,
  __experimentalUseGradient,
  store as blockEditorStore,
  useBlockEditingMode,
  privateApis as blockEditorPrivateApis
} from "@wordpress/block-editor";
import { __ } from "@wordpress/i18n";
import { useSelect, useDispatch } from "@wordpress/data";
import { isBlobURL } from "@wordpress/blob";
import { store as noticesStore } from "@wordpress/notices";
import {
  attributesFromMedia,
  IMAGE_BACKGROUND_TYPE,
  VIDEO_BACKGROUND_TYPE,
  EMBED_VIDEO_BACKGROUND_TYPE,
  dimRatioToClass,
  isContentPositionCenter,
  getPositionClassName,
  mediaPosition
} from "../shared.mjs";
import CoverInspectorControls from "./inspector-controls.mjs";
import CoverBlockControls from "./block-controls.mjs";
import CoverPlaceholder from "./cover-placeholder.mjs";
import ResizableCoverPopover from "./resizable-cover-popover.mjs";
import {
  getMediaColor,
  compositeIsDark,
  DEFAULT_BACKGROUND_COLOR,
  DEFAULT_OVERLAY_COLOR
} from "./color-utils.mjs";
import { DEFAULT_MEDIA_SIZE_SLUG } from "../constants.mjs";
import { getBackgroundEmbedHtml } from "../embed-video-utils.mjs";
import { unlock } from "../../lock-unlock.mjs";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
var { openMediaEditorModalKey } = unlock(blockEditorPrivateApis);
function getInnerBlocksTemplate(attributes) {
  return [
    [
      "core/paragraph",
      {
        style: {
          typography: {
            textAlign: "center"
          }
        },
        placeholder: __("Write title…"),
        ...attributes
      }
    ]
  ];
}
var isTemporaryMedia = (id, url) => !id && isBlobURL(url);
function CoverEdit({
  attributes,
  clientId,
  isSelected,
  overlayColor,
  setAttributes,
  setOverlayColor,
  toggleSelection,
  context: { postId, postType }
}) {
  const {
    contentPosition,
    id,
    url: originalUrl,
    backgroundType: originalBackgroundType,
    useFeaturedImage,
    dimRatio,
    focalPoint,
    hasParallax,
    isDark,
    isRepeated,
    minHeight,
    minHeightUnit,
    alt,
    allowedBlocks,
    templateLock,
    tagName: TagName = "div",
    isUserOverlayColor,
    sizeSlug,
    poster
  } = attributes;
  const [featuredImage] = useEntityProp(
    "postType",
    postType,
    "featured_media",
    postId
  );
  const { getSettings } = useSelect(blockEditorStore);
  const openMediaEditorModal = useSelect(
    (select) => select(blockEditorStore).getSettings()[openMediaEditorModalKey],
    []
  );
  const { __unstableMarkNextChangeAsNotPersistent } = useDispatch(blockEditorStore);
  const propsRef = useRef({ attributes, overlayColor });
  useLayoutEffect(() => {
    propsRef.current = { attributes, overlayColor };
  });
  const { media } = useSelect(
    (select) => {
      return {
        media: featuredImage && useFeaturedImage ? select(coreStore).getEntityRecord(
          "postType",
          "attachment",
          featuredImage,
          {
            context: "view"
          }
        ) : void 0
      };
    },
    [featuredImage, useFeaturedImage]
  );
  const mediaUrl = media?.media_details?.sizes?.[sizeSlug]?.source_url ?? media?.source_url;
  useEffect(() => {
    (async () => {
      if (!useFeaturedImage) {
        return;
      }
      const averageBackgroundColor = await getMediaColor(mediaUrl);
      const { attributes: currentAttrs, overlayColor: currentOverlay } = propsRef.current;
      let newOverlayColor = currentOverlay.color;
      if (!currentAttrs.isUserOverlayColor) {
        newOverlayColor = averageBackgroundColor;
        __unstableMarkNextChangeAsNotPersistent();
        setOverlayColor(newOverlayColor);
      }
      const newIsDark = compositeIsDark(
        currentAttrs.dimRatio,
        newOverlayColor,
        averageBackgroundColor
      );
      __unstableMarkNextChangeAsNotPersistent();
      setAttributes({
        isDark: newIsDark,
        isUserOverlayColor: currentAttrs.isUserOverlayColor || false
      });
    })();
  }, [
    mediaUrl,
    __unstableMarkNextChangeAsNotPersistent,
    setAttributes,
    setOverlayColor,
    useFeaturedImage
  ]);
  const url = useFeaturedImage ? mediaUrl : (
    // Ensure the url is not malformed due to sanitization through `wp_kses`.
    originalUrl?.replaceAll("&amp;", "&")
  );
  const backgroundType = useFeaturedImage ? IMAGE_BACKGROUND_TYPE : originalBackgroundType;
  const { createErrorNotice } = useDispatch(noticesStore);
  const { gradientClass, gradientValue } = __experimentalUseGradient();
  const onSelectMedia = async (newMedia) => {
    const mediaAttributes = attributesFromMedia(newMedia);
    const isImage = [newMedia?.type, newMedia?.media_type].includes(
      IMAGE_BACKGROUND_TYPE
    );
    const averageBackgroundColor = await getMediaColor(
      isImage ? newMedia?.url : void 0
    );
    const { attributes: currentAttrs, overlayColor: currentOverlay } = propsRef.current;
    let newOverlayColor = currentOverlay.color;
    if (!currentAttrs.isUserOverlayColor) {
      newOverlayColor = averageBackgroundColor;
      setOverlayColor(newOverlayColor);
      __unstableMarkNextChangeAsNotPersistent();
    }
    const newDimRatio = currentAttrs.url === void 0 && currentAttrs.dimRatio === 100 ? 50 : currentAttrs.dimRatio;
    const newIsDark = compositeIsDark(
      newDimRatio,
      newOverlayColor,
      averageBackgroundColor
    );
    if (backgroundType === IMAGE_BACKGROUND_TYPE && mediaAttributes?.id) {
      const { imageDefaultSize } = getSettings();
      if (sizeSlug && (newMedia?.sizes?.[sizeSlug] || newMedia?.media_details?.sizes?.[sizeSlug])) {
        mediaAttributes.sizeSlug = sizeSlug;
        mediaAttributes.url = newMedia?.sizes?.[sizeSlug]?.url || newMedia?.media_details?.sizes?.[sizeSlug]?.source_url;
      } else if (newMedia?.sizes?.[imageDefaultSize] || newMedia?.media_details?.sizes?.[imageDefaultSize]) {
        mediaAttributes.sizeSlug = imageDefaultSize;
        mediaAttributes.url = newMedia?.sizes?.[imageDefaultSize]?.url || newMedia?.media_details?.sizes?.[imageDefaultSize]?.source_url;
      } else {
        mediaAttributes.sizeSlug = DEFAULT_MEDIA_SIZE_SLUG;
      }
    }
    setAttributes({
      ...mediaAttributes,
      focalPoint: void 0,
      useFeaturedImage: void 0,
      dimRatio: newDimRatio,
      isDark: newIsDark,
      isUserOverlayColor: currentAttrs.isUserOverlayColor || false
    });
  };
  const onClearMedia = () => {
    let newOverlayColor = overlayColor.color;
    if (!isUserOverlayColor) {
      newOverlayColor = DEFAULT_OVERLAY_COLOR;
      setOverlayColor(void 0);
      __unstableMarkNextChangeAsNotPersistent();
    }
    const newIsDark = compositeIsDark(
      dimRatio,
      newOverlayColor,
      DEFAULT_BACKGROUND_COLOR
    );
    setAttributes({
      url: void 0,
      id: void 0,
      backgroundType: void 0,
      focalPoint: void 0,
      hasParallax: void 0,
      isRepeated: void 0,
      useFeaturedImage: void 0,
      isDark: newIsDark
    });
  };
  const onSetOverlayColor = async (newOverlayColor) => {
    const averageBackgroundColor = await getMediaColor(url);
    const { attributes: currentAttrs } = propsRef.current;
    const newIsDark = compositeIsDark(
      currentAttrs.dimRatio,
      newOverlayColor,
      averageBackgroundColor
    );
    setOverlayColor(newOverlayColor);
    __unstableMarkNextChangeAsNotPersistent();
    setAttributes({
      isUserOverlayColor: true,
      isDark: newIsDark
    });
  };
  const onUpdateDimRatio = async (newDimRatio) => {
    const averageBackgroundColor = await getMediaColor(url);
    const { overlayColor: currentOverlay } = propsRef.current;
    const newIsDark = compositeIsDark(
      newDimRatio,
      currentOverlay.color,
      averageBackgroundColor
    );
    setAttributes({
      dimRatio: newDimRatio,
      isDark: newIsDark
    });
  };
  const onUploadError = (message) => {
    createErrorNotice(message, { type: "snackbar" });
  };
  const onSelectEmbedUrl = (embedUrl) => {
    const newDimRatio = originalUrl === void 0 && dimRatio === 100 ? 50 : dimRatio;
    setAttributes({
      url: embedUrl,
      backgroundType: EMBED_VIDEO_BACKGROUND_TYPE,
      dimRatio: newDimRatio,
      id: void 0,
      focalPoint: void 0,
      hasParallax: void 0,
      isRepeated: void 0,
      useFeaturedImage: void 0
    });
  };
  const { embedPreview, isFetchingEmbed } = useSelect(
    (select) => {
      if (backgroundType !== EMBED_VIDEO_BACKGROUND_TYPE || !url) {
        return {
          embedPreview: void 0,
          isFetchingEmbed: false
        };
      }
      const { getEmbedPreview, isRequestingEmbedPreview } = select(coreStore);
      return {
        embedPreview: getEmbedPreview(url),
        isFetchingEmbed: isRequestingEmbedPreview(url)
      };
    },
    [url, backgroundType]
  );
  const embedHtml = useMemo(() => {
    if (backgroundType !== EMBED_VIDEO_BACKGROUND_TYPE || !embedPreview?.html) {
      return null;
    }
    return getBackgroundEmbedHtml(embedPreview.html);
  }, [embedPreview, backgroundType]);
  const isUploadingMedia = isTemporaryMedia(id, url);
  const isImageBackground = IMAGE_BACKGROUND_TYPE === backgroundType;
  const isVideoBackground = VIDEO_BACKGROUND_TYPE === backgroundType;
  const isEmbedVideoBackground = EMBED_VIDEO_BACKGROUND_TYPE === backgroundType;
  const blockEditingMode = useBlockEditingMode();
  const hasNonContentControls = blockEditingMode === "default";
  const [resizeListener, { height, width }] = useResizeObserver();
  const resizableBoxDimensions = useMemo(() => {
    return {
      height: minHeightUnit === "px" && minHeight ? minHeight : "auto",
      width: "auto"
    };
  }, [minHeight, minHeightUnit]);
  const minHeightWithUnit = minHeight && minHeightUnit ? `${minHeight}${minHeightUnit}` : minHeight;
  const isImgElement = !(hasParallax || isRepeated);
  const style = {
    minHeight: minHeightWithUnit || void 0
  };
  const backgroundImage = url ? `url(${url})` : void 0;
  const backgroundPosition = mediaPosition(focalPoint);
  const bgStyle = { backgroundColor: overlayColor.color };
  const mediaStyle = {
    objectPosition: focalPoint && isImgElement ? mediaPosition(focalPoint) : void 0
  };
  const hasBackground = !!(url || overlayColor.color || gradientValue);
  const hasInnerBlocks = useSelect(
    (select) => select(blockEditorStore).getBlock(clientId).innerBlocks.length > 0,
    [clientId]
  );
  const ref = useRef();
  const blockProps = useBlockProps({ ref });
  const [fontSizes] = useSettings("typography.fontSizes");
  const hasFontSizes = fontSizes?.length > 0;
  const innerBlocksTemplate = getInnerBlocksTemplate({
    fontSize: hasFontSizes ? "large" : void 0
  });
  const innerBlocksProps = useInnerBlocksProps(
    {
      className: "wp-block-cover__inner-container"
    },
    {
      // Avoid template sync when the `templateLock` value is `all` or `contentOnly`.
      // See: https://github.com/WordPress/gutenberg/pull/45632
      template: !hasInnerBlocks ? innerBlocksTemplate : void 0,
      templateInsertUpdatesSelection: true,
      allowedBlocks,
      templateLock,
      dropZoneElement: ref.current
    }
  );
  const mediaElement = useRef();
  const editMediaButtonRef = useRef();
  const currentSettings = {
    isVideoBackground,
    isImageBackground,
    mediaElement,
    hasInnerBlocks,
    url,
    isImgElement,
    overlayColor
  };
  const openCoverMediaEditorModal = useCallback(() => {
    if (!id || !openMediaEditorModal) {
      return;
    }
    openMediaEditorModal({
      id,
      onClose: () => {
        editMediaButtonRef.current?.focus();
      },
      onUpdate: async ({ id: newId, url: newUrl }) => {
        if (typeof newId !== "number") {
          return;
        }
        const nextAttributes = {
          id: newId,
          backgroundType: IMAGE_BACKGROUND_TYPE,
          ...newUrl ? { url: newUrl } : {},
          ...newId !== id ? { sizeSlug: DEFAULT_MEDIA_SIZE_SLUG } : {}
        };
        if (newUrl) {
          const averageBackgroundColor = await getMediaColor(newUrl);
          const {
            attributes: currentAttrs,
            overlayColor: currentOverlay
          } = propsRef.current;
          let newOverlayColor = currentOverlay.color;
          if (!currentAttrs.isUserOverlayColor) {
            newOverlayColor = averageBackgroundColor;
            setOverlayColor(newOverlayColor);
            __unstableMarkNextChangeAsNotPersistent();
          }
          nextAttributes.isDark = compositeIsDark(
            currentAttrs.dimRatio,
            newOverlayColor,
            averageBackgroundColor
          );
          nextAttributes.isUserOverlayColor = currentAttrs.isUserOverlayColor || false;
        }
        setAttributes(nextAttributes);
      }
    });
  }, [
    id,
    openMediaEditorModal,
    setAttributes,
    setOverlayColor,
    __unstableMarkNextChangeAsNotPersistent
  ]);
  const showEditMediaButton = hasNonContentControls && !useFeaturedImage && isImageBackground && !!id && !!url && !isUploadingMedia && !!openMediaEditorModal;
  const toggleUseFeaturedImage = async () => {
    const newUseFeaturedImage = !useFeaturedImage;
    const averageBackgroundColor = newUseFeaturedImage ? await getMediaColor(mediaUrl) : DEFAULT_BACKGROUND_COLOR;
    const { attributes: currentAttrs, overlayColor: currentOverlay } = propsRef.current;
    const newOverlayColor = !currentAttrs.isUserOverlayColor ? averageBackgroundColor : currentOverlay.color;
    if (!currentAttrs.isUserOverlayColor) {
      if (newUseFeaturedImage) {
        setOverlayColor(newOverlayColor);
      } else {
        setOverlayColor(void 0);
      }
      __unstableMarkNextChangeAsNotPersistent();
    }
    const newDimRatio = currentAttrs.dimRatio === 100 ? 50 : currentAttrs.dimRatio;
    const newIsDark = compositeIsDark(
      newDimRatio,
      newOverlayColor,
      averageBackgroundColor
    );
    setAttributes({
      id: void 0,
      url: void 0,
      useFeaturedImage: newUseFeaturedImage,
      dimRatio: newDimRatio,
      backgroundType: useFeaturedImage ? IMAGE_BACKGROUND_TYPE : void 0,
      isDark: newIsDark
    });
  };
  const blockControls = /* @__PURE__ */ jsx(
    CoverBlockControls,
    {
      attributes,
      setAttributes,
      onSelectMedia,
      onSelectEmbedUrl,
      currentSettings,
      toggleUseFeaturedImage,
      onClearMedia,
      blockEditingMode,
      onEditMedia: openCoverMediaEditorModal,
      editMediaButtonRef,
      showEditMediaButton
    }
  );
  const inspectorControls = /* @__PURE__ */ jsx(
    CoverInspectorControls,
    {
      attributes,
      setAttributes,
      clientId,
      setOverlayColor: onSetOverlayColor,
      coverRef: ref,
      currentSettings,
      toggleUseFeaturedImage,
      updateDimRatio: onUpdateDimRatio,
      onClearMedia,
      featuredImage: media
    }
  );
  const resizableCoverProps = {
    className: "block-library-cover__resize-container",
    clientId,
    height,
    minHeight: minHeightWithUnit,
    onResizeStart: () => {
      setAttributes({ minHeightUnit: "px" });
      toggleSelection(false);
    },
    onResize: (value) => {
      setAttributes({ minHeight: value });
    },
    onResizeStop: (newMinHeight) => {
      toggleSelection(true);
      setAttributes({ minHeight: newMinHeight });
    },
    // Hide the resize handle if an aspect ratio is set, as the aspect ratio takes precedence.
    showHandle: !attributes.style?.dimensions?.aspectRatio,
    size: resizableBoxDimensions,
    width
  };
  if (!useFeaturedImage && !hasInnerBlocks && !hasBackground) {
    return /* @__PURE__ */ jsxs(Fragment, { children: [
      blockControls,
      inspectorControls,
      hasNonContentControls && isSelected && /* @__PURE__ */ jsx(ResizableCoverPopover, { ...resizableCoverProps }),
      /* @__PURE__ */ jsxs(
        TagName,
        {
          ...blockProps,
          className: clsx("is-placeholder", blockProps.className),
          style: {
            ...blockProps.style,
            minHeight: minHeightWithUnit || void 0
          },
          children: [
            resizeListener,
            /* @__PURE__ */ jsx(
              CoverPlaceholder,
              {
                onSelectMedia,
                onError: onUploadError,
                toggleUseFeaturedImage,
                children: /* @__PURE__ */ jsx("div", { className: "wp-block-cover__placeholder-background-options", children: /* @__PURE__ */ jsx(
                  ColorPalette,
                  {
                    disableCustomColors: true,
                    value: overlayColor.color,
                    onChange: onSetOverlayColor,
                    clearable: false,
                    asButtons: true,
                    "aria-label": __("Overlay color")
                  }
                ) })
              }
            )
          ]
        }
      )
    ] });
  }
  const classes = clsx(
    {
      "is-dark-theme": isDark,
      "is-light": !isDark,
      "is-transient": isUploadingMedia,
      "has-parallax": hasParallax,
      "is-repeated": isRepeated,
      "has-custom-content-position": !isContentPositionCenter(contentPosition)
    },
    getPositionClassName(contentPosition)
  );
  const showOverlay = url || !useFeaturedImage || useFeaturedImage && !url;
  return /* @__PURE__ */ jsxs(Fragment, { children: [
    blockControls,
    inspectorControls,
    /* @__PURE__ */ jsxs(
      TagName,
      {
        ...blockProps,
        className: clsx(classes, blockProps.className),
        style: { ...style, ...blockProps.style },
        "data-url": url,
        children: [
          resizeListener,
          !url && useFeaturedImage && /* @__PURE__ */ jsx(
            Placeholder,
            {
              className: "wp-block-cover__image--placeholder-image",
              withIllustration: true
            }
          ),
          url && isImageBackground && (isImgElement ? /* @__PURE__ */ jsx(
            "img",
            {
              ref: mediaElement,
              className: "wp-block-cover__image-background",
              alt,
              src: url,
              style: mediaStyle
            }
          ) : /* @__PURE__ */ jsx(
            "div",
            {
              ref: mediaElement,
              role: alt ? "img" : void 0,
              "aria-label": alt ? alt : void 0,
              className: clsx(
                classes,
                "wp-block-cover__image-background"
              ),
              style: { backgroundImage, backgroundPosition }
            }
          )),
          url && isVideoBackground && /* @__PURE__ */ jsx(
            "video",
            {
              ref: mediaElement,
              className: "wp-block-cover__video-background",
              autoPlay: true,
              muted: true,
              loop: true,
              src: url,
              poster,
              style: mediaStyle
            }
          ),
          isEmbedVideoBackground && embedHtml && /* @__PURE__ */ jsx(
            "div",
            {
              ref: mediaElement,
              className: "wp-block-cover__video-background wp-block-cover__embed-background",
              style: mediaStyle,
              children: /* @__PURE__ */ jsx(
                SandBox,
                {
                  allowSameOrigin: true,
                  html: embedHtml,
                  title: "Background video",
                  styles: [
                    "iframe{position:fixed;top:0;left:0;width:100%;height:100%;}"
                  ]
                }
              )
            }
          ),
          isEmbedVideoBackground && !embedHtml && isFetchingEmbed && /* @__PURE__ */ jsx(Spinner, {}),
          showOverlay && /* @__PURE__ */ jsx(
            "span",
            {
              "aria-hidden": "true",
              className: clsx(
                "wp-block-cover__background",
                dimRatioToClass(dimRatio),
                {
                  [overlayColor.class]: overlayColor.class,
                  "has-background-dim": dimRatio !== void 0,
                  // For backwards compatibility. Former versions of the Cover Block applied
                  // `.wp-block-cover__gradient-background` in the presence of
                  // media, a gradient and a dim.
                  "wp-block-cover__gradient-background": url && gradientValue && dimRatio !== 0,
                  "has-background-gradient": gradientValue,
                  [gradientClass]: gradientClass
                }
              ),
              style: { backgroundImage: gradientValue, ...bgStyle }
            }
          ),
          isUploadingMedia && /* @__PURE__ */ jsx(Spinner, {}),
          /* @__PURE__ */ jsx(
            CoverPlaceholder,
            {
              disableMediaButtons: true,
              onSelectMedia,
              onError: onUploadError,
              toggleUseFeaturedImage
            }
          ),
          /* @__PURE__ */ jsx("div", { ...innerBlocksProps })
        ]
      }
    ),
    hasNonContentControls && isSelected && /* @__PURE__ */ jsx(ResizableCoverPopover, { ...resizableCoverProps })
  ] });
}
var edit_default = compose([
  withColors({ overlayColor: "background-color" })
])(CoverEdit);
export {
  edit_default as default
};
//# sourceMappingURL=index.mjs.map
