UNPKG

@wordpress/block-editor

Version:
201 lines (200 loc) 6.39 kB
// 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