"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.__experimentalGetTemplateInfo = exports.__experimentalGetDefaultTemplateTypes = exports.__experimentalGetDefaultTemplateType = exports.__experimentalGetDefaultTemplatePartAreas = void 0;
exports.__unstableIsEditorReady = __unstableIsEditorReady;
exports.canInsertBlockType = void 0;
exports.canUserUseUnfilteredHTML = canUserUseUnfilteredHTML;
exports.didPostSaveRequestSucceed = exports.didPostSaveRequestFail = void 0;
exports.getActivePostLock = getActivePostLock;
exports.getCurrentPost = exports.getClientIdsWithDescendants = exports.getClientIdsOfDescendants = exports.getBlocksByClientId = exports.getBlocks = exports.getBlockSelectionStart = exports.getBlockSelectionEnd = exports.getBlockRootClientId = exports.getBlockOrder = exports.getBlockName = exports.getBlockMode = exports.getBlockListSettings = exports.getBlockInsertionPoint = exports.getBlockIndex = exports.getBlockHierarchyRootClientId = exports.getBlockCount = exports.getBlockAttributes = exports.getBlock = exports.getAutosaveAttribute = exports.getAdjacentBlockClientId = void 0;
exports.getCurrentPostAttribute = getCurrentPostAttribute;
exports.getCurrentPostId = getCurrentPostId;
exports.getCurrentPostLastRevisionId = getCurrentPostLastRevisionId;
exports.getCurrentPostRevisionsCount = getCurrentPostRevisionsCount;
exports.getCurrentPostType = getCurrentPostType;
exports.getCurrentTemplateId = getCurrentTemplateId;
exports.getDeviceType = void 0;
exports.getEditedPostAttribute = getEditedPostAttribute;
exports.getEditedPostContent = void 0;
exports.getEditedPostPreviewLink = getEditedPostPreviewLink;
exports.getEditedPostSlug = getEditedPostSlug;
exports.getEditedPostVisibility = getEditedPostVisibility;
exports.getEditorMode = exports.getEditorBlocks = void 0;
exports.getEditorSelection = getEditorSelection;
exports.getEditorSelectionEnd = getEditorSelectionEnd;
exports.getEditorSelectionStart = getEditorSelectionStart;
exports.getEditorSettings = getEditorSettings;
exports.getNextBlockClientId = exports.getMultiSelectedBlocksStartClientId = exports.getMultiSelectedBlocksEndClientId = exports.getMultiSelectedBlocks = exports.getMultiSelectedBlockClientIds = exports.getLastMultiSelectedBlockClientId = exports.getInserterItems = exports.getGlobalBlockCount = exports.getFirstMultiSelectedBlockClientId = void 0;
exports.getPermalink = getPermalink;
exports.getPermalinkParts = getPermalinkParts;
exports.getPostEdits = void 0;
exports.getPostLockUser = getPostLockUser;
exports.getPreviousBlockClientId = exports.getPostTypeLabel = void 0;
exports.getRenderingMode = getRenderingMode;
exports.getSelectedBlocksInitialCaretPosition = exports.getSelectedBlockCount = exports.getSelectedBlockClientId = exports.getSelectedBlock = void 0;
exports.getStateBeforeOptimisticTransaction = getStateBeforeOptimisticTransaction;
exports.getTemplateLock = exports.getTemplate = exports.getSuggestedPostFormat = void 0;
exports.hasChangedContent = hasChangedContent;
exports.hasSelectedInnerBlock = exports.hasSelectedBlock = exports.hasNonPostEntityChanges = exports.hasMultiSelection = exports.hasInserterItems = exports.hasEditorUndo = exports.hasEditorRedo = void 0;
exports.inSomeHistory = inSomeHistory;
exports.isAncestorMultiSelected = void 0;
exports.isAutosavingPost = isAutosavingPost;
exports.isCaretWithinFormattedText = exports.isBlockWithinSelection = exports.isBlockValid = exports.isBlockSelected = exports.isBlockMultiSelected = exports.isBlockInsertionPointVisible = void 0;
exports.isCleanNewPost = isCleanNewPost;
exports.isCurrentPostPending = isCurrentPostPending;
exports.isCurrentPostPublished = isCurrentPostPublished;
exports.isCurrentPostScheduled = isCurrentPostScheduled;
exports.isDeletingPost = isDeletingPost;
exports.isEditedPostAutosaveable = void 0;
exports.isEditedPostBeingScheduled = isEditedPostBeingScheduled;
exports.isEditedPostDateFloating = isEditedPostDateFloating;
exports.isEditedPostEmpty = exports.isEditedPostDirty = void 0;
exports.isEditedPostNew = isEditedPostNew;
exports.isEditedPostPublishable = isEditedPostPublishable;
exports.isEditedPostSaveable = isEditedPostSaveable;
exports.isEditorPanelOpened = exports.isEditorPanelEnabled = void 0;
exports.isEditorPanelRemoved = isEditorPanelRemoved;
exports.isFirstMultiSelectedBlock = void 0;
exports.isInserterOpened = isInserterOpened;
exports.isListViewOpened = isListViewOpened;
exports.isMultiSelecting = void 0;
exports.isPermalinkEditable = isPermalinkEditable;
exports.isPostAutosavingLocked = isPostAutosavingLocked;
exports.isPostLockTakeover = isPostLockTakeover;
exports.isPostLocked = isPostLocked;
exports.isPostSavingLocked = isPostSavingLocked;
exports.isPreviewingPost = isPreviewingPost;
exports.isPublishSidebarEnabled = void 0;
exports.isPublishSidebarOpened = isPublishSidebarOpened;
exports.isPublishingPost = isPublishingPost;
exports.isSavingNonPostEntityChanges = void 0;
exports.isSavingPost = isSavingPost;
exports.isValidTemplate = exports.isTyping = exports.isSelectionEnabled = void 0;
var _blocks = require("@wordpress/blocks");
var _date = require("@wordpress/date");
var _url = require("@wordpress/url");
var _data = require("@wordpress/data");
var _deprecated = _interopRequireDefault(require("@wordpress/deprecated"));
var _element = require("@wordpress/element");
var _blockEditor = require("@wordpress/block-editor");
var _coreData = require("@wordpress/core-data");
var _preferences = require("@wordpress/preferences");
var _constants = require("./constants");
var _reducer = require("./reducer");
var _getTemplatePartIcon = require("../utils/get-template-part-icon");
var _lockUnlock = require("../lock-unlock");
var _getTemplateInfo = require("../utils/get-template-info");
/**
 * WordPress dependencies
 */

/**
 * Internal dependencies
 */

/**
 * Shared reference to an empty object for cases where it is important to avoid
 * returning a new object reference on every invocation, as in a connected or
 * other pure component which performs `shouldComponentUpdate` check on props.
 * This should be used as a last resort, since the normalized data should be
 * maintained by the reducer result in state.
 */
const EMPTY_OBJECT = {};

/**
 * Returns true if any past editor history snapshots exist, or false otherwise.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether undo history exists.
 */
const hasEditorUndo = exports.hasEditorUndo = (0, _data.createRegistrySelector)(select => () => {
  return select(_coreData.store).hasUndo();
});

