"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
var _data = require("@wordpress/data");
var _blocks = require("@wordpress/blocks");
var _i18n = require("@wordpress/i18n");
var _a11y = require("@wordpress/a11y");
var _element = require("@wordpress/element");
var _store = require("../../../store");
var _lockUnlock = require("../../../lock-unlock");
/**
 * WordPress dependencies
 */

/**
 * Internal dependencies
 */

function getIndex({
  destinationRootClientId,
  destinationIndex,
  rootClientId,
  registry
}) {
  if (rootClientId === destinationRootClientId) {
    return destinationIndex;
  }
  const parents = ['', ...registry.select(_store.store).getBlockParents(destinationRootClientId), destinationRootClientId];
  const parentIndex = parents.indexOf(rootClientId);
  if (parentIndex !== -1) {
    return registry.select(_store.store).getBlockIndex(parents[parentIndex + 1]) + 1;
  }
  return registry.select(_store.store).getBlockOrder(rootClientId).length;
}

/**
 * @typedef WPInserterConfig
 *
 * @property {string=}   rootClientId   If set, insertion will be into the
 *                                      block with this ID.
 * @property {number=}   insertionIndex If set, insertion will be into this
 *                                      explicit position.
 * @property {string=}   clientId       If set, insertion will be after the
 *                                      block with this ID.
 * @property {boolean=}  isAppender     Whether the inserter is an appender
 *                                      or not.
 * @property {Function=} onSelect       Called after insertion.
 */

/**
 * Returns the insertion point state given the inserter config.
 *
 * @param {WPInserterConfig} config Inserter Config.
 * @return {Array} Insertion Point State (rootClientID, onInsertBlocks and onToggle).
 */
function useInsertionPoint({
  rootClientId = '',
  insertionIndex,
  clientId,
  isAppender,
  onSelect,
  shouldFocusBlock = true,
  selectBlockOnInsert = true
}) {
  const registry = (0, _data.useRegistry)();
  const {
    getSelectedBlock
  } = (0, _data.useSelect)(_store.store);
  const {
    destinationRootClientId,
    destinationIndex
  } = (0, _data.useSelect)(select => {
    const {
      getSelectedBlockClientId,
      getBlockRootClientId,
      getBlockIndex,
      getBlockOrder,
      getSectionRootClientId,
      __unstableGetEditorMode
    } = (0, _lockUnlock.unlock)(select(_store.store));
    const selectedBlockClientId = getSelectedBlockClientId();
    let _destinationRootClientId = rootClientId;
    let _destinationIndex;
    if (insertionIndex !== undefined) {
      // Insert into a specific index.
      _destinationIndex = insertionIndex;
    } else if (clientId) {
      // Insert after a specific client ID.
      _destinationIndex = getBlockIndex(clientId);
    } else if (!isAppender && selectedBlockClientId) {
      const sectionRootClientId = getSectionRootClientId();

      // Avoids empty inserter when the selected block is acting
      // as the "root".
      // See https://github.com/WordPress/gutenberg/pull/66214.
      if (__unstableGetEditorMode() === 'zoom-out' && sectionRootClientId === selectedBlockClientId) {
        _destinationRootClientId = sectionRootClientId;
        _destinationIndex = getBlockOrder(_destinationRootClientId).length;
      } else {
        _destinationRootClientId = getBlockRootClientId(selectedBlockClientId);
        _destinationIndex = getBlockIndex(selectedBlockClientId) + 1;
      }
    } else {
      // Insert at the end of the list.
      _destinationIndex = getBlockOrder(_destinationRootClientId).length;
    }
    return {
      destinationRootClientId: _destinationRootClientId,
      destinationIndex: _destinationIndex
    };
  }, [rootClientId, insertionIndex, clientId, isAppender]);
  const {
    replaceBlocks,
    insertBlocks,
    showInsertionPoint,
    hideInsertionPoint,
    setLastFocus
  } = (0, _lockUnlock.unlock)((0, _data.useDispatch)(_store.store));
  const onInsertBlocks = (0, _element.useCallback)((blocks, meta, shouldForceFocusBlock = false, _rootClientId) => {
    // When we are trying to move focus or select a new block on insert, we also
    // need to clear the last focus to avoid the focus being set to the wrong block
    // when tabbing back into the canvas if the block was added from outside the
    // editor canvas.
    if (shouldForceFocusBlock || shouldFocusBlock || selectBlockOnInsert) {
      setLastFocus(null);
    }
    const selectedBlock = getSelectedBlock();
    if (!isAppender && selectedBlock && (0, _blocks.isUnmodifiedDefaultBlock)(selectedBlock)) {
      replaceBlocks(selectedBlock.clientId, blocks, null, shouldFocusBlock || shouldForceFocusBlock ? 0 : null, meta);
    } else {
      insertBlocks(blocks, isAppender || _rootClientId === undefined ? destinationIndex : getIndex({
        destinationRootClientId,
        destinationIndex,
        rootClientId: _rootClientId,
        registry
      }), isAppender || _rootClientId === undefined ? destinationRootClientId : _rootClientId, selectBlockOnInsert, shouldFocusBlock || shouldForceFocusBlock ? 0 : null, meta);
    }
    const blockLength = Array.isArray(blocks) ? blocks.length : 1;
    const message = (0, _i18n.sprintf)(
    // translators: %d: the name of the block that has been added
    (0, _i18n._n)('%d block added.', '%d blocks added.', blockLength), blockLength);
    (0, _a11y.speak)(message);
    if (onSelect) {
      onSelect(blocks);
    }
  }, [isAppender, getSelectedBlock, replaceBlocks, insertBlocks, destinationRootClientId, destinationIndex, onSelect, shouldFocusBlock, selectBlockOnInsert]);
  const onToggleInsertionPoint = (0, _element.useCallback)(item => {
    if (item?.hasOwnProperty('rootClientId')) {
      showInsertionPoint(item.rootClientId, getIndex({
        destinationRootClientId,
        destinationIndex,
        rootClientId: item.rootClientId,
        registry
      }));
    } else {
      hideInsertionPoint();
    }
  }, [showInsertionPoint, hideInsertionPoint, destinationRootClientId, destinationIndex]);
  return [destinationRootClientId, onInsertBlocks, onToggleInsertionPoint];
}
var _default = exports.default = useInsertionPoint;
//# sourceMappingURL=use-insertion-point.js.map