@wordpress/block-editor
Version:
201 lines (200 loc) • 6.39 kB
JavaScript
// packages/block-editor/src/components/grid/use-grid-layout-sync.js
import { useDispatch, useSelect } from "@wordpress/data";
import { useEffect, useMemo } from "@wordpress/element";
import { usePrevious } from "@wordpress/compose";
import { store as blockEditorStore } from "../../store";
import { GridRect } from "./utils";
import { setImmutably } from "../../utils/object";
function useGridLayoutSync({ clientId: gridClientId }) {
const { gridLayout, blockOrder, selectedBlockLayout } = useSelect(
(select) => {
const { getBlockAttributes: getBlockAttributes2, getBlockOrder } = select(blockEditorStore);
const selectedBlock = select(blockEditorStore).getSelectedBlock();
return {
gridLayout: getBlockAttributes2(gridClientId).layout ?? {},
blockOrder: getBlockOrder(gridClientId),
selectedBlockLayout: selectedBlock?.attributes.style?.layout
};
},
[gridClientId]
);
const { getBlockAttributes, getBlockRootClientId } = useSelect(blockEditorStore);
const { updateBlockAttributes, __unstableMarkNextChangeAsNotPersistent } = useDispatch(blockEditorStore);
const selectedBlockRect = useMemo(
() => selectedBlockLayout ? new GridRect(selectedBlockLayout) : null,
[selectedBlockLayout]
);
const previouslySelectedBlockRect = usePrevious(selectedBlockRect);
const previousIsManualPlacement = usePrevious(
gridLayout.isManualPlacement
);
const previousBlockOrder = usePrevious(blockOrder);
useEffect(() => {
const updates = {};
if (gridLayout.isManualPlacement) {
const occupiedRects = [];
for (const clientId of blockOrder) {
const {
columnStart,
rowStart,
columnSpan = 1,
rowSpan = 1
} = getBlockAttributes(clientId).style?.layout ?? {};
if (!columnStart || !rowStart) {
continue;
}
occupiedRects.push(
new GridRect({
columnStart,
rowStart,
columnSpan,
rowSpan
})
);
}
for (const clientId of blockOrder) {
const attributes = getBlockAttributes(clientId);
const {
columnStart,
rowStart,
columnSpan = 1,
rowSpan = 1
} = attributes.style?.layout ?? {};
if (columnStart && rowStart) {
continue;
}
const [newColumnStart, newRowStart] = placeBlock(
occupiedRects,
gridLayout.columnCount,
columnSpan,
rowSpan,
previouslySelectedBlockRect?.columnEnd,
previouslySelectedBlockRect?.rowEnd
);
occupiedRects.push(
new GridRect({
columnStart: newColumnStart,
rowStart: newRowStart,
columnSpan,
rowSpan
})
);
updates[clientId] = {
style: {
...attributes.style,
layout: {
...attributes.style?.layout,
columnStart: newColumnStart,
rowStart: newRowStart
}
}
};
}
const bottomMostRow = Math.max(
...occupiedRects.map((r) => r.rowEnd)
);
if (!gridLayout.rowCount || gridLayout.rowCount < bottomMostRow) {
updates[gridClientId] = {
layout: {
...gridLayout,
rowCount: bottomMostRow
}
};
}
for (const clientId of previousBlockOrder ?? []) {
if (!blockOrder.includes(clientId)) {
const rootClientId = getBlockRootClientId(clientId);
if (rootClientId === null) {
continue;
}
const rootAttributes = getBlockAttributes(rootClientId);
if (rootAttributes?.layout?.type === "grid") {
continue;
}
const attributes = getBlockAttributes(clientId);
const {
columnStart,
rowStart,
columnSpan,
rowSpan,
...layout
} = attributes.style?.layout ?? {};
if (columnStart || rowStart || columnSpan || rowSpan) {
const hasEmptyLayoutAttribute = Object.keys(layout).length === 0;
updates[clientId] = setImmutably(
attributes,
["style", "layout"],
hasEmptyLayoutAttribute ? void 0 : layout
);
}
}
}
} else {
if (previousIsManualPlacement === true) {
for (const clientId of blockOrder) {
const attributes = getBlockAttributes(clientId);
const { columnStart, rowStart, ...layout } = attributes.style?.layout ?? {};
if (columnStart || rowStart) {
const hasEmptyLayoutAttribute = Object.keys(layout).length === 0;
updates[clientId] = setImmutably(
attributes,
["style", "layout"],
hasEmptyLayoutAttribute ? void 0 : layout
);
}
}
}
if (gridLayout.rowCount) {
updates[gridClientId] = {
layout: {
...gridLayout,
rowCount: void 0
}
};
}
}
if (Object.keys(updates).length) {
__unstableMarkNextChangeAsNotPersistent();
updateBlockAttributes(
Object.keys(updates),
updates,
/* uniqueByBlock: */
true
);
}
}, [
// Actual deps to sync:
gridClientId,
gridLayout,
previousBlockOrder,
blockOrder,
previouslySelectedBlockRect,
previousIsManualPlacement,
// These won't change, but the linter thinks they might:
__unstableMarkNextChangeAsNotPersistent,
getBlockAttributes,
getBlockRootClientId,
updateBlockAttributes
]);
}
function placeBlock(occupiedRects, gridColumnCount, blockColumnSpan, blockRowSpan, startColumn = 1, startRow = 1) {
for (let row = startRow; ; row++) {
for (let column = row === startRow ? startColumn : 1; column <= gridColumnCount; column++) {
const candidateRect = new GridRect({
columnStart: column,
rowStart: row,
columnSpan: blockColumnSpan,
rowSpan: blockRowSpan
});
if (!occupiedRects.some(
(r) => r.intersectsRect(candidateRect)
)) {
return [column, row];
}
}
}
}
export {
useGridLayoutSync
};
//# sourceMappingURL=use-grid-layout-sync.js.map