/**
 * Returns true if any future editor history snapshots exist, or false
 * otherwise.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether redo history exists.
 */
const hasEditorRedo = exports.hasEditorRedo = (0, _data.createRegistrySelector)(select => () => {
  return select(_coreData.store).hasRedo();
});

/**
 * Returns true if the currently edited post is yet to be saved, or false if
 * the post has been saved.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether the post is new.
 */
function isEditedPostNew(state) {
  return getCurrentPost(state).status === 'auto-draft';
}

/**
 * Returns true if content includes unsaved changes, or false otherwise.
 *
 * @param {Object} state Editor state.
 *
 * @return {boolean} Whether content includes unsaved changes.
 */
function hasChangedContent(state) {
  const edits = getPostEdits(state);
  return 'content' in edits;
}

/**
 * Returns true if there are unsaved values for the current edit session, or
 * false if the editing state matches the saved or new post.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether unsaved values exist.
 */
const isEditedPostDirty = exports.isEditedPostDirty = (0, _data.createRegistrySelector)(select => state => {
  // Edits should contain only fields which differ from the saved post (reset
  // at initial load and save complete). Thus, a non-empty edits state can be
  // inferred to contain unsaved values.
  const postType = getCurrentPostType(state);
  const postId = getCurrentPostId(state);
  return select(_coreData.store).hasEditsForEntityRecord('postType', postType, postId);
});

/**
 * Returns true if there are unsaved edits for entities other than
 * the editor's post, and false otherwise.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether there are edits or not.
 */
const hasNonPostEntityChanges = exports.hasNonPostEntityChanges = (0, _data.createRegistrySelector)(select => state => {
  const dirtyEntityRecords = select(_coreData.store).__experimentalGetDirtyEntityRecords();
  const {
    type,
    id
  } = getCurrentPost(state);
  return dirtyEntityRecords.some(entityRecord => entityRecord.kind !== 'postType' || entityRecord.name !== type || entityRecord.key !== id);
});

/**
 * Returns true if there are no unsaved values for the current edit session and
 * if the currently edited post is new (has never been saved before).
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether new post and unsaved values exist.
 */
function isCleanNewPost(state) {
  return !isEditedPostDirty(state) && isEditedPostNew(state);
}

/**
 * Returns the post currently being edited in its last known saved state, not
 * including unsaved edits. Returns an object containing relevant default post
 * values if the post has not yet been saved.
 *
 * @param {Object} state Global application state.
 *
 * @return {Object} Post object.
 */
const getCurrentPost = exports.getCurrentPost = (0, _data.createRegistrySelector)(select => state => {
  const postId = getCurrentPostId(state);
  const postType = getCurrentPostType(state);
  const post = select(_coreData.store).getRawEntityRecord('postType', postType, postId);
  if (post) {
    return post;
  }

  // This exists for compatibility with the previous selector behavior
  // which would guarantee an object return based on the editor reducer's
  // default empty object state.
  return EMPTY_OBJECT;
});

/**
 * Returns the post type of the post currently being edited.
 *
 * @param {Object} state Global application state.
 *
 * @example
 *
 *```js
 * const currentPostType = wp.data.select( 'core/editor' ).getCurrentPostType();
 *```
 * @return {string} Post type.
 */
function getCurrentPostType(state) {
  return state.postType;
}

/**
 * Returns the ID of the post currently being edited, or null if the post has
 * not yet been saved.
 *
 * @param {Object} state Global application state.
 *
 * @return {?number} ID of current post.
 */
function getCurrentPostId(state) {
  return state.postId;
}

/**
 * Returns the template ID currently being rendered/edited
 *
 * @param {Object} state Global application state.
 *
 * @return {?string} Template ID.
 */
function getCurrentTemplateId(state) {
  return state.templateId;
}

/**
 * Returns the number of revisions of the post currently being edited.
 *
 * @param {Object} state Global application state.
 *
 * @return {number} Number of revisions.
 */
function getCurrentPostRevisionsCount(state) {
  var _getCurrentPost$_link;
  return (_getCurrentPost$_link = getCurrentPost(state)._links?.['version-history']?.[0]?.count) !== null && _getCurrentPost$_link !== void 0 ? _getCurrentPost$_link : 0;
}

/**
 * Returns the last revision ID of the post currently being edited,
 * or null if the post has no revisions.
 *
 * @param {Object} state Global application state.
 *
 * @return {?number} ID of the last revision.
 */
function getCurrentPostLastRevisionId(state) {
  var _getCurrentPost$_link2;
  return (_getCurrentPost$_link2 = getCurrentPost(state)._links?.['predecessor-version']?.[0]?.id) !== null && _getCurrentPost$_link2 !== void 0 ? _getCurrentPost$_link2 : null;
}

/**
 * Returns any post values which have been changed in the editor but not yet
 * been saved.
 *
 * @param {Object} state Global application state.
 *
 * @return {Object} Object of key value pairs comprising unsaved edits.
 */
const getPostEdits = exports.getPostEdits = (0, _data.createRegistrySelector)(select => state => {
  const postType = getCurrentPostType(state);
  const postId = getCurrentPostId(state);
  return select(_coreData.store).getEntityRecordEdits('postType', postType, postId) || EMPTY_OBJECT;
});

/**
 * Returns an attribute value of the saved post.
 *
 * @param {Object} state         Global application state.
 * @param {string} attributeName Post attribute name.
 *
 * @return {*} Post attribute value.
 */
function getCurrentPostAttribute(state, attributeName) {
  switch (attributeName) {
    case 'type':
      return getCurrentPostType(state);
    case 'id':
      return getCurrentPostId(state);
    default:
      const post = getCurrentPost(state);
      if (!post.hasOwnProperty(attributeName)) {
        break;
      }
      return (0, _reducer.getPostRawValue)(post[attributeName]);
  }
}

/**
 * Returns a single attribute of the post being edited, preferring the unsaved
 * edit if one exists, but merging with the attribute value for the last known
 * saved state of the post (this is needed for some nested attributes like meta).
 *
 * @param {Object} state         Global application state.
 * @param {string} attributeName Post attribute name.
 *
 * @return {*} Post attribute value.
 */
const getNestedEditedPostProperty = (0, _data.createSelector)((state, attributeName) => {
  const edits = getPostEdits(state);
  if (!edits.hasOwnProperty(attributeName)) {
    return getCurrentPostAttribute(state, attributeName);
  }
  return {
    ...getCurrentPostAttribute(state, attributeName),
    ...edits[attributeName]
  };
}, (state, attributeName) => [getCurrentPostAttribute(state, attributeName), getPostEdits(state)[attributeName]]);

