"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// packages/block-editor/src/components/provider/use-block-sync.js
var use_block_sync_exports = {};
__export(use_block_sync_exports, {
  default: () => useBlockSync
});
module.exports = __toCommonJS(use_block_sync_exports);
var import_element = require("@wordpress/element");
var import_data = require("@wordpress/data");
var import_blocks = require("@wordpress/blocks");
var import_store = require("../../store/index.cjs");
var noop = () => {
};
function cloneBlockWithMapping(block, mapping) {
  const clonedBlock = (0, import_blocks.cloneBlock)(block);
  mapping.externalToInternal.set(block.clientId, clonedBlock.clientId);
  mapping.internalToExternal.set(clonedBlock.clientId, block.clientId);
  if (block.innerBlocks?.length) {
    clonedBlock.innerBlocks = block.innerBlocks.map((innerBlock) => {
      const clonedInner = cloneBlockWithMapping(innerBlock, mapping);
      return clonedInner;
    });
  }
  return clonedBlock;
}
function restoreExternalIds(blocks, mapping) {
  return blocks.map((block) => {
    const externalId = mapping.internalToExternal.get(block.clientId);
    return {
      ...block,
      // Use external ID if available, otherwise keep internal ID (for new blocks)
      clientId: externalId ?? block.clientId,
      innerBlocks: restoreExternalIds(block.innerBlocks, mapping)
    };
  });
}
function restoreSelectionIds(selection, mapping) {
  const { selectionStart, selectionEnd, initialPosition } = selection;
  const restoreClientId = (selectionState) => {
    if (!selectionState?.clientId) {
      return selectionState;
    }
    const externalId = mapping.internalToExternal.get(
      selectionState.clientId
    );
    return {
      ...selectionState,
      clientId: externalId ?? selectionState.clientId
    };
  };
  return {
    selectionStart: restoreClientId(selectionStart),
    selectionEnd: restoreClientId(selectionEnd),
    initialPosition
  };
}
function useBlockSync({
  clientId = null,
  value: controlledBlocks,
  selection: controlledSelection,
  onChange = noop,
  onInput = noop
}) {
  const registry = (0, import_data.useRegistry)();
  const {
    resetBlocks,
    resetSelection,
    replaceInnerBlocks,
    setHasControlledInnerBlocks,
    __unstableMarkNextChangeAsNotPersistent
  } = registry.dispatch(import_store.store);
  const { getBlockName, getBlocks, getSelectionStart, getSelectionEnd } = registry.select(import_store.store);
  const isControlled = (0, import_data.useSelect)(
    (select) => {
      return !clientId || select(import_store.store).areInnerBlocksControlled(clientId);
    },
    [clientId]
  );
  const pendingChangesRef = (0, import_element.useRef)({ incoming: null, outgoing: [] });
  const subscribedRef = (0, import_element.useRef)(false);
  const idMappingRef = (0, import_element.useRef)({
    externalToInternal: /* @__PURE__ */ new Map(),
    internalToExternal: /* @__PURE__ */ new Map()
  });
  const setControlledBlocks = () => {
    if (!controlledBlocks) {
      return;
    }
    __unstableMarkNextChangeAsNotPersistent();
    if (clientId) {
      registry.batch(() => {
        setHasControlledInnerBlocks(clientId, true);
        idMappingRef.current.externalToInternal.clear();
        idMappingRef.current.internalToExternal.clear();
        const storeBlocks = controlledBlocks.map(
          (block) => cloneBlockWithMapping(block, idMappingRef.current)
        );
        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 = (0, import_element.useRef)(onInput);
  const onChangeRef = (0, import_element.useRef)(onChange);
  (0, import_element.useEffect)(() => {
    onInputRef.current = onInput;
    onChangeRef.current = onChange;
  }, [onInput, onChange]);
  (0, import_element.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 = (0, import_element.useRef)(false);
  (0, import_element.useEffect)(() => {
    if (!isMountedRef.current) {
      isMountedRef.current = true;
      return;
    }
    if (!isControlled) {
      pendingChangesRef.current.outgoing = [];
      setControlledBlocks();
    }
  }, [isControlled]);
  (0, import_element.useEffect)(() => {
    const {
      getSelectedBlocksInitialCaretPosition,
      isLastBlockChangePersistent,
      __unstableIsLastBlockChangeIgnored,
      areInnerBlocksControlled
    } = registry.select(import_store.store);
    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;
        const blocksForParent = clientId ? restoreExternalIds(blocks, idMappingRef.current) : blocks;
        const selection = {
          selectionStart: getSelectionStart(),
          selectionEnd: getSelectionEnd(),
          initialPosition: getSelectedBlocksInitialCaretPosition()
        };
        const selectionForParent = clientId ? restoreSelectionIds(selection, idMappingRef.current) : selection;
        pendingChangesRef.current.outgoing.push(blocksForParent);
        const updateParent = isPersistent ? onChangeRef.current : onInputRef.current;
        updateParent(blocksForParent, {
          selection: selectionForParent
        });
      }
      previousAreBlocksDifferent = areBlocksDifferent;
    }, import_store.store);
    return () => {
      subscribedRef.current = false;
      unsubscribe();
    };
  }, [registry, clientId]);
  (0, import_element.useEffect)(() => {
    return () => {
      unsetControlledBlocks();
    };
  }, []);
}
//# sourceMappingURL=use-block-sync.cjs.map
