UNPKG

@wordpress/block-editor

Version:
158 lines (157 loc) 5.27 kB
// packages/block-editor/src/components/provider/use-block-sync.js import { useEffect, useRef } from "@wordpress/element"; import { useRegistry, useSelect } from "@wordpress/data"; import { cloneBlock } from "@wordpress/blocks"; import { store as blockEditorStore } from "../../store"; var noop = () => { }; function useBlockSync({ clientId = null, value: controlledBlocks, selection: controlledSelection, onChange = noop, onInput = noop }) { const registry = useRegistry(); const { resetBlocks, resetSelection, replaceInnerBlocks, setHasControlledInnerBlocks, __unstableMarkNextChangeAsNotPersistent } = registry.dispatch(blockEditorStore); const { getBlockName, getBlocks, getSelectionStart, getSelectionEnd } = registry.select(blockEditorStore); const isControlled = useSelect( (select) => { return !clientId || select(blockEditorStore).areInnerBlocksControlled(clientId); }, [clientId] ); const pendingChangesRef = useRef({ incoming: null, outgoing: [] }); const subscribedRef = useRef(false); const setControlledBlocks = () => { if (!controlledBlocks) { return; } __unstableMarkNextChangeAsNotPersistent(); if (clientId) { registry.batch(() => { setHasControlledInnerBlocks(clientId, true); const storeBlocks = controlledBlocks.map( (block) => cloneBlock(block) ); if (subscribedRef.current) { pendingChangesRef.current.incoming = storeBlocks; } __unstableMarkNextChangeAsNotPersistent(); replaceInnerBlocks(clientId, storeBlocks); }); } else { if (subscribedRef.current) { pendingChangesRef.current.incoming = controlledBlocks; } resetBlocks(controlledBlocks); } }; const unsetControlledBlocks = () => { __unstableMarkNextChangeAsNotPersistent(); if (clientId) { setHasControlledInnerBlocks(clientId, false); __unstableMarkNextChangeAsNotPersistent(); replaceInnerBlocks(clientId, []); } else { resetBlocks([]); } }; const onInputRef = useRef(onInput); const onChangeRef = useRef(onChange); useEffect(() => { onInputRef.current = onInput; onChangeRef.current = onChange; }, [onInput, onChange]); useEffect(() => { if (pendingChangesRef.current.outgoing.includes(controlledBlocks)) { if (pendingChangesRef.current.outgoing[pendingChangesRef.current.outgoing.length - 1] === controlledBlocks) { pendingChangesRef.current.outgoing = []; } } else if (getBlocks(clientId) !== controlledBlocks) { pendingChangesRef.current.outgoing = []; setControlledBlocks(); if (controlledSelection) { resetSelection( controlledSelection.selectionStart, controlledSelection.selectionEnd, controlledSelection.initialPosition ); } } }, [controlledBlocks, clientId]); const isMountedRef = useRef(false); useEffect(() => { if (!isMountedRef.current) { isMountedRef.current = true; return; } if (!isControlled) { pendingChangesRef.current.outgoing = []; setControlledBlocks(); } }, [isControlled]); useEffect(() => { const { getSelectedBlocksInitialCaretPosition, isLastBlockChangePersistent, __unstableIsLastBlockChangeIgnored, areInnerBlocksControlled } = registry.select(blockEditorStore); let blocks = getBlocks(clientId); let isPersistent = isLastBlockChangePersistent(); let previousAreBlocksDifferent = false; subscribedRef.current = true; const unsubscribe = registry.subscribe(() => { if (clientId !== null && getBlockName(clientId) === null) { return; } const isStillControlled = !clientId || areInnerBlocksControlled(clientId); if (!isStillControlled) { return; } const newIsPersistent = isLastBlockChangePersistent(); const newBlocks = getBlocks(clientId); const areBlocksDifferent = newBlocks !== blocks; blocks = newBlocks; if (areBlocksDifferent && (pendingChangesRef.current.incoming || __unstableIsLastBlockChangeIgnored())) { pendingChangesRef.current.incoming = null; isPersistent = newIsPersistent; return; } const didPersistenceChange = previousAreBlocksDifferent && !areBlocksDifferent && newIsPersistent && !isPersistent; if (areBlocksDifferent || didPersistenceChange) { isPersistent = newIsPersistent; pendingChangesRef.current.outgoing.push(blocks); const updateParent = isPersistent ? onChangeRef.current : onInputRef.current; updateParent(blocks, { selection: { selectionStart: getSelectionStart(), selectionEnd: getSelectionEnd(), initialPosition: getSelectedBlocksInitialCaretPosition() } }); } previousAreBlocksDifferent = areBlocksDifferent; }, blockEditorStore); return () => { subscribedRef.current = false; unsubscribe(); }; }, [registry, clientId]); useEffect(() => { return () => { unsetControlledBlocks(); }; }, []); } export { useBlockSync as default }; //# sourceMappingURL=use-block-sync.js.map