/**
 * Returns a single attribute of the post being edited, preferring the unsaved
 * edit if one exists, but falling back to the attribute for the last known
 * saved state of the post.
 *
 * @param {Object} state         Global application state.
 * @param {string} attributeName Post attribute name.
 *
 * @example
 *
 *```js
 * 	// Get specific media size based on the featured media ID
 * 	// Note: change sizes?.large for any registered size
 * 	const getFeaturedMediaUrl = useSelect( ( select ) => {
 * 		const getFeaturedMediaId =
 * 			select( 'core/editor' ).getEditedPostAttribute( 'featured_media' );
 * 		const media = select( 'core' ).getEntityRecord(
 * 			'postType',
 * 			'attachment',
 * 			getFeaturedMediaId
 * 		);
 *
 * 		return (
 * 			media?.media_details?.sizes?.large?.source_url || media?.source_url || ''
 * 		);
 * }, [] );
 *```
 *
 * @return {*} Post attribute value.
 */
function getEditedPostAttribute(state, attributeName) {
  // Special cases.
  switch (attributeName) {
    case 'content':
      return getEditedPostContent(state);
  }

  // Fall back to saved post value if not edited.
  const edits = getPostEdits(state);
  if (!edits.hasOwnProperty(attributeName)) {
    return getCurrentPostAttribute(state, attributeName);
  }

  // Merge properties are objects which contain only the patch edit in state,
  // and thus must be merged with the current post attribute.
  if (_constants.EDIT_MERGE_PROPERTIES.has(attributeName)) {
    return getNestedEditedPostProperty(state, attributeName);
  }
  return edits[attributeName];
}

/**
 * Returns an attribute value of the current autosave revision for a post, or
 * null if there is no autosave for the post.
 *
 * @deprecated since 5.6. Callers should use the `getAutosave( postType, postId, userId )` selector
 * 			   from the '@wordpress/core-data' package and access properties on the returned
 * 			   autosave object using getPostRawValue.
 *
 * @param {Object} state         Global application state.
 * @param {string} attributeName Autosave attribute name.
 *
 * @return {*} Autosave attribute value.
 */
const getAutosaveAttribute = exports.getAutosaveAttribute = (0, _data.createRegistrySelector)(select => (state, attributeName) => {
  if (!_constants.AUTOSAVE_PROPERTIES.includes(attributeName) && attributeName !== 'preview_link') {
    return;
  }
  const postType = getCurrentPostType(state);

  // Currently template autosaving is not supported.
  if (postType === 'wp_template') {
    return false;
  }
  const postId = getCurrentPostId(state);
  const currentUserId = select(_coreData.store).getCurrentUser()?.id;
  const autosave = select(_coreData.store).getAutosave(postType, postId, currentUserId);
  if (autosave) {
    return (0, _reducer.getPostRawValue)(autosave[attributeName]);
  }
});

/**
 * Returns the current visibility of the post being edited, preferring the
 * unsaved value if different than the saved post. The return value is one of
 * "private", "password", or "public".
 *
 * @param {Object} state Global application state.
 *
 * @return {string} Post visibility.
 */
function getEditedPostVisibility(state) {
  const status = getEditedPostAttribute(state, 'status');
  if (status === 'private') {
    return 'private';
  }
  const password = getEditedPostAttribute(state, 'password');
  if (password) {
    return 'password';
  }
  return 'public';
}

/**
 * Returns true if post is pending review.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether current post is pending review.
 */
function isCurrentPostPending(state) {
  return getCurrentPost(state).status === 'pending';
}

/**
 * Return true if the current post has already been published.
 *
 * @param {Object} state         Global application state.
 * @param {Object} [currentPost] Explicit current post for bypassing registry selector.
 *
 * @return {boolean} Whether the post has been published.
 */
function isCurrentPostPublished(state, currentPost) {
  const post = currentPost || getCurrentPost(state);
  return ['publish', 'private'].indexOf(post.status) !== -1 || post.status === 'future' && !(0, _date.isInTheFuture)(new Date(Number((0, _date.getDate)(post.date)) - _constants.ONE_MINUTE_IN_MS));
}

/**
 * Returns true if post is already scheduled.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether current post is scheduled to be posted.
 */
function isCurrentPostScheduled(state) {
  return getCurrentPost(state).status === 'future' && !isCurrentPostPublished(state);
}

/**
 * Return true if the post being edited can be published.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether the post can been published.
 */
function isEditedPostPublishable(state) {
  const post = getCurrentPost(state);

  // TODO: Post being publishable should be superset of condition of post
  // being saveable. Currently this restriction is imposed at UI.
  //
  //  See: <PostPublishButton /> (`isButtonEnabled` assigned by `isSaveable`).

  return isEditedPostDirty(state) || ['publish', 'private', 'future'].indexOf(post.status) === -1;
}

/**
 * Returns true if the post can be saved, or false otherwise. A post must
 * contain a title, an excerpt, or non-empty content to be valid for save.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether the post can be saved.
 */
function isEditedPostSaveable(state) {
  if (isSavingPost(state)) {
    return false;
  }

  // TODO: Post should not be saveable if not dirty. Cannot be added here at
  // this time since posts where meta boxes are present can be saved even if
  // the post is not dirty. Currently this restriction is imposed at UI, but
  // should be moved here.
  //
  //  See: `isEditedPostPublishable` (includes `isEditedPostDirty` condition)
  //  See: <PostSavedState /> (`forceIsDirty` prop)
  //  See: <PostPublishButton /> (`forceIsDirty` prop)
  //  See: https://github.com/WordPress/gutenberg/pull/4184.

  return !!getEditedPostAttribute(state, 'title') || !!getEditedPostAttribute(state, 'excerpt') || !isEditedPostEmpty(state) || _element.Platform.OS === 'native';
}

/**
 * Returns true if the edited post has content. A post has content if it has at
 * least one saveable block or otherwise has a non-empty content property
 * assigned.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether post has content.
 */
const isEditedPostEmpty = exports.isEditedPostEmpty = (0, _data.createRegistrySelector)(select => state => {
  // While the condition of truthy content string is sufficient to determine
  // emptiness, testing saveable blocks length is a trivial operation. Since
  // this function can be called frequently, optimize for the fast case as a
  // condition of the mere existence of blocks. Note that the value of edited
  // content takes precedent over block content, and must fall through to the
  // default logic.
  const postId = getCurrentPostId(state);
  const postType = getCurrentPostType(state);
  const record = select(_coreData.store).getEditedEntityRecord('postType', postType, postId);
  if (typeof record.content !== 'function') {
    return !record.content;
  }
  const blocks = getEditedPostAttribute(state, 'blocks');
  if (blocks.length === 0) {
    return true;
  }

  // Pierce the abstraction of the serializer in knowing that blocks are
  // joined with newlines such that even if every individual block
  // produces an empty save result, the serialized content is non-empty.
  if (blocks.length > 1) {
    return false;
  }

  // There are two conditions under which the optimization cannot be
  // assumed, and a fallthrough to getEditedPostContent must occur:
  //
  // 1. getBlocksForSerialization has special treatment in omitting a
  //    single unmodified default block.
  // 2. Comment delimiters are omitted for a freeform or unregistered
  //    block in its serialization. The freeform block specifically may
  //    produce an empty string in its saved output.
  //
  // For all other content, the single block is assumed to make a post
  // non-empty, if only by virtue of its own comment delimiters.
  const blockName = blocks[0].name;
  if (blockName !== (0, _blocks.getDefaultBlockName)() && blockName !== (0, _blocks.getFreeformContentHandlerName)()) {
    return false;
  }
  return !getEditedPostContent(state);
});

