// 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
