// packages/block-editor/src/components/global-styles/dimensions-panel.js
import clsx from "clsx";
import { __ } from "@wordpress/i18n";
import {
  __experimentalToolsPanel as ToolsPanel,
  __experimentalToolsPanelItem as ToolsPanelItem,
  BoxControl,
  __experimentalUnitControl as UnitControl,
  __experimentalUseCustomUnits as useCustomUnits,
  __experimentalInputControlPrefixWrapper as InputControlPrefixWrapper
} from "@wordpress/components";
import { Icon, alignNone, stretchWide } from "@wordpress/icons";
import { useCallback, useState } from "@wordpress/element";
import { getValueFromVariable } from "@wordpress/global-styles-engine";
import { useToolsPanelDropdownMenuProps } from "./utils.mjs";
import SpacingSizesControl from "../spacing-sizes-control/index.mjs";
import DimensionControl from "../dimension-control/index.mjs";
import ChildLayoutControl from "../child-layout-control/index.mjs";
import AspectRatioTool from "../dimensions-tool/aspect-ratio-tool.mjs";
import { cleanEmptyObject } from "../../hooks/utils.mjs";
import { setImmutably } from "../../utils/object.mjs";
import {
  DEFAULT_BLOCK_STYLE_STATE,
  hasPseudoBlockStyleState,
  hasViewportBlockStyleState
} from "../../hooks/block-style-state.mjs";
import { jsx, jsxs } from "react/jsx-runtime";
var AXIAL_SIDES = ["horizontal", "vertical"];
function useHasDimensionsPanel(settings, styleState = DEFAULT_BLOCK_STYLE_STATE) {
  return hasContentSize(settings) || hasWideSize(settings) || hasPadding(settings) || hasMargin(settings) || hasGap(settings) || hasHeight(settings) || hasMinHeight(settings) || hasMinWidth(settings) || hasWidth(settings) || hasAspectRatio(settings, styleState) || hasChildLayout(settings, styleState);
}
function hasContentSize(settings) {
  return settings?.layout?.contentSize;
}
function hasWideSize(settings) {
  return settings?.layout?.wideSize;
}
function hasPadding(settings) {
  return settings?.spacing?.padding;
}
function hasMargin(settings) {
  return settings?.spacing?.margin;
}
function hasGap(settings) {
  return settings?.spacing?.blockGap;
}
function hasHeight(settings) {
  return settings?.dimensions?.height;
}
function hasMinHeight(settings) {
  return settings?.dimensions?.minHeight;
}
function hasMinWidth(settings) {
  return settings?.dimensions?.minWidth;
}
function hasWidth(settings) {
  return settings?.dimensions?.width;
}
function hasAspectRatio(settings, styleState = DEFAULT_BLOCK_STYLE_STATE) {
  return !hasPseudoBlockStyleState(styleState) && settings?.dimensions?.aspectRatio;
}
function hasChildLayout(settings, styleState = DEFAULT_BLOCK_STYLE_STATE) {
  if (hasPseudoBlockStyleState(styleState)) {
    return false;
  }
  const {
    type: parentLayoutType = "default",
    default: { type: defaultParentLayoutType = "default" } = {},
    allowSizingOnChildren = false
  } = settings?.parentLayout ?? {};
  const support = (defaultParentLayoutType === "flex" || parentLayoutType === "flex" || defaultParentLayoutType === "grid" || parentLayoutType === "grid") && allowSizingOnChildren;
  return !!settings?.layout && support;
}
function hasSpacingPresets(settings) {
  const { defaultSpacingSizes, spacingSizes } = settings?.spacing || {};
  return defaultSpacingSizes !== false && spacingSizes?.default?.length > 0 || spacingSizes?.theme?.length > 0 || spacingSizes?.custom?.length > 0;
}
function filterValuesBySides(values, sides) {
  if (!sides || !values) {
    return values;
  }
  const filteredValues = {};
  sides.forEach((side) => {
    if (side === "vertical") {
      filteredValues.top = values.top;
      filteredValues.bottom = values.bottom;
    }
    if (side === "horizontal") {
      filteredValues.left = values.left;
      filteredValues.right = values.right;
    }
    filteredValues[side] = values?.[side];
  });
  return filteredValues;
}
function splitStyleValue(value) {
  if (value && typeof value === "string") {
    return {
      top: value,
      right: value,
      bottom: value,
      left: value
    };
  }
  return value;
}
function splitGapValue(value, isAxialGap) {
  if (!value) {
    return value;
  }
  if (typeof value === "string") {
    return isAxialGap ? { top: value, right: value, bottom: value, left: value } : { top: value };
  }
  return {
    ...value,
    right: value?.left,
    bottom: value?.top
  };
}
function DimensionsToolsPanel({
  resetAllFilter,
  onChange,
  value,
  panelId,
  children
}) {
  const dropdownMenuProps = useToolsPanelDropdownMenuProps();
  const resetAll = () => {
    const updatedValue = resetAllFilter(value);
    onChange(updatedValue);
  };
  return /* @__PURE__ */ jsx(
    ToolsPanel,
    {
      label: __("Dimensions"),
      resetAll,
      panelId,
      dropdownMenuProps,
      children
    }
  );
}
var DEFAULT_CONTROLS = {
  contentSize: true,
  wideSize: true,
  padding: true,
  margin: true,
  blockGap: true,
  height: true,
  minHeight: true,
  minWidth: true,
  width: true,
  aspectRatio: true,
  childLayout: true
};
function DimensionsPanel({
  as: Wrapper = DimensionsToolsPanel,
  value,
  onChange,
  inheritedValue = value,
  settings,
  panelId,
  defaultControls = DEFAULT_CONTROLS,
  onVisualize = () => {
  },
  // Special case because the layout controls are not part of the dimensions panel
  // in global styles but not in block inspector.
  includeLayoutControls = false,
  styleState = DEFAULT_BLOCK_STYLE_STATE
}) {
  const { dimensions, spacing } = settings;
  const decodeValue = (rawValue) => {
    if (rawValue && typeof rawValue === "object") {
      return Object.keys(rawValue).reduce((acc, key) => {
        acc[key] = getValueFromVariable(
          { settings: { dimensions, spacing } },
          "",
          rawValue[key]
        );
        return acc;
      }, {});
    }
    return getValueFromVariable(
      { settings: { dimensions, spacing } },
      "",
      rawValue
    );
  };
  const showSpacingPresetsControl = hasSpacingPresets(settings);
  const units = useCustomUnits({
    availableUnits: settings?.spacing?.units || [
      "%",
      "px",
      "em",
      "rem",
      "vw"
    ]
  });
  const minimumMargin = -Infinity;
  const [minMarginValue, setMinMarginValue] = useState(minimumMargin);
  const resetAllFilter = useCallback((previousValue) => {
    return {
      ...previousValue,
      layout: cleanEmptyObject({
        ...previousValue?.layout,
        contentSize: void 0,
        wideSize: void 0,
        selfStretch: void 0,
        flexSize: void 0,
        columnStart: void 0,
        rowStart: void 0,
        columnSpan: void 0,
        rowSpan: void 0
      }),
      spacing: {
        ...previousValue?.spacing,
        padding: void 0,
        margin: void 0,
        blockGap: void 0
      },
      dimensions: {
        ...previousValue?.dimensions,
        height: void 0,
        minHeight: void 0,
        minWidth: void 0,
        aspectRatio: void 0,
        width: void 0
      }
    };
  }, []);
  const showContentSizeControl = hasContentSize(settings) && includeLayoutControls;
  const contentSizeValue = decodeValue(inheritedValue?.layout?.contentSize);
  const setContentSizeValue = (newValue) => {
    onChange(
      setImmutably(
        value,
        ["layout", "contentSize"],
        newValue || void 0
      )
    );
  };
  const hasUserSetContentSizeValue = () => !!value?.layout?.contentSize;
  const resetContentSizeValue = () => setContentSizeValue(void 0);
  const showWideSizeControl = hasWideSize(settings) && includeLayoutControls;
  const wideSizeValue = decodeValue(inheritedValue?.layout?.wideSize);
  const setWideSizeValue = (newValue) => {
    onChange(
      setImmutably(
        value,
        ["layout", "wideSize"],
        newValue || void 0
      )
    );
  };
  const hasUserSetWideSizeValue = () => !!value?.layout?.wideSize;
  const resetWideSizeValue = () => setWideSizeValue(void 0);
  const showPaddingControl = hasPadding(settings);
  const rawPadding = decodeValue(inheritedValue?.spacing?.padding);
  const paddingValues = splitStyleValue(rawPadding);
  const paddingSides = Array.isArray(settings?.spacing?.padding) ? settings?.spacing?.padding : settings?.spacing?.padding?.sides;
  const isAxialPadding = paddingSides && paddingSides.some((side) => AXIAL_SIDES.includes(side));
  const setPaddingValues = (newPaddingValues) => {
    const padding = filterValuesBySides(newPaddingValues, paddingSides);
    onChange(setImmutably(value, ["spacing", "padding"], padding));
  };
  const hasPaddingValue = () => !!value?.spacing?.padding && Object.keys(value?.spacing?.padding).length;
  const resetPaddingValue = () => setPaddingValues(void 0);
  const onMouseOverPadding = () => onVisualize("padding");
  const showMarginControl = hasMargin(settings);
  const rawMargin = decodeValue(inheritedValue?.spacing?.margin);
  const marginValues = splitStyleValue(rawMargin);
  const marginSides = Array.isArray(settings?.spacing?.margin) ? settings?.spacing?.margin : settings?.spacing?.margin?.sides;
  const isAxialMargin = marginSides && marginSides.some((side) => AXIAL_SIDES.includes(side));
  const setMarginValues = (newMarginValues) => {
    const margin = filterValuesBySides(newMarginValues, marginSides);
    onChange(setImmutably(value, ["spacing", "margin"], margin));
  };
  const hasMarginValue = () => !!value?.spacing?.margin && Object.keys(value?.spacing?.margin).length;
  const resetMarginValue = () => setMarginValues(void 0);
  const onMouseOverMargin = () => onVisualize("margin");
  const showGapControl = hasGap(settings);
  const gapSides = Array.isArray(settings?.spacing?.blockGap) ? settings?.spacing?.blockGap : settings?.spacing?.blockGap?.sides;
  const isAxialGap = gapSides && gapSides.some((side) => AXIAL_SIDES.includes(side));
  const gapValue = decodeValue(inheritedValue?.spacing?.blockGap);
  const gapValues = splitGapValue(gapValue, isAxialGap);
  const setGapValue = (newGapValue) => {
    onChange(
      setImmutably(value, ["spacing", "blockGap"], newGapValue)
    );
  };
  const setGapValues = (nextBoxGapValue) => {
    if (!nextBoxGapValue) {
      setGapValue(null);
    }
    if (!isAxialGap && nextBoxGapValue?.hasOwnProperty("top")) {
      setGapValue(nextBoxGapValue.top);
    } else {
      setGapValue({
        top: nextBoxGapValue?.top,
        left: nextBoxGapValue?.left
      });
    }
  };
  const resetGapValue = () => setGapValue(void 0);
  const hasGapValue = () => !!value?.spacing?.blockGap;
  const showMinHeightControl = hasMinHeight(settings);
  const minHeightValue = decodeValue(inheritedValue?.dimensions?.minHeight);
  const setMinHeightValue = (newValue) => {
    const tempValue = setImmutably(
      value,
      ["dimensions", "minHeight"],
      newValue
    );
    onChange(
      setImmutably(
        tempValue,
        ["dimensions", "aspectRatio"],
        void 0
      )
    );
  };
  const resetMinHeightValue = () => {
    setMinHeightValue(void 0);
  };
  const hasMinHeightValue = () => !!value?.dimensions?.minHeight;
  const showHeightControl = hasHeight(settings);
  const heightValue = decodeValue(inheritedValue?.dimensions?.height);
  const setHeightValue = (newValue) => {
    const tempValue = setImmutably(
      value,
      ["dimensions", "height"],
      newValue
    );
    onChange(
      setImmutably(
        tempValue,
        ["dimensions", "aspectRatio"],
        void 0
      )
    );
  };
  const resetHeightValue = () => {
    setHeightValue(void 0);
  };
  const hasHeightValue = () => !!value?.dimensions?.height;
  const showMinWidthControl = hasMinWidth(settings);
  const minWidthValue = decodeValue(inheritedValue?.dimensions?.minWidth);
  const setMinWidthValue = (newValue) => {
    onChange(
      setImmutably(value, ["dimensions", "minWidth"], newValue)
    );
  };
  const resetMinWidthValue = () => {
    setMinWidthValue(void 0);
  };
  const hasMinWidthValue = () => !!value?.dimensions?.minWidth;
  const showWidthControl = hasWidth(settings);
  const widthValue = decodeValue(inheritedValue?.dimensions?.width);
  const setWidthValue = (newValue) => {
    onChange(setImmutably(value, ["dimensions", "width"], newValue));
  };
  const resetWidthValue = () => {
    setWidthValue(void 0);
  };
  const hasWidthValue = () => !!value?.dimensions?.width;
  const showAspectRatioControl = hasAspectRatio(settings, styleState);
  const aspectRatioValue = decodeValue(
    inheritedValue?.dimensions?.aspectRatio
  );
  const setAspectRatioValue = (newValue) => {
    const tempValue = setImmutably(
      value,
      ["dimensions", "aspectRatio"],
      newValue
    );
    onChange(
      setImmutably(tempValue, ["dimensions", "minHeight"], void 0)
    );
  };
  const hasAspectRatioValue = () => !!value?.dimensions?.aspectRatio;
  const showChildLayoutControl = hasChildLayout(settings, styleState);
  const childLayout = inheritedValue?.layout;
  const setChildLayout = (newChildLayout) => {
    onChange({
      ...value,
      layout: {
        ...value?.layout,
        ...newChildLayout
      }
    });
  };
  const onMouseLeaveControls = () => onVisualize(false);
  return /* @__PURE__ */ jsxs(
    Wrapper,
    {
      resetAllFilter,
      value,
      onChange,
      panelId,
      children: [
        (showContentSizeControl || showWideSizeControl) && /* @__PURE__ */ jsx("span", { className: "span-columns", children: __("Set the width of the main content area.") }),
        showContentSizeControl && /* @__PURE__ */ jsx(
          ToolsPanelItem,
          {
            label: __("Content width"),
            hasValue: hasUserSetContentSizeValue,
            onDeselect: resetContentSizeValue,
            isShownByDefault: defaultControls.contentSize ?? DEFAULT_CONTROLS.contentSize,
            panelId,
            children: /* @__PURE__ */ jsx(
              UnitControl,
              {
                __next40pxDefaultSize: true,
                label: __("Content width"),
                labelPosition: "top",
                value: contentSizeValue || "",
                onChange: (nextContentSize) => {
                  setContentSizeValue(nextContentSize);
                },
                units,
                prefix: /* @__PURE__ */ jsx(InputControlPrefixWrapper, { variant: "icon", children: /* @__PURE__ */ jsx(Icon, { icon: alignNone }) })
              }
            )
          }
        ),
        showWideSizeControl && /* @__PURE__ */ jsx(
          ToolsPanelItem,
          {
            label: __("Wide width"),
            hasValue: hasUserSetWideSizeValue,
            onDeselect: resetWideSizeValue,
            isShownByDefault: defaultControls.wideSize ?? DEFAULT_CONTROLS.wideSize,
            panelId,
            children: /* @__PURE__ */ jsx(
              UnitControl,
              {
                __next40pxDefaultSize: true,
                label: __("Wide width"),
                labelPosition: "top",
                value: wideSizeValue || "",
                onChange: (nextWideSize) => {
                  setWideSizeValue(nextWideSize);
                },
                units,
                prefix: /* @__PURE__ */ jsx(InputControlPrefixWrapper, { variant: "icon", children: /* @__PURE__ */ jsx(Icon, { icon: stretchWide }) })
              }
            )
          }
        ),
        showPaddingControl && /* @__PURE__ */ jsxs(
          ToolsPanelItem,
          {
            hasValue: hasPaddingValue,
            label: __("Padding"),
            onDeselect: resetPaddingValue,
            isShownByDefault: defaultControls.padding ?? DEFAULT_CONTROLS.padding,
            className: clsx({
              "tools-panel-item-spacing": showSpacingPresetsControl
            }),
            panelId,
            children: [
              !showSpacingPresetsControl && /* @__PURE__ */ jsx(
                BoxControl,
                {
                  values: paddingValues,
                  onChange: setPaddingValues,
                  label: __("Padding"),
                  sides: paddingSides,
                  units,
                  allowReset: false,
                  splitOnAxis: isAxialPadding,
                  inputProps: {
                    onMouseOver: onMouseOverPadding,
                    onMouseOut: onMouseLeaveControls
                  }
                }
              ),
              showSpacingPresetsControl && /* @__PURE__ */ jsx(
                SpacingSizesControl,
                {
                  values: paddingValues,
                  onChange: setPaddingValues,
                  label: __("Padding"),
                  sides: paddingSides,
                  units,
                  allowReset: false,
                  onMouseOver: onMouseOverPadding,
                  onMouseOut: onMouseLeaveControls
                }
              )
            ]
          }
        ),
        showMarginControl && /* @__PURE__ */ jsxs(
          ToolsPanelItem,
          {
            hasValue: hasMarginValue,
            label: __("Margin"),
            onDeselect: resetMarginValue,
            isShownByDefault: defaultControls.margin ?? DEFAULT_CONTROLS.margin,
            className: clsx({
              "tools-panel-item-spacing": showSpacingPresetsControl
            }),
            panelId,
            children: [
              !showSpacingPresetsControl && /* @__PURE__ */ jsx(
                BoxControl,
                {
                  values: marginValues,
                  onChange: setMarginValues,
                  inputProps: {
                    min: minMarginValue,
                    onDragStart: () => {
                      setMinMarginValue(0);
                    },
                    onDragEnd: () => {
                      setMinMarginValue(minimumMargin);
                    },
                    onMouseOver: onMouseOverMargin,
                    onMouseOut: onMouseLeaveControls
                  },
                  label: __("Margin"),
                  sides: marginSides,
                  units,
                  allowReset: false,
                  splitOnAxis: isAxialMargin
                }
              ),
              showSpacingPresetsControl && /* @__PURE__ */ jsx(
                SpacingSizesControl,
                {
                  values: marginValues,
                  onChange: setMarginValues,
                  minimumCustomValue: -Infinity,
                  label: __("Margin"),
                  sides: marginSides,
                  units,
                  allowReset: false,
                  onMouseOver: onMouseOverMargin,
                  onMouseOut: onMouseLeaveControls
                }
              )
            ]
          }
        ),
        showGapControl && /* @__PURE__ */ jsxs(
          ToolsPanelItem,
          {
            hasValue: hasGapValue,
            label: __("Block spacing"),
            onDeselect: resetGapValue,
            isShownByDefault: defaultControls.blockGap ?? DEFAULT_CONTROLS.blockGap,
            className: clsx({
              "tools-panel-item-spacing": showSpacingPresetsControl,
              "single-column": (
                // If UnitControl is used, should be single-column.
                !showSpacingPresetsControl && !isAxialGap
              )
            }),
            panelId,
            children: [
              !showSpacingPresetsControl && (isAxialGap ? /* @__PURE__ */ jsx(
                BoxControl,
                {
                  label: __("Block spacing"),
                  min: 0,
                  onChange: setGapValues,
                  units,
                  sides: gapSides,
                  values: gapValues,
                  allowReset: false,
                  splitOnAxis: isAxialGap
                }
              ) : /* @__PURE__ */ jsx(
                UnitControl,
                {
                  __next40pxDefaultSize: true,
                  label: __("Block spacing"),
                  min: 0,
                  onChange: setGapValue,
                  units,
                  value: gapValue
                }
              )),
              showSpacingPresetsControl && /* @__PURE__ */ jsx(
                SpacingSizesControl,
                {
                  label: __("Block spacing"),
                  min: 0,
                  onChange: setGapValues,
                  showSideInLabel: false,
                  sides: isAxialGap ? gapSides : ["top"],
                  values: gapValues,
                  allowReset: false
                }
              )
            ]
          }
        ),
        showChildLayoutControl && /* @__PURE__ */ jsx(
          ChildLayoutControl,
          {
            value: childLayout,
            onChange: setChildLayout,
            parentLayout: settings?.parentLayout,
            panelId,
            showGridSpanDefaults: !hasViewportBlockStyleState(styleState),
            isShownByDefault: defaultControls.childLayout ?? DEFAULT_CONTROLS.childLayout
          }
        ),
        showMinHeightControl && /* @__PURE__ */ jsx(
          ToolsPanelItem,
          {
            hasValue: hasMinHeightValue,
            label: __("Minimum height"),
            onDeselect: resetMinHeightValue,
            isShownByDefault: defaultControls.minHeight ?? DEFAULT_CONTROLS.minHeight,
            panelId,
            children: /* @__PURE__ */ jsx(
              DimensionControl,
              {
                label: __("Minimum height"),
                value: minHeightValue,
                onChange: setMinHeightValue,
                dimensionSizes: dimensions?.dimensionSizes
              }
            )
          }
        ),
        showMinWidthControl && /* @__PURE__ */ jsx(
          ToolsPanelItem,
          {
            hasValue: hasMinWidthValue,
            label: __("Minimum width"),
            onDeselect: resetMinWidthValue,
            isShownByDefault: defaultControls.minWidth ?? DEFAULT_CONTROLS.minWidth,
            panelId,
            children: /* @__PURE__ */ jsx(
              DimensionControl,
              {
                label: __("Minimum width"),
                value: minWidthValue,
                onChange: setMinWidthValue,
                dimensionSizes: dimensions?.dimensionSizes
              }
            )
          }
        ),
        showHeightControl && /* @__PURE__ */ jsx(
          ToolsPanelItem,
          {
            hasValue: hasHeightValue,
            label: __("Height"),
            onDeselect: resetHeightValue,
            isShownByDefault: defaultControls.height ?? DEFAULT_CONTROLS.height,
            panelId,
            children: /* @__PURE__ */ jsx(
              DimensionControl,
              {
                label: __("Height"),
                value: heightValue,
                onChange: setHeightValue,
                dimensionSizes: dimensions?.dimensionSizes
              }
            )
          }
        ),
        showWidthControl && /* @__PURE__ */ jsx(
          ToolsPanelItem,
          {
            hasValue: hasWidthValue,
            label: __("Width"),
            onDeselect: resetWidthValue,
            isShownByDefault: defaultControls.width ?? DEFAULT_CONTROLS.width,
            panelId,
            children: /* @__PURE__ */ jsx(
              DimensionControl,
              {
                label: __("Width"),
                value: widthValue,
                onChange: setWidthValue,
                dimensionSizes: dimensions?.dimensionSizes
              }
            )
          }
        ),
        showAspectRatioControl && /* @__PURE__ */ jsx(
          AspectRatioTool,
          {
            hasValue: hasAspectRatioValue,
            value: aspectRatioValue,
            onChange: setAspectRatioValue,
            panelId,
            isShownByDefault: defaultControls.aspectRatio ?? DEFAULT_CONTROLS.aspectRatio
          }
        )
      ]
    }
  );
}
export {
  DimensionsPanel as default,
  useHasDimensionsPanel
};
//# sourceMappingURL=dimensions-panel.mjs.map