/**
 * Returns true if the post can be autosaved, or false otherwise.
 *
 * @param {Object} state    Global application state.
 * @param {Object} autosave A raw autosave object from the REST API.
 *
 * @return {boolean} Whether the post can be autosaved.
 */
const isEditedPostAutosaveable = exports.isEditedPostAutosaveable = (0, _data.createRegistrySelector)(select => state => {
  // A post must contain a title, an excerpt, or non-empty content to be valid for autosaving.
  if (!isEditedPostSaveable(state)) {
    return false;
  }

  // A post is not autosavable when there is a post autosave lock.
  if (isPostAutosavingLocked(state)) {
    return false;
  }
  const postType = getCurrentPostType(state);
  const postTypeObject = select(_coreData.store).getPostType(postType);

  // Currently template autosaving is not supported.
  // @todo: Remove hardcode check for template after bumping required WP version to 6.8.
  if (postType === 'wp_template' || !postTypeObject?.supports?.autosave) {
    return false;
  }
  const postId = getCurrentPostId(state);
  const hasFetchedAutosave = select(_coreData.store).hasFetchedAutosaves(postType, postId);
  const currentUserId = select(_coreData.store).getCurrentUser()?.id;

  // Disable reason - this line causes the side-effect of fetching the autosave
  // via a resolver, moving below the return would result in the autosave never
  // being fetched.
  // eslint-disable-next-line @wordpress/no-unused-vars-before-return
  const autosave = select(_coreData.store).getAutosave(postType, postId, currentUserId);

  // If any existing autosaves have not yet been fetched, this function is
  // unable to determine if the post is autosaveable, so return false.
  if (!hasFetchedAutosave) {
    return false;
  }

  // If we don't already have an autosave, the post is autosaveable.
  if (!autosave) {
    return true;
  }

  // To avoid an expensive content serialization, use the content dirtiness
  // flag in place of content field comparison against the known autosave.
  // This is not strictly accurate, and relies on a tolerance toward autosave
  // request failures for unnecessary saves.
  if (hasChangedContent(state)) {
    return true;
  }

  // If title, excerpt, or meta have changed, the post is autosaveable.
  return ['title', 'excerpt', 'meta'].some(field => (0, _reducer.getPostRawValue)(autosave[field]) !== getEditedPostAttribute(state, field));
});

/**
 * Return true if the post being edited is being scheduled. Preferring the
 * unsaved status values.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether the post has been published.
 */
function isEditedPostBeingScheduled(state) {
  const date = getEditedPostAttribute(state, 'date');
  // Offset the date by one minute (network latency).
  const checkedDate = new Date(Number((0, _date.getDate)(date)) - _constants.ONE_MINUTE_IN_MS);
  return (0, _date.isInTheFuture)(checkedDate);
}

/**
 * Returns whether the current post should be considered to have a "floating"
 * date (i.e. that it would publish "Immediately" rather than at a set time).
 *
 * Unlike in the PHP backend, the REST API returns a full date string for posts
 * where the 0000-00-00T00:00:00 placeholder is present in the database. To
 * infer that a post is set to publish "Immediately" we check whether the date
 * and modified date are the same.
 *
 * @param {Object} state Editor state.
 *
 * @return {boolean} Whether the edited post has a floating date value.
 */
function isEditedPostDateFloating(state) {
  const date = getEditedPostAttribute(state, 'date');
  const modified = getEditedPostAttribute(state, 'modified');

  // This should be the status of the persisted post
  // It shouldn't use the "edited" status otherwise it breaks the
  // inferred post data floating status
  // See https://github.com/WordPress/gutenberg/issues/28083.
  const status = getCurrentPost(state).status;
  if (status === 'draft' || status === 'auto-draft' || status === 'pending') {
    return date === modified || date === null;
  }
  return false;
}

/**
 * Returns true if the post is currently being deleted, or false otherwise.
 *
 * @param {Object} state Editor state.
 *
 * @return {boolean} Whether post is being deleted.
 */
function isDeletingPost(state) {
  return !!state.deleting.pending;
}

/**
 * Returns true if the post is currently being saved, or false otherwise.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether post is being saved.
 */
function isSavingPost(state) {
  return !!state.saving.pending;
}

/**
 * Returns true if non-post entities are currently being saved, or false otherwise.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether non-post entities are being saved.
 */
const isSavingNonPostEntityChanges = exports.isSavingNonPostEntityChanges = (0, _data.createRegistrySelector)(select => state => {
  const entitiesBeingSaved = select(_coreData.store).__experimentalGetEntitiesBeingSaved();
  const {
    type,
    id
  } = getCurrentPost(state);
  return entitiesBeingSaved.some(entityRecord => entityRecord.kind !== 'postType' || entityRecord.name !== type || entityRecord.key !== id);
});

/**
 * Returns true if a previous post save was attempted successfully, or false
 * otherwise.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether the post was saved successfully.
 */
const didPostSaveRequestSucceed = exports.didPostSaveRequestSucceed = (0, _data.createRegistrySelector)(select => state => {
  const postType = getCurrentPostType(state);
  const postId = getCurrentPostId(state);
  return !select(_coreData.store).getLastEntitySaveError('postType', postType, postId);
});

/**
 * Returns true if a previous post save was attempted but failed, or false
 * otherwise.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether the post save failed.
 */
const didPostSaveRequestFail = exports.didPostSaveRequestFail = (0, _data.createRegistrySelector)(select => state => {
  const postType = getCurrentPostType(state);
  const postId = getCurrentPostId(state);
  return !!select(_coreData.store).getLastEntitySaveError('postType', postType, postId);
});

/**
 * Returns true if the post is autosaving, or false otherwise.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether the post is autosaving.
 */
function isAutosavingPost(state) {
  return isSavingPost(state) && Boolean(state.saving.options?.isAutosave);
}

/**
 * Returns true if the post is being previewed, or false otherwise.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether the post is being previewed.
 */
function isPreviewingPost(state) {
  return isSavingPost(state) && Boolean(state.saving.options?.isPreview);
}

/**
 * Returns the post preview link
 *
 * @param {Object} state Global application state.
 *
 * @return {string | undefined} Preview Link.
 */
function getEditedPostPreviewLink(state) {
  if (state.saving.pending || isSavingPost(state)) {
    return;
  }
  let previewLink = getAutosaveAttribute(state, 'preview_link');
  // Fix for issue: https://github.com/WordPress/gutenberg/issues/33616
  // If the post is draft, ignore the preview link from the autosave record,
  // because the preview could be a stale autosave if the post was switched from
  // published to draft.
  // See: https://github.com/WordPress/gutenberg/pull/37952.
  if (!previewLink || 'draft' === getCurrentPost(state).status) {
    previewLink = getEditedPostAttribute(state, 'link');
    if (previewLink) {
      previewLink = (0, _url.addQueryArgs)(previewLink, {
        preview: true
      });
    }
  }
  const featuredImageId = getEditedPostAttribute(state, 'featured_media');
  if (previewLink && featuredImageId) {
    return (0, _url.addQueryArgs)(previewLink, {
      _thumbnail_id: featuredImageId
    });
  }
  return previewLink;
}

