// packages/block-editor/src/components/block-tools/insertion-point.js
import clsx from "clsx";
import { useSelect, useDispatch } from "@wordpress/data";
import {
  useRef,
  createContext,
  useContext,
  useCallback
} from "@wordpress/element";
import { __unstableMotion as motion } from "@wordpress/components";
import { useReducedMotion } from "@wordpress/compose";
import Inserter from "../inserter";
import { store as blockEditorStore } from "../../store";
import BlockPopoverInbetween from "../block-popover/inbetween";
import BlockDropZonePopover from "../block-popover/drop-zone";
import { unlock } from "../../lock-unlock";
import { jsx, jsxs } from "react/jsx-runtime";
var InsertionPointOpenRef = createContext();
InsertionPointOpenRef.displayName = "InsertionPointOpenRefContext";
function InbetweenInsertionPointPopover({
  __unstablePopoverSlot,
  __unstableContentRef,
  operation = "insert",
  nearestSide = "right"
}) {
  const { selectBlock, hideInsertionPoint } = useDispatch(blockEditorStore);
  const openRef = useContext(InsertionPointOpenRef);
  const ref = useRef();
  const {
    orientation,
    previousClientId,
    nextClientId,
    rootClientId,
    isInserterShown,
    isDistractionFree,
    isZoomOutMode
  } = useSelect((select) => {
    const {
      getBlockOrder,
      getBlockListSettings,
      getBlockInsertionPoint,
      isBlockBeingDragged,
      getPreviousBlockClientId,
      getNextBlockClientId,
      getSettings,
      isZoomOut
    } = unlock(select(blockEditorStore));
    const insertionPoint = getBlockInsertionPoint();
    const order = getBlockOrder(insertionPoint.rootClientId);
    if (!order.length) {
      return {};
    }
    let _previousClientId = order[insertionPoint.index - 1];
    let _nextClientId = order[insertionPoint.index];
    while (isBlockBeingDragged(_previousClientId)) {
      _previousClientId = getPreviousBlockClientId(_previousClientId);
    }
    while (isBlockBeingDragged(_nextClientId)) {
      _nextClientId = getNextBlockClientId(_nextClientId);
    }
    const settings = getSettings();
    return {
      previousClientId: _previousClientId,
      nextClientId: _nextClientId,
      orientation: getBlockListSettings(insertionPoint.rootClientId)?.orientation || "vertical",
      rootClientId: insertionPoint.rootClientId,
      isDistractionFree: settings.isDistractionFree,
      isInserterShown: insertionPoint?.__unstableWithInserter,
      isZoomOutMode: isZoomOut()
    };
  }, []);
  const { getBlockEditingMode } = useSelect(blockEditorStore);
  const disableMotion = useReducedMotion();
  function onClick(event) {
    if (event.target === ref.current && nextClientId && getBlockEditingMode(nextClientId) !== "disabled") {
      selectBlock(nextClientId, -1);
    }
  }
  function maybeHideInserterPoint(event) {
    if (event.target === ref.current && !openRef.current) {
      hideInsertionPoint();
    }
  }
  function onFocus(event) {
    if (event.target !== ref.current) {
      openRef.current = true;
    }
  }
  const maybeResetOpenRef = useCallback(
    (node) => {
      if (!node && openRef.current) {
        openRef.current = false;
      }
    },
    [openRef]
  );
  const lineVariants = {
    // Initial position starts from the center and invisible.
    start: {
      opacity: 0,
      scale: 0
    },
    // The line expands to fill the container. If the inserter is visible it
    // is delayed so it appears orchestrated.
    rest: {
      opacity: 1,
      scale: 1,
      transition: { delay: isInserterShown ? 0.5 : 0, type: "tween" }
    },
    hover: {
      opacity: 1,
      scale: 1,
      transition: { delay: 0.5, type: "tween" }
    }
  };
  const inserterVariants = {
    start: {
      scale: disableMotion ? 1 : 0
    },
    rest: {
      scale: 1,
      transition: { delay: 0.4, type: "tween" }
    }
  };
  if (isDistractionFree) {
    return null;
  }
  if (isZoomOutMode && operation !== "insert") {
    return null;
  }
  const orientationClassname = orientation === "horizontal" || operation === "group" ? "is-horizontal" : "is-vertical";
  const className = clsx(
    "block-editor-block-list__insertion-point",
    orientationClassname
  );
  return /* @__PURE__ */ jsx(
    BlockPopoverInbetween,
    {
      previousClientId,
      nextClientId,
      __unstablePopoverSlot,
      __unstableContentRef,
      operation,
      nearestSide,
      children: /* @__PURE__ */ jsxs(
        motion.div,
        {
          layout: !disableMotion,
          initial: disableMotion ? "rest" : "start",
          animate: "rest",
          whileHover: "hover",
          whileTap: "pressed",
          exit: "start",
          ref,
          tabIndex: -1,
          onClick,
          onFocus,
          className: clsx(className, {
            "is-with-inserter": isInserterShown
          }),
          onHoverEnd: maybeHideInserterPoint,
          children: [
            /* @__PURE__ */ jsx(
              motion.div,
              {
                variants: lineVariants,
                className: "block-editor-block-list__insertion-point-indicator",
                "data-testid": "block-list-insertion-point-indicator"
              }
            ),
            isInserterShown && /* @__PURE__ */ jsx(
              motion.div,
              {
                variants: inserterVariants,
                className: clsx(
                  "block-editor-block-list__insertion-point-inserter"
                ),
                children: /* @__PURE__ */ jsx(
                  Inserter,
                  {
                    ref: maybeResetOpenRef,
                    position: "bottom center",
                    clientId: nextClientId,
                    rootClientId,
                    __experimentalIsQuick: true,
                    onToggle: (isOpen) => {
                      openRef.current = isOpen;
                    },
                    onSelectOrClose: () => {
                      openRef.current = false;
                    }
                  }
                )
              }
            )
          ]
        }
      )
    }
  );
}
function InsertionPoint(props) {
  const { insertionPoint, isVisible, isBlockListEmpty } = useSelect(
    (select) => {
      const {
        getBlockInsertionPoint,
        isBlockInsertionPointVisible,
        getBlockCount
      } = select(blockEditorStore);
      const blockInsertionPoint = getBlockInsertionPoint();
      return {
        insertionPoint: blockInsertionPoint,
        isVisible: isBlockInsertionPointVisible(),
        isBlockListEmpty: getBlockCount(blockInsertionPoint?.rootClientId) === 0
      };
    },
    []
  );
  if (!isVisible || // Don't render the insertion point if the block list is empty.
  // The insertion point will be represented by the appender instead.
  isBlockListEmpty) {
    return null;
  }
  return insertionPoint.operation === "replace" ? /* @__PURE__ */ jsx(
    BlockDropZonePopover,
    {
      ...props
    },
    `${insertionPoint.rootClientId}-${insertionPoint.index}`
  ) : /* @__PURE__ */ jsx(
    InbetweenInsertionPointPopover,
    {
      operation: insertionPoint.operation,
      nearestSide: insertionPoint.nearestSide,
      ...props
    }
  );
}
export {
  InsertionPointOpenRef,
  InsertionPoint as default
};
//# sourceMappingURL=insertion-point.js.map
