UNPKG

@wordpress/block-editor

Version:
145 lines (121 loc) 5.96 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _element = require("@wordpress/element"); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _classnames = _interopRequireDefault(require("classnames")); var _compose = require("@wordpress/compose"); var _components = require("@wordpress/components"); var _useBlockRefs = require("../block-list/use-block-props/use-block-refs"); var _usePopoverScroll = _interopRequireDefault(require("./use-popover-scroll")); /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ const MAX_POPOVER_RECOMPUTE_COUNTER = Number.MAX_SAFE_INTEGER; function BlockPopover({ clientId, bottomClientId, children, __unstableRefreshSize, __unstableCoverTarget = false, __unstablePopoverSlot, __unstableContentRef, shift = true, ...props }, ref) { const selectedElement = (0, _useBlockRefs.__unstableUseBlockElement)(clientId); const lastSelectedElement = (0, _useBlockRefs.__unstableUseBlockElement)(bottomClientId !== null && bottomClientId !== void 0 ? bottomClientId : clientId); const mergedRefs = (0, _compose.useMergeRefs)([ref, (0, _usePopoverScroll.default)(__unstableContentRef)]); const [popoverDimensionsRecomputeCounter, forceRecomputePopoverDimensions] = (0, _element.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. (0, _element.useLayoutEffect)(() => { if (!selectedElement) { return; } const observer = new window.MutationObserver(forceRecomputePopoverDimensions); observer.observe(selectedElement, { attributes: true }); return () => { observer.disconnect(); }; }, [selectedElement]); const style = (0, _element.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 || lastSelectedElement !== selectedElement) { return {}; } return { position: 'absolute', width: selectedElement.offsetWidth, height: selectedElement.offsetHeight }; }, [selectedElement, lastSelectedElement, __unstableRefreshSize, popoverDimensionsRecomputeCounter]); const popoverAnchor = (0, _element.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() { var _lastSelectedBCR$left, _lastSelectedBCR$top, _lastSelectedBCR$righ, _lastSelectedBCR$bott; const selectedBCR = selectedElement.getBoundingClientRect(); const lastSelectedBCR = lastSelectedElement?.getBoundingClientRect(); // Get the biggest rectangle that encompasses completely the currently // selected element and the last selected element: // - for top/left coordinates, use the smaller numbers // - for the bottom/right coordinates, use the largest numbers const left = Math.min(selectedBCR.left, (_lastSelectedBCR$left = lastSelectedBCR?.left) !== null && _lastSelectedBCR$left !== void 0 ? _lastSelectedBCR$left : Infinity); const top = Math.min(selectedBCR.top, (_lastSelectedBCR$top = lastSelectedBCR?.top) !== null && _lastSelectedBCR$top !== void 0 ? _lastSelectedBCR$top : Infinity); const right = Math.max(selectedBCR.right, (_lastSelectedBCR$righ = lastSelectedBCR.right) !== null && _lastSelectedBCR$righ !== void 0 ? _lastSelectedBCR$righ : -Infinity); const bottom = Math.max(selectedBCR.bottom, (_lastSelectedBCR$bott = lastSelectedBCR.bottom) !== null && _lastSelectedBCR$bott !== void 0 ? _lastSelectedBCR$bott : -Infinity); const width = right - left; const height = bottom - top; return new window.DOMRect(left, top, width, height); }, ownerDocument: selectedElement.ownerDocument }; }, [bottomClientId, lastSelectedElement, selectedElement, popoverDimensionsRecomputeCounter]); if (!selectedElement || bottomClientId && !lastSelectedElement) { return null; } return (0, _element.createElement)(_components.Popover, (0, _extends2.default)({ 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 || null, placement: "top-start", resize: false, flip: false, shift: shift }, props, { className: (0, _classnames.default)('block-editor-block-popover', props.className), variant: "unstyled" }), __unstableCoverTarget && (0, _element.createElement)("div", { style: style }, children), !__unstableCoverTarget && children); } var _default = (0, _element.forwardRef)(BlockPopover); exports.default = _default; //# sourceMappingURL=index.js.map