/**
 * Returns a suggested post format for the current post, inferred only if there
 * is a single block within the post and it is of a type known to match a
 * default post format. Returns null if the format cannot be determined.
 *
 * @return {?string} Suggested post format.
 */
const getSuggestedPostFormat = exports.getSuggestedPostFormat = (0, _data.createRegistrySelector)(select => () => {
  const blocks = select(_blockEditor.store).getBlocks();
  if (blocks.length > 2) {
    return null;
  }
  let name;
  // If there is only one block in the content of the post grab its name
  // so we can derive a suitable post format from it.
  if (blocks.length === 1) {
    name = blocks[0].name;
    // Check for core/embed `video` and `audio` eligible suggestions.
    if (name === 'core/embed') {
      const provider = blocks[0].attributes?.providerNameSlug;
      if (['youtube', 'vimeo'].includes(provider)) {
        name = 'core/video';
      } else if (['spotify', 'soundcloud'].includes(provider)) {
        name = 'core/audio';
      }
    }
  }

  // If there are two blocks in the content and the last one is a text blocks
  // grab the name of the first one to also suggest a post format from it.
  if (blocks.length === 2 && blocks[1].name === 'core/paragraph') {
    name = blocks[0].name;
  }

  // We only convert to default post formats in core.
  switch (name) {
    case 'core/image':
      return 'image';
    case 'core/quote':
    case 'core/pullquote':
      return 'quote';
    case 'core/gallery':
      return 'gallery';
    case 'core/video':
      return 'video';
    case 'core/audio':
      return 'audio';
    default:
      return null;
  }
});

/**
 * Returns the content of the post being edited.
 *
 * @param {Object} state Global application state.
 *
 * @return {string} Post content.
 */
const getEditedPostContent = exports.getEditedPostContent = (0, _data.createRegistrySelector)(select => state => {
  const postId = getCurrentPostId(state);
  const postType = getCurrentPostType(state);
  const record = select(_coreData.store).getEditedEntityRecord('postType', postType, postId);
  if (record) {
    if (typeof record.content === 'function') {
      return record.content(record);
    } else if (record.blocks) {
      return (0, _blocks.__unstableSerializeAndClean)(record.blocks);
    } else if (record.content) {
      return record.content;
    }
  }
  return '';
});

/**
 * Returns true if the post is being published, or false otherwise.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether post is being published.
 */
function isPublishingPost(state) {
  return isSavingPost(state) && !isCurrentPostPublished(state) && getEditedPostAttribute(state, 'status') === 'publish';
}

/**
 * Returns whether the permalink is editable or not.
 *
 * @param {Object} state Editor state.
 *
 * @return {boolean} Whether or not the permalink is editable.
 */
function isPermalinkEditable(state) {
  const permalinkTemplate = getEditedPostAttribute(state, 'permalink_template');
  return _constants.PERMALINK_POSTNAME_REGEX.test(permalinkTemplate);
}

/**
 * Returns the permalink for the post.
 *
 * @param {Object} state Editor state.
 *
 * @return {?string} The permalink, or null if the post is not viewable.
 */
function getPermalink(state) {
  const permalinkParts = getPermalinkParts(state);
  if (!permalinkParts) {
    return null;
  }
  const {
    prefix,
    postName,
    suffix
  } = permalinkParts;
  if (isPermalinkEditable(state)) {
    return prefix + postName + suffix;
  }
  return prefix;
}

/**
 * Returns the slug for the post being edited, preferring a manually edited
 * value if one exists, then a sanitized version of the current post title, and
 * finally the post ID.
 *
 * @param {Object} state Editor state.
 *
 * @return {string} The current slug to be displayed in the editor
 */
function getEditedPostSlug(state) {
  return getEditedPostAttribute(state, 'slug') || (0, _url.cleanForSlug)(getEditedPostAttribute(state, 'title')) || getCurrentPostId(state);
}

/**
 * Returns the permalink for a post, split into its three parts: the prefix,
 * the postName, and the suffix.
 *
 * @param {Object} state Editor state.
 *
 * @return {Object} An object containing the prefix, postName, and suffix for
 *                  the permalink, or null if the post is not viewable.
 */
function getPermalinkParts(state) {
  const permalinkTemplate = getEditedPostAttribute(state, 'permalink_template');
  if (!permalinkTemplate) {
    return null;
  }
  const postName = getEditedPostAttribute(state, 'slug') || getEditedPostAttribute(state, 'generated_slug');
  const [prefix, suffix] = permalinkTemplate.split(_constants.PERMALINK_POSTNAME_REGEX);
  return {
    prefix,
    postName,
    suffix
  };
}

/**
 * Returns whether the post is locked.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Is locked.
 */
function isPostLocked(state) {
  return state.postLock.isLocked;
}

/**
 * Returns whether post saving is locked.
 *
 * @param {Object} state Global application state.
 *
 * @example
 * ```jsx
 * import { __ } from '@wordpress/i18n';
 * import { store as editorStore } from '@wordpress/editor';
 * import { useSelect } from '@wordpress/data';
 *
 * const ExampleComponent = () => {
 * 	const isSavingLocked = useSelect(
 * 		( select ) => select( editorStore ).isPostSavingLocked(),
 * 		[]
 * 	);
 *
 * 	return isSavingLocked ? (
 * 		<p>{ __( 'Post saving is locked' ) }</p>
 * 	) : (
 * 		<p>{ __( 'Post saving is not locked' ) }</p>
 * 	);
 * };
 * ```
 *
 * @return {boolean} Is locked.
 */
function isPostSavingLocked(state) {
  return Object.keys(state.postSavingLock).length > 0;
}

/**
 * Returns whether post autosaving is locked.
 *
 * @param {Object} state Global application state.
 *
 * @example
 * ```jsx
 * import { __ } from '@wordpress/i18n';
 * import { store as editorStore } from '@wordpress/editor';
 * import { useSelect } from '@wordpress/data';
 *
 * const ExampleComponent = () => {
 * 	const isAutoSavingLocked = useSelect(
 * 		( select ) => select( editorStore ).isPostAutosavingLocked(),
 * 		[]
 * 	);
 *
 * 	return isAutoSavingLocked ? (
 * 		<p>{ __( 'Post auto saving is locked' ) }</p>
 * 	) : (
 * 		<p>{ __( 'Post auto saving is not locked' ) }</p>
 * 	);
 * };
 * ```
 *
 * @return {boolean} Is locked.
 */
function isPostAutosavingLocked(state) {
  return Object.keys(state.postAutosavingLock).length > 0;
}

/**
 * Returns whether the edition of the post has been taken over.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Is post lock takeover.
 */
function isPostLockTakeover(state) {
  return state.postLock.isTakeover;
}

/**
 * Returns details about the post lock user.
 *
 * @param {Object} state Global application state.
 *
 * @return {Object} A user object.
 */
function getPostLockUser(state) {
  return state.postLock.user;
}

/**
 * Returns the active post lock.
 *
 * @param {Object} state Global application state.
 *
 * @return {Object} The lock object.
 */
