: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
function GridItemResizerInner({
const [resizeDirection, setResizeDirection] = (0,external_wp_element_namespaceObject.useState)(null);
const [enableSide, setEnableSide] = (0,external_wp_element_namespaceObject.useState)({
(0,external_wp_element_namespaceObject.useEffect)(() => {
const observer = new window.ResizeObserver(() => {
const blockClientRect = blockElement.getBoundingClientRect();
const rootBlockClientRect = rootBlockElement.getBoundingClientRect();
top: blockClientRect.top > rootBlockClientRect.top,
bottom: blockClientRect.bottom < rootBlockClientRect.bottom,
left: blockClientRect.left > rootBlockClientRect.left,
right: blockClientRect.right < rootBlockClientRect.right
observer.observe(blockElement);
return () => observer.disconnect();
}, [blockElement, rootBlockElement]);
justifyContent: 'center',
...(justification[resizeDirection] && {
justifyContent: justification[resizeDirection]
...(alignment[resizeDirection] && {
alignItems: alignment[resizeDirection]
return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(cover, {
className: "block-editor-grid-item-resizer",
__unstablePopoverSlot: "block-toolbar",
additionalStyles: styles,
children: /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.ResizableBox, {
className: "block-editor-grid-item-resizer__box",
bottom: enableSide.bottom,
onResizeStart: (event, direction) => {
* The container justification and alignment need to be set
* according to the direction the resizer is being dragged in,
* so that it resizes in the right direction.
setResizeDirection(direction);
* The mouseup event on the resize handle doesn't trigger if the mouse
* isn't directly above the handle, so we try to detect if it happens
* outside the grid and dispatch a mouseup event on the handle.
blockElement.ownerDocument.addEventListener('mouseup', () => {
event.target.dispatchEvent(new Event('mouseup', {
onResizeStop: (event, direction, boxElement) => {
const columnGap = parseFloat(getComputedCSS(rootBlockElement, 'column-gap'));
const rowGap = parseFloat(getComputedCSS(rootBlockElement, 'row-gap'));
const gridColumnTracks = getGridTracks(getComputedCSS(rootBlockElement, 'grid-template-columns'), columnGap);
const gridRowTracks = getGridTracks(getComputedCSS(rootBlockElement, 'grid-template-rows'), rowGap);
const rect = new window.DOMRect(blockElement.offsetLeft + boxElement.offsetLeft, blockElement.offsetTop + boxElement.offsetTop, boxElement.offsetWidth, boxElement.offsetHeight);
const columnStart = getClosestTrack(gridColumnTracks, rect.left) + 1;
const rowStart = getClosestTrack(gridRowTracks, rect.top) + 1;
const columnEnd = getClosestTrack(gridColumnTracks, rect.right, 'end') + 1;
const rowEnd = getClosestTrack(gridRowTracks, rect.bottom, 'end') + 1;
columnSpan: columnEnd - columnStart + 1,
rowSpan: rowEnd - rowStart + 1
* Given a grid-template-columns or grid-template-rows CSS property value, gets the start and end
* position in pixels of each grid track.
* https://css-tricks.com/snippets/css/complete-guide-grid/#aa-grid-track
* @param {string} template The grid-template-columns or grid-template-rows CSS property value.
* Only supports fixed sizes in pixels.
* @param {number} gap The gap between grid tracks in pixels.
* @return {Array<{start: number, end: number}>} An array of objects with the start and end
* position in pixels of each grid track.
function getGridTracks(template, gap) {
for (const size of template.split(' ')) {
const previousTrack = tracks[tracks.length - 1];
const start = previousTrack ? previousTrack.end + gap : 0;
const end = start + parseFloat(size);
* Given an array of grid tracks and a position in pixels, gets the index of the closest track to
* https://css-tricks.com/snippets/css/complete-guide-grid/#aa-grid-track
* @param {Array<{start: number, end: number}>} tracks An array of objects with the start and end
* position in pixels of each grid track.
* @param {number} position The position in pixels.
* @param {string} edge The edge of the track to compare the
* position to. Either 'start' or 'end'.
* @return {number} The index of the closest track to the position. 0-based, unlike CSS grid which
function getClosestTrack(tracks, position, edge = 'start') {
return tracks.reduce((closest, track, index) => Math.abs(track[edge] - position) < Math.abs(tracks[closest][edge] - position) ? index : closest, 0);
;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/hooks/layout-child.js
function useBlockPropsChildLayoutStyles({
const shouldRenderChildLayoutStyles = (0,external_wp_data_namespaceObject.useSelect)(select => {
return !select(store).getSettings().disableLayoutStyles;
const layout = (_style$layout = style?.layout) !== null && _style$layout !== void 0 ? _style$layout : {};
const parentLayout = useLayout() || {};
const id = (0,external_wp_compose_namespaceObject.useInstanceId)(useBlockPropsChildLayoutStyles);
const selector = `.wp-container-content-${id}`;
if (shouldRenderChildLayoutStyles) {
if (selfStretch === 'fixed' && flexSize) {
} else if (selfStretch === 'fill') {
} else if (columnStart && columnSpan) {
grid-column: ${columnStart} / span ${columnSpan};
} else if (columnStart) {
grid-column: ${columnStart};
grid-column: span ${columnSpan};
* If minimumColumnWidth is set on the parent, or if no
* columnCount is set, the grid is responsive so a
* container query is needed for the span to resize.
if ((columnSpan || columnStart) && (minimumColumnWidth || !columnCount)) {
// Check if columnSpan and columnStart are numbers so Math.max doesn't break.
const columnSpanNumber = columnSpan ? parseInt(columnSpan) : null;
const columnStartNumber = columnStart ? parseInt(columnStart) : null;
const highestNumber = Math.max(columnSpanNumber, columnStartNumber);
let parentColumnValue = parseFloat(minimumColumnWidth);
* 12rem is the default minimumColumnWidth value.
* If parentColumnValue is not a number, default to 12.
if (isNaN(parentColumnValue)) {
let parentColumnUnit = minimumColumnWidth?.replace(parentColumnValue, '');
* Check that parent column unit is either 'px', 'rem' or 'em'.
* If not, default to 'rem'.
if (!['px', 'rem', 'em'].includes(parentColumnUnit)) {
parentColumnUnit = 'rem';
const defaultGapValue = parentColumnUnit === 'px' ? 24 : 1.5;
const containerQueryValue = highestNumber * parentColumnValue + (highestNumber - 1) * defaultGapValue;
// If a span is set we want to preserve it as long as possible, otherwise we just reset the value.
const gridColumnValue = columnSpan ? '1/-1' : 'auto';
css += `@container (max-width: ${containerQueryValue}${parentColumnUnit}) {
grid-column: ${gridColumnValue};
if (rowStart && rowSpan) {
grid-row: ${rowStart} / span ${rowSpan};
grid-row: span ${rowSpan};
// Only attach a container class if there is generated CSS to be attached.
// Attach a `wp-container-content` id-based classname.
className: `wp-container-content-${id}`
function ChildLayoutControlsPure({
type: parentLayoutType = 'default',
allowSizingOnChildren = false
const rootClientId = (0,external_wp_data_namespaceObject.useSelect)(select => {
return select(store).getBlockRootClientId(clientId);
// Use useState() instead of useRef() so that GridItemResizer updates when ref is set.
const [resizerBounds, setResizerBounds] = (0,external_wp_element_namespaceObject.useState)();
if (parentLayoutType !== 'grid') {
return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_ReactJSXRuntime_namespaceObject.Fragment, {
children: [/*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(GridVisualizer, {
contentRef: setResizerBounds
}), allowSizingOnChildren && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(GridItemResizer, {
// Don't allow resizing beyond the grid visualizer.
/* harmony default export */ const layout_child = ({
useBlockProps: useBlockPropsChildLayoutStyles,
edit: ChildLayoutControlsPure,
attributeKeys: ['style'],
;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/convert-to-group-buttons/use-convert-to-group-button-props.js
* Contains the properties `ConvertToGroupButton` component needs.
* @typedef {Object} ConvertToGroupButtonProps
* @property {string[]} clientIds An array of the selected client ids.
* @property {boolean} isGroupable Indicates if the selected blocks can be grouped.
* @property {boolean} isUngroupable Indicates if the selected blocks can be ungrouped.
* @property {WPBlock[]} blocksSelection An array of the selected blocks.
* @property {string} groupingBlockName The name of block used for handling grouping interactions.
* Returns the properties `ConvertToGroupButton` component needs to work properly.
* It is used in `BlockSettingsMenuControls` to know if `ConvertToGroupButton`
* should be rendered, to avoid ending up with an empty MenuGroup.
* @param {?string[]} selectedClientIds An optional array of clientIds to group. The selected blocks
* from the block editor store are used if this is not provided.
* @return {ConvertToGroupButtonProps} Returns the properties needed by `ConvertToGroupButton`.
function useConvertToGroupButtonProps(selectedClientIds) {
return (0,external_wp_data_namespaceObject.useSelect)(select => {
getSelectedBlockClientIds,
} = select(external_wp_blocks_namespaceObject.store);
const clientIds = selectedClientIds?.length ? selectedClientIds : getSelectedBlockClientIds();
const blocksSelection = getBlocksByClientId(clientIds);
const [firstSelectedBlock] = blocksSelection;
const _isUngroupable = clientIds.length === 1 && isUngroupable(clientIds[0]);
isGroupable: isGroupable(clientIds),
isUngroupable: _isUngroupable,
groupingBlockName: getGroupingBlockName(),
onUngroup: _isUngroupable && getBlockType(firstSelectedBlock.name)?.transforms?.ungroup
;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/convert-to-group-buttons/index.js
function ConvertToGroupButton({
getSelectedBlockClientIds
} = (0,external_wp_data_namespaceObject.useSelect)(store);
} = (0,external_wp_data_namespaceObject.useDispatch)(store);
const onConvertToGroup = () => {
// Activate the `transform` on the Grouping Block which does the conversion.
const newBlocks = (0,external_wp_blocks_namespaceObject.switchToBlockType)(blocksSelection, groupingBlockName);
replaceBlocks(clientIds, newBlocks);
const onConvertFromGroup = () => {
let innerBlocks = blocksSelection[0].innerBlocks;
if (!innerBlocks.length) {
innerBlocks = onUngroup(blocksSelection[0].attributes, blocksSelection[0].innerBlocks);
replaceBlocks(clientIds, innerBlocks);
if (!isGroupable && !isUngroupable) {
const selectedBlockClientIds = getSelectedBlockClientIds();
return /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsxs)(external_ReactJSXRuntime_namespaceObject.Fragment, {
children: [isGroupable && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.MenuItem, {
shortcut: selectedBlockClientIds.length > 1 ? external_wp_keycodes_namespaceObject.displayShortcut.primary('g') : undefined,
children: (0,external_wp_i18n_namespaceObject._x)('Group', 'verb')
}), isUngroupable && /*#__PURE__*/(0,external_ReactJSXRuntime_namespaceObject.jsx)(external_wp_components_namespaceObject.MenuItem, {
children: (0,external_wp_i18n_namespaceObject._x)('Ungroup', 'Ungrouping blocks from within a grouping block back into individual blocks within the Editor ')
;// CONCATENATED MODULE: ./node_modules/@wordpress/block-editor/build-module/components/block-lock/use-block-lock.js
* Return details about the block lock status.
* @param {string} clientId The block client Id.
* @return {Object} Block lock status
function useBlockLock(clientId) {
return (0,external_wp_data_namespaceObject.useSelect)(select => {