UNPKG

@wordpress/block-editor

Version:
114 lines (110 loc) 4.05 kB
/** * External dependencies */ import clsx from 'clsx'; /** * WordPress dependencies */ import { useMergeRefs } from '@wordpress/compose'; import { Popover } from '@wordpress/components'; import { forwardRef, useMemo, useReducer, useLayoutEffect } from '@wordpress/element'; /** * Internal dependencies */ import { useBlockElement } from '../block-list/use-block-props/use-block-refs'; import usePopoverScroll from './use-popover-scroll'; import { rectUnion, getElementBounds } from '../../utils/dom'; import { jsx as _jsx } from "react/jsx-runtime"; const MAX_POPOVER_RECOMPUTE_COUNTER = Number.MAX_SAFE_INTEGER; function BlockPopover({ clientId, bottomClientId, children, __unstablePopoverSlot, __unstableContentRef, shift = true, ...props }, ref) { const selectedElement = useBlockElement(clientId); const lastSelectedElement = useBlockElement(bottomClientId !== null && bottomClientId !== void 0 ? bottomClientId : clientId); const mergedRefs = useMergeRefs([ref, usePopoverScroll(__unstableContentRef)]); const [popoverDimensionsRecomputeCounter, forceRecomputePopoverDimensions] = useReducer( // Module is there to make sure that the counter doesn't overflow. s => (s + 1) % MAX_POPOVER_RECOMPUTE_COUNTER, 0); // When blocks are moved up/down, they are animated to their new position by // updating the `transform` property manually (i.e. without using CSS // transitions or animations). The animation, which can also scroll the block // editor, can sometimes cause the position of the Popover to get out of sync. // A MutationObserver is therefore used to make sure that changes to the // selectedElement's attribute (i.e. `transform`) can be tracked and used to // trigger the Popover to rerender. useLayoutEffect(() => { if (!selectedElement) { return; } const observer = new window.MutationObserver(forceRecomputePopoverDimensions); observer.observe(selectedElement, { attributes: true }); return () => { observer.disconnect(); }; }, [selectedElement]); const popoverAnchor = useMemo(() => { if ( // popoverDimensionsRecomputeCounter 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. popoverDimensionsRecomputeCounter < 0 || !selectedElement || bottomClientId && !lastSelectedElement) { return undefined; } return { getBoundingClientRect() { return lastSelectedElement ? rectUnion(getElementBounds(selectedElement), getElementBounds(lastSelectedElement)) : getElementBounds(selectedElement); }, contextElement: selectedElement }; }, [popoverDimensionsRecomputeCounter, selectedElement, bottomClientId, lastSelectedElement]); if (!selectedElement || bottomClientId && !lastSelectedElement) { return null; } return /*#__PURE__*/_jsx(Popover, { ref: mergedRefs, animate: false, focusOnMount: false, anchor: popoverAnchor // Render in the old slot if needed for backward compatibility, // otherwise render in place (not in the default popover slot). , __unstableSlotName: __unstablePopoverSlot, inline: !__unstablePopoverSlot, placement: "top-start", resize: false, flip: false, shift: shift, ...props, className: clsx('block-editor-block-popover', props.className), variant: "unstyled", children: children }); } export const PrivateBlockPopover = forwardRef(BlockPopover); const PublicBlockPopover = ({ clientId, bottomClientId, children, ...props }, ref) => /*#__PURE__*/_jsx(PrivateBlockPopover, { ...props, bottomClientId: bottomClientId, clientId: clientId, __unstableContentRef: undefined, __unstablePopoverSlot: undefined, ref: ref, children: children }); /** * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/block-popover/README.md */ export default forwardRef(PublicBlockPopover); //# sourceMappingURL=index.js.map