function getActivePostLock(state) {
  return state.postLock.activePostLock;
}

/**
 * Returns whether or not the user has the unfiltered_html capability.
 *
 * @param {Object} state Editor state.
 *
 * @return {boolean} Whether the user can or can't post unfiltered HTML.
 */
function canUserUseUnfilteredHTML(state) {
  return Boolean(getCurrentPost(state)._links?.hasOwnProperty('wp:action-unfiltered-html'));
}

/**
 * Returns whether the pre-publish panel should be shown
 * or skipped when the user clicks the "publish" button.
 *
 * @return {boolean} Whether the pre-publish panel should be shown or not.
 */
const isPublishSidebarEnabled = exports.isPublishSidebarEnabled = (0, _data.createRegistrySelector)(select => () => !!select(_preferences.store).get('core', 'isPublishSidebarEnabled'));

/**
 * Return the current block list.
 *
 * @param {Object} state
 * @return {Array} Block list.
 */
const getEditorBlocks = exports.getEditorBlocks = (0, _data.createSelector)(state => {
  return getEditedPostAttribute(state, 'blocks') || (0, _blocks.parse)(getEditedPostContent(state));
}, state => [getEditedPostAttribute(state, 'blocks'), getEditedPostContent(state)]);

/**
 * Returns true if the given panel was programmatically removed, or false otherwise.
 * All panels are not removed by default.
 *
 * @param {Object} state     Global application state.
 * @param {string} panelName A string that identifies the panel.
 *
 * @return {boolean} Whether or not the panel is removed.
 */
function isEditorPanelRemoved(state, panelName) {
  return state.removedPanels.includes(panelName);
}

/**
 * Returns true if the given panel is enabled, or false otherwise. Panels are
 * enabled by default.
 *
 * @param {Object} state     Global application state.
 * @param {string} panelName A string that identifies the panel.
 *
 * @return {boolean} Whether or not the panel is enabled.
 */
const isEditorPanelEnabled = exports.isEditorPanelEnabled = (0, _data.createRegistrySelector)(select => (state, panelName) => {
  // For backward compatibility, we check edit-post
  // even though now this is in "editor" package.
  const inactivePanels = select(_preferences.store).get('core', 'inactivePanels');
  return !isEditorPanelRemoved(state, panelName) && !inactivePanels?.includes(panelName);
});

/**
 * Returns true if the given panel is open, or false otherwise. Panels are
 * closed by default.
 *
 * @param {Object} state     Global application state.
 * @param {string} panelName A string that identifies the panel.
 *
 * @return {boolean} Whether or not the panel is open.
 */
const isEditorPanelOpened = exports.isEditorPanelOpened = (0, _data.createRegistrySelector)(select => (state, panelName) => {
  // For backward compatibility, we check edit-post
  // even though now this is in "editor" package.
  const openPanels = select(_preferences.store).get('core', 'openPanels');
  return !!openPanels?.includes(panelName);
});

/**
 * A block selection object.
 *
 * @typedef {Object} WPBlockSelection
 *
 * @property {string} clientId     A block client ID.
 * @property {string} attributeKey A block attribute key.
 * @property {number} offset       An attribute value offset, based on the rich
 *                                 text value. See `wp.richText.create`.
 */

/**
 * Returns the current selection start.
 *
 * @deprecated since Gutenberg 10.0.0.
 *
 * @param {Object} state
 * @return {WPBlockSelection} The selection start.
 */
function getEditorSelectionStart(state) {
  (0, _deprecated.default)("select('core/editor').getEditorSelectionStart", {
    since: '5.8',
    alternative: "select('core/editor').getEditorSelection"
  });
  return getEditedPostAttribute(state, 'selection')?.selectionStart;
}

/**
 * Returns the current selection end.
 *
 * @deprecated since Gutenberg 10.0.0.
 *
 * @param {Object} state
 * @return {WPBlockSelection} The selection end.
 */
function getEditorSelectionEnd(state) {
  (0, _deprecated.default)("select('core/editor').getEditorSelectionStart", {
    since: '5.8',
    alternative: "select('core/editor').getEditorSelection"
  });
  return getEditedPostAttribute(state, 'selection')?.selectionEnd;
}

/**
 * Returns the current selection.
 *
 * @param {Object} state
 * @return {WPBlockSelection} The selection end.
 */
function getEditorSelection(state) {
  return getEditedPostAttribute(state, 'selection');
}

/**
 * Is the editor ready
 *
 * @param {Object} state
 * @return {boolean} is Ready.
 */
function __unstableIsEditorReady(state) {
  return !!state.postId;
}

/**
 * Returns the post editor settings.
 *
 * @param {Object} state Editor state.
 *
 * @return {Object} The editor settings object.
 */
function getEditorSettings(state) {
  return state.editorSettings;
}

/**
 * Returns the post editor's rendering mode.
 *
 * @param {Object} state Editor state.
 *
 * @return {string} Rendering mode.
 */
function getRenderingMode(state) {
  return state.renderingMode;
}

/**
 * Returns the current editing canvas device type.
 *
 * @param {Object} state Global application state.
 *
 * @return {string} Device type.
 */
const getDeviceType = exports.getDeviceType = (0, _data.createRegistrySelector)(select => state => {
  const isZoomOut = (0, _lockUnlock.unlock)(select(_blockEditor.store)).isZoomOut();
  if (isZoomOut) {
    return 'Desktop';
  }
  return state.deviceType;
});

/**
 * Returns true if the list view is opened.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether the list view is opened.
 */
function isListViewOpened(state) {
  return state.listViewPanel;
}

/**
 * Returns true if the inserter is opened.
 *
 * @param {Object} state Global application state.
 *
 * @return {boolean} Whether the inserter is opened.
 */
function isInserterOpened(state) {
  return !!state.blockInserterPanel;
}

/**
 * Returns the current editing mode.
 *
 * @param {Object} state Global application state.
 *
 * @return {string} Editing mode.
 */
const getEditorMode = exports.getEditorMode = (0, _data.createRegistrySelector)(select => () => {
  var _select$get;
  return (_select$get = select(_preferences.store).get('core', 'editorMode')) !== null && _select$get !== void 0 ? _select$get : 'visual';
});

/*
 * Backward compatibility
 */

/**
 * Returns state object prior to a specified optimist transaction ID, or `null`
 * if the transaction corresponding to the given ID cannot be found.
 *
 * @deprecated since Gutenberg 9.7.0.
 */
function getStateBeforeOptimisticTransaction() {
  (0, _deprecated.default)("select('core/editor').getStateBeforeOptimisticTransaction", {
    since: '5.7',
    hint: 'No state history is kept on this store anymore'
  });
  return null;
}
/**
 * Returns true if an optimistic transaction is pending commit, for which the
 * before state satisfies the given predicate function.
 *
 * @deprecated since Gutenberg 9.7.0.
 */
