// packages/block-editor/src/hooks/utils.js
import clsx from "clsx";
import { getBlockSupport } from "@wordpress/blocks";
import { memo, useMemo, useEffect, useId, useState } from "@wordpress/element";
import { useDispatch, useRegistry } from "@wordpress/data";
import { createHigherOrderComponent } from "@wordpress/compose";
import { addFilter } from "@wordpress/hooks";
import {
  useBlockEditContext,
  mayDisplayControlsKey,
  mayDisplayParentControlsKey
} from "../components/block-edit/context.mjs";
import { useSettings } from "../components/index.mjs";
import { useSettingsForBlockElement } from "../components/global-styles/hooks.mjs";
import { getValueFromObjectPath, setImmutably } from "../utils/object.mjs";
import { store as blockEditorStore } from "../store/index.mjs";
import { unlock } from "../lock-unlock.mjs";
import { jsx } from "react/jsx-runtime";
var cleanEmptyObject = (object) => {
  if (object === null || typeof object !== "object" || Array.isArray(object)) {
    return object;
  }
  const cleanedNestedObjects = Object.entries(object).map(([key, value]) => [key, cleanEmptyObject(value)]).filter(([, value]) => value !== void 0);
  return !cleanedNestedObjects.length ? void 0 : Object.fromEntries(cleanedNestedObjects);
};
function transformStyles(activeSupports, migrationPaths, result, source, index, results) {
  if (Object.values(activeSupports ?? {}).every(
    (isActive) => !isActive
  )) {
    return result;
  }
  if (results.length === 1 && result.innerBlocks.length === source.length) {
    return result;
  }
  let referenceBlockAttributes = source[0]?.attributes;
  if (results.length > 1 && source.length > 1) {
    if (source[index]) {
      referenceBlockAttributes = source[index]?.attributes;
    } else {
      return result;
    }
  }
  let returnBlock = result;
  Object.entries(activeSupports).forEach(([support, isActive]) => {
    if (isActive) {
      migrationPaths[support].forEach((path) => {
        const styleValue = getValueFromObjectPath(
          referenceBlockAttributes,
          path
        );
        if (styleValue) {
          returnBlock = {
            ...returnBlock,
            attributes: setImmutably(
              returnBlock.attributes,
              path,
              styleValue
            )
          };
        }
      });
    }
  });
  return returnBlock;
}
function shouldSkipSerialization(blockNameOrType, featureSet, feature) {
  const support = getBlockSupport(blockNameOrType, featureSet);
  const skipSerialization = support?.__experimentalSkipSerialization;
  if (Array.isArray(skipSerialization)) {
    return skipSerialization.includes(feature);
  }
  return skipSerialization;
}
var pendingStyleOverrides = /* @__PURE__ */ new WeakMap();
function useStyleOverride({ id, css }) {
  return usePrivateStyleOverride({ id, css });
}
function usePrivateStyleOverride({
  id,
  css,
  assets,
  __unstableType,
  variation,
  clientId
} = {}) {
  const { setStyleOverride, deleteStyleOverride } = unlock(
    useDispatch(blockEditorStore)
  );
  const registry = useRegistry();
  const fallbackId = useId();
  useEffect(() => {
    if (!css && !assets) {
      return;
    }
    const _id = id || fallbackId;
    const override = {
      id,
      css,
      assets,
      __unstableType,
      variation,
      clientId
    };
    if (!pendingStyleOverrides.get(registry)) {
      pendingStyleOverrides.set(registry, []);
    }
    pendingStyleOverrides.get(registry).push([_id, override]);
    window.queueMicrotask(() => {
      if (pendingStyleOverrides.get(registry)?.length) {
        registry.batch(() => {
          pendingStyleOverrides.get(registry).forEach((args) => {
            setStyleOverride(...args);
          });
          pendingStyleOverrides.set(registry, []);
        });
      }
    });
    return () => {
      const isPending = pendingStyleOverrides.get(registry)?.find(([currentId]) => currentId === _id);
      if (isPending) {
        pendingStyleOverrides.set(
          registry,
          pendingStyleOverrides.get(registry).filter(([currentId]) => currentId !== _id)
        );
      } else {
        deleteStyleOverride(_id);
      }
    };
  }, [
    id,
    css,
    clientId,
    assets,
    __unstableType,
    fallbackId,
    setStyleOverride,
    deleteStyleOverride,
    registry,
    variation
  ]);
}
function useBlockSettings(name, parentLayout) {
  const [
    backgroundImage,
    backgroundSize,
    customFontFamilies,
    defaultFontFamilies,
    themeFontFamilies,
    defaultFontSizesEnabled,
    customFontSizes,
    defaultFontSizes,
    themeFontSizes,
    customFontSize,
    fontStyle,
    fontWeight,
    lineHeight,
    textAlign,
    textColumns,
    textDecoration,
    writingMode,
    textTransform,
    letterSpacing,
    padding,
    margin,
    blockGap,
    defaultSpacingSizesEnabled,
    customSpacingSize,
    userSpacingSizes,
    defaultSpacingSizes,
    themeSpacingSizes,
    units,
    aspectRatio,
    height,
    minHeight,
    width,
    dimensionSizes,
    layout,
    borderColor,
    borderRadius,
    borderStyle,
    borderWidth,
    borderRadiusSizes,
    customColorsEnabled,
    customColors,
    customDuotone,
    themeColors,
    defaultColors,
    defaultPalette,
    defaultDuotone,
    userDuotonePalette,
    themeDuotonePalette,
    defaultDuotonePalette,
    userGradientPalette,
    themeGradientPalette,
    defaultGradientPalette,
    defaultGradients,
    areCustomGradientsEnabled,
    isBackgroundEnabled,
    isLinkEnabled,
    isTextEnabled,
    isHeadingEnabled,
    isButtonEnabled,
    shadow
  ] = useSettings(
    "background.backgroundImage",
    "background.backgroundSize",
    "typography.fontFamilies.custom",
    "typography.fontFamilies.default",
    "typography.fontFamilies.theme",
    "typography.defaultFontSizes",
    "typography.fontSizes.custom",
    "typography.fontSizes.default",
    "typography.fontSizes.theme",
    "typography.customFontSize",
    "typography.fontStyle",
    "typography.fontWeight",
    "typography.lineHeight",
    "typography.textAlign",
    "typography.textColumns",
    "typography.textDecoration",
    "typography.writingMode",
    "typography.textTransform",
    "typography.letterSpacing",
    "spacing.padding",
    "spacing.margin",
    "spacing.blockGap",
    "spacing.defaultSpacingSizes",
    "spacing.customSpacingSize",
    "spacing.spacingSizes.custom",
    "spacing.spacingSizes.default",
    "spacing.spacingSizes.theme",
    "spacing.units",
    "dimensions.aspectRatio",
    "dimensions.height",
    "dimensions.minHeight",
    "dimensions.width",
    "dimensions.dimensionSizes",
    "layout",
    "border.color",
    "border.radius",
    "border.style",
    "border.width",
    "border.radiusSizes",
    "color.custom",
    "color.palette.custom",
    "color.customDuotone",
    "color.palette.theme",
    "color.palette.default",
    "color.defaultPalette",
    "color.defaultDuotone",
    "color.duotone.custom",
    "color.duotone.theme",
    "color.duotone.default",
    "color.gradients.custom",
    "color.gradients.theme",
    "color.gradients.default",
    "color.defaultGradients",
    "color.customGradient",
    "color.background",
    "color.link",
    "color.text",
    "color.heading",
    "color.button",
    "shadow"
  );
  const rawSettings = useMemo(() => {
    return {
      background: {
        backgroundImage,
        backgroundSize
      },
      color: {
        palette: {
          custom: customColors,
          theme: themeColors,
          default: defaultColors
        },
        gradients: {
          custom: userGradientPalette,
          theme: themeGradientPalette,
          default: defaultGradientPalette
        },
        duotone: {
          custom: userDuotonePalette,
          theme: themeDuotonePalette,
          default: defaultDuotonePalette
        },
        defaultGradients,
        defaultPalette,
        defaultDuotone,
        custom: customColorsEnabled,
        customGradient: areCustomGradientsEnabled,
        customDuotone,
        background: isBackgroundEnabled,
        link: isLinkEnabled,
        heading: isHeadingEnabled,
        button: isButtonEnabled,
        text: isTextEnabled
      },
      typography: {
        fontFamilies: {
          custom: customFontFamilies,
          default: defaultFontFamilies,
          theme: themeFontFamilies
        },
        fontSizes: {
          custom: customFontSizes,
          default: defaultFontSizes,
          theme: themeFontSizes
        },
        customFontSize,
        defaultFontSizes: defaultFontSizesEnabled,
        fontStyle,
        fontWeight,
        lineHeight,
        textAlign,
        textColumns,
        textDecoration,
        textTransform,
        letterSpacing,
        writingMode
      },
      spacing: {
        spacingSizes: {
          custom: userSpacingSizes,
          default: defaultSpacingSizes,
          theme: themeSpacingSizes
        },
        customSpacingSize,
        defaultSpacingSizes: defaultSpacingSizesEnabled,
        padding,
        margin,
        blockGap,
        units
      },
      border: {
        color: borderColor,
        radius: borderRadius,
        style: borderStyle,
        width: borderWidth,
        radiusSizes: borderRadiusSizes
      },
      dimensions: {
        aspectRatio,
        height,
        minHeight,
        width,
        dimensionSizes
      },
      layout,
      parentLayout,
      shadow
    };
  }, [
    backgroundImage,
    backgroundSize,
    customFontFamilies,
    defaultFontFamilies,
    themeFontFamilies,
    defaultFontSizesEnabled,
    customFontSizes,
    defaultFontSizes,
    themeFontSizes,
    customFontSize,
    fontStyle,
    fontWeight,
    lineHeight,
    textAlign,
    textColumns,
    textDecoration,
    textTransform,
    letterSpacing,
    writingMode,
    padding,
    margin,
    blockGap,
    defaultSpacingSizesEnabled,
    customSpacingSize,
    userSpacingSizes,
    defaultSpacingSizes,
    themeSpacingSizes,
    units,
    aspectRatio,
    height,
    minHeight,
    width,
    dimensionSizes,
    layout,
    parentLayout,
    borderColor,
    borderRadius,
    borderStyle,
    borderWidth,
    borderRadiusSizes,
    customColorsEnabled,
    customColors,
    customDuotone,
    themeColors,
    defaultColors,
    defaultPalette,
    defaultDuotone,
    userDuotonePalette,
    themeDuotonePalette,
    defaultDuotonePalette,
    userGradientPalette,
    themeGradientPalette,
    defaultGradientPalette,
    defaultGradients,
    areCustomGradientsEnabled,
    isBackgroundEnabled,
    isLinkEnabled,
    isTextEnabled,
    isHeadingEnabled,
    isButtonEnabled,
    shadow
  ]);
  return useSettingsForBlockElement(rawSettings, name);
}
function createBlockEditFilter(features) {
  features = features.map((settings) => {
    return { ...settings, Edit: memo(settings.edit) };
  });
  const withBlockEditHooks = createHigherOrderComponent(
    (OriginalBlockEdit) => (props) => {
      const context = useBlockEditContext();
      return [
        ...features.map((feature, i) => {
          const {
            Edit,
            hasSupport,
            attributeKeys = [],
            shareWithChildBlocks
          } = feature;
          const shouldDisplayControls = context[mayDisplayControlsKey] || context[mayDisplayParentControlsKey] && shareWithChildBlocks;
          if (!shouldDisplayControls || !hasSupport(props.name)) {
            return null;
          }
          const neededProps = {};
          for (const key of attributeKeys) {
            if (props.attributes[key]) {
              neededProps[key] = props.attributes[key];
            }
          }
          return /* @__PURE__ */ jsx(
            Edit,
            {
              name: props.name,
              isSelected: props.isSelected,
              clientId: props.clientId,
              setAttributes: props.setAttributes,
              __unstableParentLayout: props.__unstableParentLayout,
              ...neededProps
            },
            i
          );
        }),
        /* @__PURE__ */ jsx(OriginalBlockEdit, { ...props }, "edit")
      ];
    },
    "withBlockEditHooks"
  );
  addFilter("editor.BlockEdit", "core/editor/hooks", withBlockEditHooks);
}
function BlockProps({
  index,
  useBlockProps: hook,
  setAllWrapperProps,
  ...props
}) {
  const wrapperProps = hook(props);
  const setWrapperProps = (next) => setAllWrapperProps((prev) => {
    const nextAll = [...prev];
    nextAll[index] = next;
    return nextAll;
  });
  useEffect(() => {
    setWrapperProps(wrapperProps);
    return () => {
      setWrapperProps(void 0);
    };
  });
  return null;
}
var BlockPropsPure = memo(BlockProps);
function createBlockListBlockFilter(features) {
  const withBlockListBlockHooks = createHigherOrderComponent(
    (BlockListBlock) => (props) => {
      const [allWrapperProps, setAllWrapperProps] = useState(
        Array(features.length).fill(void 0)
      );
      return [
        ...features.map((feature, i) => {
          const {
            hasSupport,
            attributeKeys = [],
            useBlockProps,
            isMatch
          } = feature;
          const neededProps = {};
          for (const key of attributeKeys) {
            if (props.attributes[key]) {
              neededProps[key] = props.attributes[key];
            }
          }
          if (
            // Skip rendering if none of the needed attributes are
            // set.
            !Object.keys(neededProps).length || !hasSupport(props.name) || isMatch && !isMatch(neededProps)
          ) {
            return null;
          }
          return /* @__PURE__ */ jsx(
            BlockPropsPure,
            {
              index: i,
              useBlockProps,
              setAllWrapperProps,
              name: props.name,
              clientId: props.clientId,
              ...neededProps
            },
            i
          );
        }),
        /* @__PURE__ */ jsx(
          BlockListBlock,
          {
            ...props,
            wrapperProps: allWrapperProps.filter(Boolean).reduce((acc, wrapperProps) => {
              return {
                ...acc,
                ...wrapperProps,
                className: clsx(
                  acc.className,
                  wrapperProps.className
                ),
                style: {
                  ...acc.style,
                  ...wrapperProps.style
                }
              };
            }, props.wrapperProps || {})
          },
          "edit"
        )
      ];
    },
    "withBlockListBlockHooks"
  );
  addFilter(
    "editor.BlockListBlock",
    "core/editor/hooks",
    withBlockListBlockHooks
  );
}
function createBlockSaveFilter(features) {
  function extraPropsFromHooks(props, name, attributes) {
    return features.reduce((accu, feature) => {
      const { hasSupport, attributeKeys = [], addSaveProps } = feature;
      const neededAttributes = {};
      for (const key of attributeKeys) {
        if (attributes[key]) {
          neededAttributes[key] = attributes[key];
        }
      }
      if (
        // Skip rendering if none of the needed attributes are
        // set.
        !Object.keys(neededAttributes).length || !hasSupport(name)
      ) {
        return accu;
      }
      return addSaveProps(accu, name, neededAttributes);
    }, props);
  }
  addFilter(
    "blocks.getSaveContent.extraProps",
    "core/editor/hooks",
    extraPropsFromHooks,
    0
  );
  addFilter(
    "blocks.getSaveContent.extraProps",
    "core/editor/hooks",
    (props) => {
      if (props.hasOwnProperty("className") && !props.className) {
        delete props.className;
      }
      return props;
    }
  );
}
export {
  cleanEmptyObject,
  createBlockEditFilter,
  createBlockListBlockFilter,
  createBlockSaveFilter,
  shouldSkipSerialization,
  transformStyles,
  useBlockSettings,
  usePrivateStyleOverride,
  useStyleOverride
};
//# sourceMappingURL=utils.mjs.map
