@wordpress/block-editor
Version:
170 lines (169 loc) • 5.84 kB
JavaScript
// packages/block-editor/src/components/block-popover/inbetween.js
import clsx from "clsx";
import { useSelect } from "@wordpress/data";
import { useMemo, useReducer, useLayoutEffect } from "@wordpress/element";
import { Popover } from "@wordpress/components";
import { isRTL } from "@wordpress/i18n";
import { store as blockEditorStore } from "../../store";
import { useBlockElement } from "../block-list/use-block-props/use-block-refs";
import usePopoverScroll from "./use-popover-scroll";
import { jsx } from "react/jsx-runtime";
var MAX_POPOVER_RECOMPUTE_COUNTER = Number.MAX_SAFE_INTEGER;
function BlockPopoverInbetween({
previousClientId,
nextClientId,
children,
__unstablePopoverSlot,
__unstableContentRef,
operation = "insert",
nearestSide = "right",
...props
}) {
const [popoverRecomputeCounter, forcePopoverRecompute] = useReducer(
// Module is there to make sure that the counter doesn't overflow.
(s) => (s + 1) % MAX_POPOVER_RECOMPUTE_COUNTER,
0
);
const { orientation, rootClientId, isVisible } = useSelect(
(select) => {
const {
getBlockListSettings,
getBlockRootClientId,
isBlockVisible
} = select(blockEditorStore);
const _rootClientId = getBlockRootClientId(
previousClientId ?? nextClientId
);
return {
orientation: getBlockListSettings(_rootClientId)?.orientation || "vertical",
rootClientId: _rootClientId,
isVisible: isBlockVisible(previousClientId) && isBlockVisible(nextClientId)
};
},
[previousClientId, nextClientId]
);
const previousElement = useBlockElement(previousClientId);
const nextElement = useBlockElement(nextClientId);
const isVertical = orientation === "vertical";
const popoverAnchor = useMemo(() => {
if (
// popoverRecomputeCounter is by definition always equal or greater than 0.
// This check is only there to satisfy the correctness of the
// exhaustive-deps rule for the `useMemo` hook.
popoverRecomputeCounter < 0 || !previousElement && !nextElement || !isVisible
) {
return void 0;
}
const contextElement = operation === "group" ? nextElement || previousElement : previousElement || nextElement;
return {
contextElement,
getBoundingClientRect() {
const previousRect = previousElement ? previousElement.getBoundingClientRect() : null;
const nextRect = nextElement ? nextElement.getBoundingClientRect() : null;
let left = 0;
let top = 0;
let width = 0;
let height = 0;
if (operation === "group") {
const targetRect = nextRect || previousRect;
top = targetRect.top;
width = 0;
height = targetRect.bottom - targetRect.top;
left = nearestSide === "left" ? targetRect.left - 2 : targetRect.right - 2;
} else if (isVertical) {
top = previousRect ? previousRect.bottom : nextRect.top;
width = previousRect ? previousRect.width : nextRect.width;
height = nextRect && previousRect ? nextRect.top - previousRect.bottom : 0;
left = previousRect ? previousRect.left : nextRect.left;
} else {
top = previousRect ? previousRect.top : nextRect.top;
height = previousRect ? previousRect.height : nextRect.height;
if (isRTL()) {
left = nextRect ? nextRect.right : previousRect.left;
width = previousRect && nextRect ? previousRect.left - nextRect.right : 0;
} else {
left = previousRect ? previousRect.right : nextRect.left;
width = previousRect && nextRect ? nextRect.left - previousRect.right : 0;
}
width = Math.max(width, 0);
}
return new window.DOMRect(left, top, width, height);
}
};
}, [
previousElement,
nextElement,
popoverRecomputeCounter,
isVertical,
isVisible,
operation,
nearestSide
]);
const popoverScrollRef = usePopoverScroll(__unstableContentRef);
useLayoutEffect(() => {
if (!previousElement) {
return;
}
const observer = new window.MutationObserver(forcePopoverRecompute);
observer.observe(previousElement, { attributes: true });
return () => {
observer.disconnect();
};
}, [previousElement]);
useLayoutEffect(() => {
if (!nextElement) {
return;
}
const observer = new window.MutationObserver(forcePopoverRecompute);
observer.observe(nextElement, { attributes: true });
return () => {
observer.disconnect();
};
}, [nextElement]);
useLayoutEffect(() => {
if (!previousElement) {
return;
}
previousElement.ownerDocument.defaultView.addEventListener(
"resize",
forcePopoverRecompute
);
return () => {
previousElement.ownerDocument.defaultView?.removeEventListener(
"resize",
forcePopoverRecompute
);
};
}, [previousElement]);
if (!previousElement && !nextElement || !isVisible) {
return null;
}
return /* @__PURE__ */ jsx(
Popover,
{
ref: popoverScrollRef,
animate: false,
anchor: popoverAnchor,
focusOnMount: false,
__unstableSlotName: __unstablePopoverSlot,
inline: !__unstablePopoverSlot,
...props,
className: clsx(
"block-editor-block-popover",
"block-editor-block-popover__inbetween",
props.className
),
resize: false,
flip: false,
placement: "overlay",
variant: "unstyled",
children: /* @__PURE__ */ jsx("div", { className: "block-editor-block-popover__inbetween-container", children })
},
nextClientId + "--" + rootClientId
);
}
var inbetween_default = BlockPopoverInbetween;
export {
inbetween_default as default
};
//# sourceMappingURL=inbetween.js.map