function inSomeHistory() {
  (0, _deprecated.default)("select('core/editor').inSomeHistory", {
    since: '5.7',
    hint: 'No state history is kept on this store anymore'
  });
  return false;
}
function getBlockEditorSelector(name) {
  return (0, _data.createRegistrySelector)(select => (state, ...args) => {
    (0, _deprecated.default)("`wp.data.select( 'core/editor' )." + name + '`', {
      since: '5.3',
      alternative: "`wp.data.select( 'core/block-editor' )." + name + '`',
      version: '6.2'
    });
    return select(_blockEditor.store)[name](...args);
  });
}

/**
 * @see getBlockName in core/block-editor store.
 */
const getBlockName = exports.getBlockName = getBlockEditorSelector('getBlockName');

/**
 * @see isBlockValid in core/block-editor store.
 */
const isBlockValid = exports.isBlockValid = getBlockEditorSelector('isBlockValid');

/**
 * @see getBlockAttributes in core/block-editor store.
 */
const getBlockAttributes = exports.getBlockAttributes = getBlockEditorSelector('getBlockAttributes');

/**
 * @see getBlock in core/block-editor store.
 */
const getBlock = exports.getBlock = getBlockEditorSelector('getBlock');

/**
 * @see getBlocks in core/block-editor store.
 */
const getBlocks = exports.getBlocks = getBlockEditorSelector('getBlocks');

/**
 * @see getClientIdsOfDescendants in core/block-editor store.
 */
const getClientIdsOfDescendants = exports.getClientIdsOfDescendants = getBlockEditorSelector('getClientIdsOfDescendants');

/**
 * @see getClientIdsWithDescendants in core/block-editor store.
 */
const getClientIdsWithDescendants = exports.getClientIdsWithDescendants = getBlockEditorSelector('getClientIdsWithDescendants');

/**
 * @see getGlobalBlockCount in core/block-editor store.
 */
const getGlobalBlockCount = exports.getGlobalBlockCount = getBlockEditorSelector('getGlobalBlockCount');

/**
 * @see getBlocksByClientId in core/block-editor store.
 */
const getBlocksByClientId = exports.getBlocksByClientId = getBlockEditorSelector('getBlocksByClientId');

/**
 * @see getBlockCount in core/block-editor store.
 */
const getBlockCount = exports.getBlockCount = getBlockEditorSelector('getBlockCount');

/**
 * @see getBlockSelectionStart in core/block-editor store.
 */
const getBlockSelectionStart = exports.getBlockSelectionStart = getBlockEditorSelector('getBlockSelectionStart');

/**
 * @see getBlockSelectionEnd in core/block-editor store.
 */
const getBlockSelectionEnd = exports.getBlockSelectionEnd = getBlockEditorSelector('getBlockSelectionEnd');

/**
 * @see getSelectedBlockCount in core/block-editor store.
 */
const getSelectedBlockCount = exports.getSelectedBlockCount = getBlockEditorSelector('getSelectedBlockCount');

/**
 * @see hasSelectedBlock in core/block-editor store.
 */
const hasSelectedBlock = exports.hasSelectedBlock = getBlockEditorSelector('hasSelectedBlock');

/**
 * @see getSelectedBlockClientId in core/block-editor store.
 */
const getSelectedBlockClientId = exports.getSelectedBlockClientId = getBlockEditorSelector('getSelectedBlockClientId');

/**
 * @see getSelectedBlock in core/block-editor store.
 */
const getSelectedBlock = exports.getSelectedBlock = getBlockEditorSelector('getSelectedBlock');

/**
 * @see getBlockRootClientId in core/block-editor store.
 */
const getBlockRootClientId = exports.getBlockRootClientId = getBlockEditorSelector('getBlockRootClientId');

/**
 * @see getBlockHierarchyRootClientId in core/block-editor store.
 */
const getBlockHierarchyRootClientId = exports.getBlockHierarchyRootClientId = getBlockEditorSelector('getBlockHierarchyRootClientId');

/**
 * @see getAdjacentBlockClientId in core/block-editor store.
 */
const getAdjacentBlockClientId = exports.getAdjacentBlockClientId = getBlockEditorSelector('getAdjacentBlockClientId');

/**
 * @see getPreviousBlockClientId in core/block-editor store.
 */
const getPreviousBlockClientId = exports.getPreviousBlockClientId = getBlockEditorSelector('getPreviousBlockClientId');

/**
 * @see getNextBlockClientId in core/block-editor store.
 */
const getNextBlockClientId = exports.getNextBlockClientId = getBlockEditorSelector('getNextBlockClientId');

/**
 * @see getSelectedBlocksInitialCaretPosition in core/block-editor store.
 */
const getSelectedBlocksInitialCaretPosition = exports.getSelectedBlocksInitialCaretPosition = getBlockEditorSelector('getSelectedBlocksInitialCaretPosition');

/**
 * @see getMultiSelectedBlockClientIds in core/block-editor store.
 */
const getMultiSelectedBlockClientIds = exports.getMultiSelectedBlockClientIds = getBlockEditorSelector('getMultiSelectedBlockClientIds');

/**
 * @see getMultiSelectedBlocks in core/block-editor store.
 */
const getMultiSelectedBlocks = exports.getMultiSelectedBlocks = getBlockEditorSelector('getMultiSelectedBlocks');

/**
 * @see getFirstMultiSelectedBlockClientId in core/block-editor store.
 */
const getFirstMultiSelectedBlockClientId = exports.getFirstMultiSelectedBlockClientId = getBlockEditorSelector('getFirstMultiSelectedBlockClientId');

/**
 * @see getLastMultiSelectedBlockClientId in core/block-editor store.
 */
const getLastMultiSelectedBlockClientId = exports.getLastMultiSelectedBlockClientId = getBlockEditorSelector('getLastMultiSelectedBlockClientId');

/**
 * @see isFirstMultiSelectedBlock in core/block-editor store.
 */
const isFirstMultiSelectedBlock = exports.isFirstMultiSelectedBlock = getBlockEditorSelector('isFirstMultiSelectedBlock');

/**
 * @see isBlockMultiSelected in core/block-editor store.
 */
const isBlockMultiSelected = exports.isBlockMultiSelected = getBlockEditorSelector('isBlockMultiSelected');

/**
 * @see isAncestorMultiSelected in core/block-editor store.
 */
const isAncestorMultiSelected = exports.isAncestorMultiSelected = getBlockEditorSelector('isAncestorMultiSelected');

/**
 * @see getMultiSelectedBlocksStartClientId in core/block-editor store.
 */
const getMultiSelectedBlocksStartClientId = exports.getMultiSelectedBlocksStartClientId = getBlockEditorSelector('getMultiSelectedBlocksStartClientId');

/**
 * @see getMultiSelectedBlocksEndClientId in core/block-editor store.
 */
const getMultiSelectedBlocksEndClientId = exports.getMultiSelectedBlocksEndClientId = getBlockEditorSelector('getMultiSelectedBlocksEndClientId');

/**
 * @see getBlockOrder in core/block-editor store.
 */
const getBlockOrder = exports.getBlockOrder = getBlockEditorSelector('getBlockOrder');

/**
 * @see getBlockIndex in core/block-editor store.
 */
const getBlockIndex = exports.getBlockIndex = getBlockEditorSelector('getBlockIndex');

/**
 * @see isBlockSelected in core/block-editor store.
 */
const isBlockSelected = exports.isBlockSelected = getBlockEditorSelector('isBlockSelected');

/**
 * @see hasSelectedInnerBlock in core/block-editor store.
 */
const hasSelectedInnerBlock = exports.hasSelectedInnerBlock = getBlockEditorSelector('hasSelectedInnerBlock');

/**
 * @see isBlockWithinSelection in core/block-editor store.
 */
const isBlockWithinSelection = exports.isBlockWithinSelection = getBlockEditorSelector('isBlockWithinSelection');

/**
 * @see hasMultiSelection in core/block-editor store.
 */
const hasMultiSelection = exports.hasMultiSelection = getBlockEditorSelector('hasMultiSelection');

/**
 * @see isMultiSelecting in core/block-editor store.
 */
const isMultiSelecting = exports.isMultiSelecting = getBlockEditorSelector('isMultiSelecting');

/**
 * @see isSelectionEnabled in core/block-editor store.
 */
const isSelectionEnabled = exports.isSelectionEnabled = getBlockEditorSelector('isSelectionEnabled');

/**
 * @see getBlockMode in core/block-editor store.
 */
const getBlockMode = exports.getBlockMode = getBlockEditorSelector('getBlockMode');

/**
 * @see isTyping in core/block-editor store.
 */
const isTyping = exports.isTyping = getBlockEditorSelector('isTyping');

/**
 * @see isCaretWithinFormattedText in core/block-editor store.
 */
const isCaretWithinFormattedText = exports.isCaretWithinFormattedText = getBlockEditorSelector('isCaretWithinFormattedText');

/**
 * @see getBlockInsertionPoint in core/block-editor store.
 */
const getBlockInsertionPoint = exports.getBlockInsertionPoint = getBlockEditorSelector('getBlockInsertionPoint');

/**
 * @see isBlockInsertionPointVisible in core/block-editor store.
 */
const isBlockInsertionPointVisible = exports.isBlockInsertionPointVisible = getBlockEditorSelector('isBlockInsertionPointVisible');

/**
 * @see isValidTemplate in core/block-editor store.
 */
const isValidTemplate = exports.isValidTemplate = getBlockEditorSelector('isValidTemplate');

/**
 * @see getTemplate in core/block-editor store.
 */
const getTemplate = exports.getTemplate = getBlockEditorSelector('getTemplate');

/**
 * @see getTemplateLock in core/block-editor store.
 */
const getTemplateLock = exports.getTemplateLock = getBlockEditorSelector('getTemplateLock');

/**
 * @see canInsertBlockType in core/block-editor store.
 */
const canInsertBlockType = exports.canInsertBlockType = getBlockEditorSelector('canInsertBlockType');

/**
 * @see getInserterItems in core/block-editor store.
 */
const getInserterItems = exports.getInserterItems = getBlockEditorSelector('getInserterItems');

/**
 * @see hasInserterItems in core/block-editor store.
 */
const hasInserterItems = exports.hasInserterItems = getBlockEditorSelector('hasInserterItems');

/**
 * @see getBlockListSettings in core/block-editor store.
 */
const getBlockListSettings = exports.getBlockListSettings = getBlockEditorSelector('getBlockListSettings');
const __experimentalGetDefaultTemplateTypes = exports.__experimentalGetDefaultTemplateTypes = (0, _data.createRegistrySelector)(select => () => {
  (0, _deprecated.default)("select('core/editor').__experimentalGetDefaultTemplateTypes", {
    since: '6.8',
    alternative: "select('core/core-data').getCurrentTheme()?.default_template_types"
  });
  return select(_coreData.store).getCurrentTheme()?.default_template_types;
});

/**
 * Returns the default template part areas.
 *
 * @param {Object} state Global application state.
 *
 * @return {Array} The template part areas.
 */
const __experimentalGetDefaultTemplatePartAreas = exports.__experimentalGetDefaultTemplatePartAreas = (0, _data.createRegistrySelector)(select => (0, _data.createSelector)(() => {
  (0, _deprecated.default)("select('core/editor').__experimentalGetDefaultTemplatePartAreas", {
    since: '6.8',
    alternative: "select('core/core-data').getCurrentTheme()?.default_template_part_areas"
  });
  const areas = select(_coreData.store).getCurrentTheme()?.default_template_part_areas || [];
  return areas.map(item => {
    return {
      ...item,
      icon: (0, _getTemplatePartIcon.getTemplatePartIcon)(item.icon)
    };
  });
}));

/**
 * Returns a default template type searched by slug.
 *
 * @param {Object} state Global application state.
 * @param {string} slug  The template type slug.
 *
 * @return {Object} The template type.
 */
const __experimentalGetDefaultTemplateType = exports.__experimentalGetDefaultTemplateType = (0, _data.createRegistrySelector)(select => (0, _data.createSelector)((state, slug) => {
  var _Object$values$find;
  (0, _deprecated.default)("select('core/editor').__experimentalGetDefaultTemplateType", {
    since: '6.8'
  });
  const templateTypes = select(_coreData.store).getCurrentTheme()?.default_template_types;
  if (!templateTypes) {
    return EMPTY_OBJECT;
  }
  return (_Object$values$find = Object.values(templateTypes).find(type => type.slug === slug)) !== null && _Object$values$find !== void 0 ? _Object$values$find : EMPTY_OBJECT;
}));

/**
 * Given a template entity, return information about it which is ready to be
 * rendered, such as the title, description, and icon.
 *
 * @param {Object} state    Global application state.
 * @param {Object} template The template for which we need information.
 * @return {Object} Information about the template, including title, description, and icon.
 */
const __experimentalGetTemplateInfo = exports.__experimentalGetTemplateInfo = (0, _data.createRegistrySelector)(select => (0, _data.createSelector)((state, template) => {
  (0, _deprecated.default)("select('core/editor').__experimentalGetTemplateInfo", {
    since: '6.8'
  });
  if (!template) {
    return EMPTY_OBJECT;
  }
  const currentTheme = select(_coreData.store).getCurrentTheme();
  const templateTypes = currentTheme?.default_template_types || [];
  const templateAreas = currentTheme?.default_template_part_areas || [];
  return (0, _getTemplateInfo.getTemplateInfo)({
    template,
    templateAreas,
    templateTypes
  });
}));

/**
 * Returns a post type label depending on the current post.
 *
 * @param {Object} state Global application state.
 *
 * @return {string|undefined} The post type label if available, otherwise undefined.
 */
const getPostTypeLabel = exports.getPostTypeLabel = (0, _data.createRegistrySelector)(select => state => {
  const currentPostType = getCurrentPostType(state);
  const postType = select(_coreData.store).getPostType(currentPostType);
  // Disable reason: Post type labels object is shaped like this.
  // eslint-disable-next-line camelcase
  return postType?.labels?.singular_name;
});

/**
 * Returns true if the publish sidebar is opened.
 *
 * @param {Object} state Global application state
 *
 * @return {boolean} Whether the publish sidebar is open.
 */
function isPublishSidebarOpened(state) {
  return state.publishSidebarActive;
}
//# sourceMappingURL=selectors.js.map