UNPKG

@wordpress/block-editor

Version:
1,606 lines (1,604 loc) 61.8 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; 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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // packages/block-editor/src/store/reducer.js var reducer_exports = {}; __export(reducer_exports, { blockEditingModes: () => blockEditingModes, blockListSettings: () => blockListSettings, blockVisibility: () => blockVisibility, blocks: () => blocks, blocksMode: () => blocksMode, default: () => reducer_default, draggedBlocks: () => draggedBlocks, editedContentOnlySection: () => editedContentOnlySection, expandedBlock: () => expandedBlock, hasBlockSpotlight: () => hasBlockSpotlight, hasSameKeys: () => hasSameKeys, highlightedBlock: () => highlightedBlock, initialPosition: () => initialPosition, insertionCue: () => insertionCue, insertionPoint: () => insertionPoint, isBlockInterfaceHidden: () => isBlockInterfaceHidden, isDragging: () => isDragging, isMultiSelecting: () => isMultiSelecting, isSelectionEnabled: () => isSelectionEnabled, isTyping: () => isTyping, isUpdatingSameBlockAttribute: () => isUpdatingSameBlockAttribute, lastBlockAttributesChange: () => lastBlockAttributesChange, lastBlockInserted: () => lastBlockInserted, lastFocus: () => lastFocus, openedBlockSettingsMenu: () => openedBlockSettingsMenu, preferences: () => preferences, registeredInserterMediaCategories: () => registeredInserterMediaCategories, selection: () => selection, settings: () => settings, styleOverrides: () => styleOverrides, template: () => template, withDerivedBlockEditingModes: () => withDerivedBlockEditingModes, zoomLevel: () => zoomLevel }); module.exports = __toCommonJS(reducer_exports); var import_es6 = __toESM(require("fast-deep-equal/es6")); var import_compose = require("@wordpress/compose"); var import_data = require("@wordpress/data"); var import_deprecated = __toESM(require("@wordpress/deprecated")); var import_blocks = require("@wordpress/blocks"); var import_defaults = require("./defaults"); var import_array = require("./array"); var import_private_keys = require("./private-keys"); var import_lock_unlock = require("../lock-unlock"); var { isContentBlock } = (0, import_lock_unlock.unlock)(import_blocks.privateApis); var identity = (x) => x; function mapBlockOrder(blocks2, rootClientId = "") { const result = /* @__PURE__ */ new Map(); const current = []; result.set(rootClientId, current); blocks2.forEach((block) => { const { clientId, innerBlocks } = block; current.push(clientId); mapBlockOrder(innerBlocks, clientId).forEach( (order, subClientId) => { result.set(subClientId, order); } ); }); return result; } function mapBlockParents(blocks2, rootClientId = "") { const result = []; const stack = [[rootClientId, blocks2]]; while (stack.length) { const [parent, currentBlocks] = stack.shift(); currentBlocks.forEach(({ innerBlocks, ...block }) => { result.push([block.clientId, parent]); if (innerBlocks?.length) { stack.push([block.clientId, innerBlocks]); } }); } return result; } function flattenBlocks(blocks2, transform = identity) { const result = []; const stack = [...blocks2]; while (stack.length) { const { innerBlocks, ...block } = stack.shift(); stack.push(...innerBlocks); result.push([block.clientId, transform(block)]); } return result; } function getFlattenedClientIds(blocks2) { const result = {}; const stack = [...blocks2]; while (stack.length) { const { innerBlocks, ...block } = stack.shift(); stack.push(...innerBlocks); result[block.clientId] = true; } return result; } function getFlattenedBlocksWithoutAttributes(blocks2) { return flattenBlocks(blocks2, (block) => { const { attributes, ...restBlock } = block; return restBlock; }); } function getFlattenedBlockAttributes(blocks2) { return flattenBlocks(blocks2, (block) => block.attributes); } function hasSameKeys(a, b) { return (0, import_es6.default)(Object.keys(a), Object.keys(b)); } function isUpdatingSameBlockAttribute(action, lastAction) { return action.type === "UPDATE_BLOCK_ATTRIBUTES" && lastAction !== void 0 && lastAction.type === "UPDATE_BLOCK_ATTRIBUTES" && (0, import_es6.default)(action.clientIds, lastAction.clientIds) && hasSameKeys(action.attributes, lastAction.attributes); } function updateBlockTreeForBlocks(state, blocks2) { const treeToUpdate = state.tree; const stack = [...blocks2]; const flattenedBlocks = [...blocks2]; while (stack.length) { const block = stack.shift(); stack.push(...block.innerBlocks); flattenedBlocks.push(...block.innerBlocks); } for (const block of flattenedBlocks) { treeToUpdate.set(block.clientId, {}); } for (const block of flattenedBlocks) { treeToUpdate.set( block.clientId, Object.assign(treeToUpdate.get(block.clientId), { ...state.byClientId.get(block.clientId), attributes: state.attributes.get(block.clientId), innerBlocks: block.innerBlocks.map( (subBlock) => treeToUpdate.get(subBlock.clientId) ) }) ); } } function updateParentInnerBlocksInTree(state, updatedClientIds, updateChildrenOfUpdatedClientIds = false) { const treeToUpdate = state.tree; const uncontrolledParents = /* @__PURE__ */ new Set([]); const controlledParents = /* @__PURE__ */ new Set(); for (const clientId of updatedClientIds) { let current = updateChildrenOfUpdatedClientIds ? clientId : state.parents.get(clientId); do { if (state.controlledInnerBlocks[current]) { controlledParents.add(current); break; } else { uncontrolledParents.add(current); current = state.parents.get(current); } } while (current !== void 0); } for (const clientId of uncontrolledParents) { treeToUpdate.set(clientId, { ...treeToUpdate.get(clientId) }); } for (const clientId of uncontrolledParents) { treeToUpdate.get(clientId).innerBlocks = (state.order.get(clientId) || []).map((subClientId) => treeToUpdate.get(subClientId)); } for (const clientId of controlledParents) { treeToUpdate.set("controlled||" + clientId, { innerBlocks: (state.order.get(clientId) || []).map( (subClientId) => treeToUpdate.get(subClientId) ) }); } } var withBlockTree = (reducer) => (state = {}, action) => { const newState = reducer(state, action); if (newState === state) { return state; } newState.tree = state.tree ? state.tree : /* @__PURE__ */ new Map(); switch (action.type) { case "RECEIVE_BLOCKS": case "INSERT_BLOCKS": { newState.tree = new Map(newState.tree); updateBlockTreeForBlocks(newState, action.blocks); updateParentInnerBlocksInTree( newState, action.rootClientId ? [action.rootClientId] : [""], true ); break; } case "UPDATE_BLOCK": newState.tree = new Map(newState.tree); newState.tree.set(action.clientId, { ...newState.tree.get(action.clientId), ...newState.byClientId.get(action.clientId), attributes: newState.attributes.get(action.clientId) }); updateParentInnerBlocksInTree( newState, [action.clientId], false ); break; case "SYNC_DERIVED_BLOCK_ATTRIBUTES": case "UPDATE_BLOCK_ATTRIBUTES": { newState.tree = new Map(newState.tree); action.clientIds.forEach((clientId) => { newState.tree.set(clientId, { ...newState.tree.get(clientId), attributes: newState.attributes.get(clientId) }); }); updateParentInnerBlocksInTree( newState, action.clientIds, false ); break; } case "REPLACE_BLOCKS_AUGMENTED_WITH_CHILDREN": { const inserterClientIds = getFlattenedClientIds( action.blocks ); newState.tree = new Map(newState.tree); action.replacedClientIds.forEach((clientId) => { newState.tree.delete(clientId); if (!inserterClientIds[clientId]) { newState.tree.delete("controlled||" + clientId); } }); updateBlockTreeForBlocks(newState, action.blocks); updateParentInnerBlocksInTree( newState, action.blocks.map((b) => b.clientId), false ); const parentsOfRemovedBlocks2 = []; for (const clientId of action.clientIds) { const parentId = state.parents.get(clientId); if (parentId !== void 0 && (parentId === "" || newState.byClientId.get(parentId))) { parentsOfRemovedBlocks2.push(parentId); } } updateParentInnerBlocksInTree( newState, parentsOfRemovedBlocks2, true ); break; } case "REMOVE_BLOCKS_AUGMENTED_WITH_CHILDREN": const parentsOfRemovedBlocks = []; for (const clientId of action.clientIds) { const parentId = state.parents.get(clientId); if (parentId !== void 0 && (parentId === "" || newState.byClientId.get(parentId))) { parentsOfRemovedBlocks.push(parentId); } } newState.tree = new Map(newState.tree); action.removedClientIds.forEach((clientId) => { newState.tree.delete(clientId); newState.tree.delete("controlled||" + clientId); }); updateParentInnerBlocksInTree( newState, parentsOfRemovedBlocks, true ); break; case "MOVE_BLOCKS_TO_POSITION": { const updatedBlockUids = []; if (action.fromRootClientId) { updatedBlockUids.push(action.fromRootClientId); } else { updatedBlockUids.push(""); } if (action.toRootClientId) { updatedBlockUids.push(action.toRootClientId); } newState.tree = new Map(newState.tree); updateParentInnerBlocksInTree( newState, updatedBlockUids, true ); break; } case "MOVE_BLOCKS_UP": case "MOVE_BLOCKS_DOWN": { const updatedBlockUids = [ action.rootClientId ? action.rootClientId : "" ]; newState.tree = new Map(newState.tree); updateParentInnerBlocksInTree( newState, updatedBlockUids, true ); break; } case "SAVE_REUSABLE_BLOCK_SUCCESS": { const updatedBlockUids = []; newState.attributes.forEach((attributes, clientId) => { if (newState.byClientId.get(clientId).name === "core/block" && attributes.ref === action.updatedId) { updatedBlockUids.push(clientId); } }); newState.tree = new Map(newState.tree); updatedBlockUids.forEach((clientId) => { newState.tree.set(clientId, { ...newState.byClientId.get(clientId), attributes: newState.attributes.get(clientId), innerBlocks: newState.tree.get(clientId).innerBlocks }); }); updateParentInnerBlocksInTree( newState, updatedBlockUids, false ); } } return newState; }; function withPersistentBlockChange(reducer) { let lastAction; let markNextChangeAsNotPersistent = false; let explicitPersistent; return (state, action) => { let nextState = reducer(state, action); let nextIsPersistentChange; if (action.type === "SET_EXPLICIT_PERSISTENT") { explicitPersistent = action.isPersistentChange; nextIsPersistentChange = state.isPersistentChange ?? true; } if (explicitPersistent !== void 0) { nextIsPersistentChange = explicitPersistent; return nextIsPersistentChange === nextState.isPersistentChange ? nextState : { ...nextState, isPersistentChange: nextIsPersistentChange }; } const isExplicitPersistentChange = action.type === "MARK_LAST_CHANGE_AS_PERSISTENT" || markNextChangeAsNotPersistent; if (state === nextState && !isExplicitPersistentChange) { markNextChangeAsNotPersistent = action.type === "MARK_NEXT_CHANGE_AS_NOT_PERSISTENT"; nextIsPersistentChange = state?.isPersistentChange ?? true; if (state.isPersistentChange === nextIsPersistentChange) { return state; } return { ...nextState, isPersistentChange: nextIsPersistentChange }; } nextState = { ...nextState, isPersistentChange: isExplicitPersistentChange ? !markNextChangeAsNotPersistent : !isUpdatingSameBlockAttribute(action, lastAction) }; lastAction = action; markNextChangeAsNotPersistent = action.type === "MARK_NEXT_CHANGE_AS_NOT_PERSISTENT"; return nextState; }; } function withIgnoredBlockChange(reducer) { const IGNORED_ACTION_TYPES = /* @__PURE__ */ new Set(["RECEIVE_BLOCKS"]); return (state, action) => { const nextState = reducer(state, action); if (nextState !== state) { nextState.isIgnoredChange = IGNORED_ACTION_TYPES.has(action.type); } return nextState; }; } var withInnerBlocksRemoveCascade = (reducer) => (state, action) => { const getAllChildren = (clientIds) => { let result = clientIds; for (let i = 0; i < result.length; i++) { if (!state.order.get(result[i]) || action.keepControlledInnerBlocks && action.keepControlledInnerBlocks[result[i]]) { continue; } if (result === clientIds) { result = [...result]; } result.push(...state.order.get(result[i])); } return result; }; if (state) { switch (action.type) { case "REMOVE_BLOCKS": action = { ...action, type: "REMOVE_BLOCKS_AUGMENTED_WITH_CHILDREN", removedClientIds: getAllChildren(action.clientIds) }; break; case "REPLACE_BLOCKS": action = { ...action, type: "REPLACE_BLOCKS_AUGMENTED_WITH_CHILDREN", replacedClientIds: getAllChildren(action.clientIds) }; break; } } return reducer(state, action); }; var withBlockReset = (reducer) => (state, action) => { if (action.type === "RESET_BLOCKS") { const newState = { ...state, byClientId: new Map( getFlattenedBlocksWithoutAttributes(action.blocks) ), attributes: new Map(getFlattenedBlockAttributes(action.blocks)), order: mapBlockOrder(action.blocks), parents: new Map(mapBlockParents(action.blocks)), controlledInnerBlocks: {} }; newState.tree = new Map(state?.tree); updateBlockTreeForBlocks(newState, action.blocks); newState.tree.set("", { innerBlocks: action.blocks.map( (subBlock) => newState.tree.get(subBlock.clientId) ) }); return newState; } return reducer(state, action); }; var withReplaceInnerBlocks = (reducer) => (state, action) => { if (action.type !== "REPLACE_INNER_BLOCKS") { return reducer(state, action); } const nestedControllers = {}; if (Object.keys(state.controlledInnerBlocks).length) { const stack = [...action.blocks]; while (stack.length) { const { innerBlocks, ...block } = stack.shift(); stack.push(...innerBlocks); if (!!state.controlledInnerBlocks[block.clientId]) { nestedControllers[block.clientId] = true; } } } let stateAfterBlocksRemoval = state; if (state.order.get(action.rootClientId)) { stateAfterBlocksRemoval = reducer(stateAfterBlocksRemoval, { type: "REMOVE_BLOCKS", keepControlledInnerBlocks: nestedControllers, clientIds: state.order.get(action.rootClientId) }); } let stateAfterInsert = stateAfterBlocksRemoval; if (action.blocks.length) { stateAfterInsert = reducer(stateAfterInsert, { ...action, type: "INSERT_BLOCKS", index: 0 }); const stateAfterInsertOrder = new Map(stateAfterInsert.order); Object.keys(nestedControllers).forEach((key) => { if (state.order.get(key)) { stateAfterInsertOrder.set(key, state.order.get(key)); } }); stateAfterInsert.order = stateAfterInsertOrder; stateAfterInsert.tree = new Map(stateAfterInsert.tree); Object.keys(nestedControllers).forEach((_key) => { const key = `controlled||${_key}`; if (state.tree.has(key)) { stateAfterInsert.tree.set(key, state.tree.get(key)); } }); } return stateAfterInsert; }; var withSaveReusableBlock = (reducer) => (state, action) => { if (state && action.type === "SAVE_REUSABLE_BLOCK_SUCCESS") { const { id, updatedId } = action; if (id === updatedId) { return state; } state = { ...state }; state.attributes = new Map(state.attributes); state.attributes.forEach((attributes, clientId) => { const { name } = state.byClientId.get(clientId); if (name === "core/block" && attributes.ref === id) { state.attributes.set(clientId, { ...attributes, ref: updatedId }); } }); } return reducer(state, action); }; var withResetControlledBlocks = (reducer) => (state, action) => { if (action.type === "SET_HAS_CONTROLLED_INNER_BLOCKS") { const tempState = reducer(state, { type: "REPLACE_INNER_BLOCKS", rootClientId: action.clientId, blocks: [] }); return reducer(tempState, action); } return reducer(state, action); }; var blocks = (0, import_compose.pipe)( import_data.combineReducers, withSaveReusableBlock, // Needs to be before withBlockCache. withBlockTree, // Needs to be before withInnerBlocksRemoveCascade. withInnerBlocksRemoveCascade, withReplaceInnerBlocks, // Needs to be after withInnerBlocksRemoveCascade. withBlockReset, withPersistentBlockChange, withIgnoredBlockChange, withResetControlledBlocks )({ // The state is using a Map instead of a plain object for performance reasons. // You can run the "./test/performance.js" unit test to check the impact // code changes can have on this reducer. byClientId(state = /* @__PURE__ */ new Map(), action) { switch (action.type) { case "RECEIVE_BLOCKS": case "INSERT_BLOCKS": { const newState = new Map(state); getFlattenedBlocksWithoutAttributes(action.blocks).forEach( ([key, value]) => { newState.set(key, value); } ); return newState; } case "UPDATE_BLOCK": { if (!state.has(action.clientId)) { return state; } const { attributes, ...changes } = action.updates; if (Object.values(changes).length === 0) { return state; } const newState = new Map(state); newState.set(action.clientId, { ...state.get(action.clientId), ...changes }); return newState; } case "REPLACE_BLOCKS_AUGMENTED_WITH_CHILDREN": { if (!action.blocks) { return state; } const newState = new Map(state); action.replacedClientIds.forEach((clientId) => { newState.delete(clientId); }); getFlattenedBlocksWithoutAttributes(action.blocks).forEach( ([key, value]) => { newState.set(key, value); } ); return newState; } case "REMOVE_BLOCKS_AUGMENTED_WITH_CHILDREN": { const newState = new Map(state); action.removedClientIds.forEach((clientId) => { newState.delete(clientId); }); return newState; } } return state; }, // The state is using a Map instead of a plain object for performance reasons. // You can run the "./test/performance.js" unit test to check the impact // code changes can have on this reducer. attributes(state = /* @__PURE__ */ new Map(), action) { switch (action.type) { case "RECEIVE_BLOCKS": case "INSERT_BLOCKS": { const newState = new Map(state); getFlattenedBlockAttributes(action.blocks).forEach( ([key, value]) => { newState.set(key, value); } ); return newState; } case "UPDATE_BLOCK": { if (!state.get(action.clientId) || !action.updates.attributes) { return state; } const newState = new Map(state); newState.set(action.clientId, { ...state.get(action.clientId), ...action.updates.attributes }); return newState; } case "SYNC_DERIVED_BLOCK_ATTRIBUTES": case "UPDATE_BLOCK_ATTRIBUTES": { if (action.clientIds.every((id) => !state.get(id))) { return state; } let hasChange = false; const newState = new Map(state); for (const clientId of action.clientIds) { const updatedAttributeEntries = Object.entries( !!action.options?.uniqueByBlock ? action.attributes[clientId] : action.attributes ?? {} ); if (updatedAttributeEntries.length === 0) { continue; } let hasUpdatedAttributes = false; const existingAttributes = state.get(clientId); const newAttributes = {}; updatedAttributeEntries.forEach(([key, value]) => { if (existingAttributes[key] !== value) { hasUpdatedAttributes = true; newAttributes[key] = value; } }); hasChange = hasChange || hasUpdatedAttributes; if (hasUpdatedAttributes) { newState.set(clientId, { ...existingAttributes, ...newAttributes }); } } return hasChange ? newState : state; } case "REPLACE_BLOCKS_AUGMENTED_WITH_CHILDREN": { if (!action.blocks) { return state; } const newState = new Map(state); action.replacedClientIds.forEach((clientId) => { newState.delete(clientId); }); getFlattenedBlockAttributes(action.blocks).forEach( ([key, value]) => { newState.set(key, value); } ); return newState; } case "REMOVE_BLOCKS_AUGMENTED_WITH_CHILDREN": { const newState = new Map(state); action.removedClientIds.forEach((clientId) => { newState.delete(clientId); }); return newState; } } return state; }, // The state is using a Map instead of a plain object for performance reasons. // You can run the "./test/performance.js" unit test to check the impact // code changes can have on this reducer. order(state = /* @__PURE__ */ new Map(), action) { switch (action.type) { case "RECEIVE_BLOCKS": { const blockOrder = mapBlockOrder(action.blocks); const newState = new Map(state); blockOrder.forEach((order, clientId) => { if (clientId !== "") { newState.set(clientId, order); } }); newState.set( "", (state.get("") ?? []).concat(blockOrder[""]) ); return newState; } case "INSERT_BLOCKS": { const { rootClientId = "" } = action; const subState = state.get(rootClientId) || []; const mappedBlocks = mapBlockOrder( action.blocks, rootClientId ); const { index = subState.length } = action; const newState = new Map(state); mappedBlocks.forEach((order, clientId) => { newState.set(clientId, order); }); newState.set( rootClientId, (0, import_array.insertAt)( subState, mappedBlocks.get(rootClientId), index ) ); return newState; } case "MOVE_BLOCKS_TO_POSITION": { const { fromRootClientId = "", toRootClientId = "", clientIds } = action; const { index = state.get(toRootClientId).length } = action; if (fromRootClientId === toRootClientId) { const subState = state.get(toRootClientId); const fromIndex = subState.indexOf(clientIds[0]); const newState2 = new Map(state); newState2.set( toRootClientId, (0, import_array.moveTo)( state.get(toRootClientId), fromIndex, index, clientIds.length ) ); return newState2; } const newState = new Map(state); newState.set( fromRootClientId, state.get(fromRootClientId)?.filter((id) => !clientIds.includes(id)) ?? [] ); newState.set( toRootClientId, (0, import_array.insertAt)(state.get(toRootClientId), clientIds, index) ); return newState; } case "MOVE_BLOCKS_UP": { const { clientIds, rootClientId = "" } = action; const firstClientId = clientIds[0]; const subState = state.get(rootClientId); if (!subState.length || firstClientId === subState[0]) { return state; } const firstIndex = subState.indexOf(firstClientId); const newState = new Map(state); newState.set( rootClientId, (0, import_array.moveTo)( subState, firstIndex, firstIndex - 1, clientIds.length ) ); return newState; } case "MOVE_BLOCKS_DOWN": { const { clientIds, rootClientId = "" } = action; const firstClientId = clientIds[0]; const lastClientId = clientIds[clientIds.length - 1]; const subState = state.get(rootClientId); if (!subState.length || lastClientId === subState[subState.length - 1]) { return state; } const firstIndex = subState.indexOf(firstClientId); const newState = new Map(state); newState.set( rootClientId, (0, import_array.moveTo)( subState, firstIndex, firstIndex + 1, clientIds.length ) ); return newState; } case "REPLACE_BLOCKS_AUGMENTED_WITH_CHILDREN": { const { clientIds } = action; if (!action.blocks) { return state; } const mappedBlocks = mapBlockOrder(action.blocks); const newState = new Map(state); action.replacedClientIds.forEach((clientId) => { newState.delete(clientId); }); mappedBlocks.forEach((order, clientId) => { if (clientId !== "") { newState.set(clientId, order); } }); newState.forEach((order, clientId) => { const newSubOrder = Object.values(order).reduce( (result, subClientId) => { if (subClientId === clientIds[0]) { return [...result, ...mappedBlocks.get("")]; } if (clientIds.indexOf(subClientId) === -1) { result.push(subClientId); } return result; }, [] ); newState.set(clientId, newSubOrder); }); return newState; } case "REMOVE_BLOCKS_AUGMENTED_WITH_CHILDREN": { const newState = new Map(state); action.removedClientIds.forEach((clientId) => { newState.delete(clientId); }); newState.forEach((order, clientId) => { const newSubOrder = order?.filter( (id) => !action.removedClientIds.includes(id) ) ?? []; if (newSubOrder.length !== order.length) { newState.set(clientId, newSubOrder); } }); return newState; } } return state; }, // While technically redundant data as the inverse of `order`, it serves as // an optimization for the selectors which derive the ancestry of a block. parents(state = /* @__PURE__ */ new Map(), action) { switch (action.type) { case "RECEIVE_BLOCKS": { const newState = new Map(state); mapBlockParents(action.blocks).forEach( ([key, value]) => { newState.set(key, value); } ); return newState; } case "INSERT_BLOCKS": { const newState = new Map(state); mapBlockParents( action.blocks, action.rootClientId || "" ).forEach(([key, value]) => { newState.set(key, value); }); return newState; } case "MOVE_BLOCKS_TO_POSITION": { const newState = new Map(state); action.clientIds.forEach((id) => { newState.set(id, action.toRootClientId || ""); }); return newState; } case "REPLACE_BLOCKS_AUGMENTED_WITH_CHILDREN": { const newState = new Map(state); action.replacedClientIds.forEach((clientId) => { newState.delete(clientId); }); mapBlockParents( action.blocks, state.get(action.clientIds[0]) ).forEach(([key, value]) => { newState.set(key, value); }); return newState; } case "REMOVE_BLOCKS_AUGMENTED_WITH_CHILDREN": { const newState = new Map(state); action.removedClientIds.forEach((clientId) => { newState.delete(clientId); }); return newState; } } return state; }, controlledInnerBlocks(state = {}, { type, clientId, hasControlledInnerBlocks }) { if (type === "SET_HAS_CONTROLLED_INNER_BLOCKS") { return { ...state, [clientId]: hasControlledInnerBlocks }; } return state; } }); function isBlockInterfaceHidden(state = false, action) { switch (action.type) { case "HIDE_BLOCK_INTERFACE": return true; case "SHOW_BLOCK_INTERFACE": return false; } return state; } function isTyping(state = false, action) { switch (action.type) { case "START_TYPING": return true; case "STOP_TYPING": return false; } return state; } function isDragging(state = false, action) { switch (action.type) { case "START_DRAGGING": return true; case "STOP_DRAGGING": return false; } return state; } function draggedBlocks(state = [], action) { switch (action.type) { case "START_DRAGGING_BLOCKS": return action.clientIds; case "STOP_DRAGGING_BLOCKS": return []; } return state; } function blockVisibility(state = {}, action) { if (action.type === "SET_BLOCK_VISIBILITY") { return { ...state, ...action.updates }; } return state; } function selectionHelper(state = {}, action) { switch (action.type) { case "CLEAR_SELECTED_BLOCK": { if (state.clientId) { return {}; } return state; } case "SELECT_BLOCK": if (action.clientId === state.clientId) { return state; } return { clientId: action.clientId }; case "REPLACE_INNER_BLOCKS": case "INSERT_BLOCKS": { if (!action.updateSelection || !action.blocks.length) { return state; } return { clientId: action.blocks[0].clientId }; } case "REMOVE_BLOCKS": if (!action.clientIds || !action.clientIds.length || action.clientIds.indexOf(state.clientId) === -1) { return state; } return {}; case "REPLACE_BLOCKS": { if (action.clientIds.indexOf(state.clientId) === -1) { return state; } const blockToSelect = action.blocks[action.indexToSelect] || action.blocks[action.blocks.length - 1]; if (!blockToSelect) { return {}; } if (blockToSelect.clientId === state.clientId) { return state; } return { clientId: blockToSelect.clientId }; } } return state; } function selection(state = {}, action) { switch (action.type) { case "SELECTION_CHANGE": if (action.clientId) { return { selectionStart: { clientId: action.clientId, attributeKey: action.attributeKey, offset: action.startOffset }, selectionEnd: { clientId: action.clientId, attributeKey: action.attributeKey, offset: action.endOffset } }; } return { selectionStart: action.start || state.selectionStart, selectionEnd: action.end || state.selectionEnd }; case "RESET_SELECTION": const { selectionStart: selectionStart2, selectionEnd: selectionEnd2 } = action; return { selectionStart: selectionStart2, selectionEnd: selectionEnd2 }; case "MULTI_SELECT": const { start, end } = action; if (start === state.selectionStart?.clientId && end === state.selectionEnd?.clientId) { return state; } return { selectionStart: { clientId: start }, selectionEnd: { clientId: end } }; case "RESET_BLOCKS": const startClientId = state?.selectionStart?.clientId; const endClientId = state?.selectionEnd?.clientId; if (!startClientId && !endClientId) { return state; } if (!action.blocks.some( (block) => block.clientId === startClientId )) { return { selectionStart: {}, selectionEnd: {} }; } if (!action.blocks.some( (block) => block.clientId === endClientId )) { return { ...state, selectionEnd: state.selectionStart }; } } const selectionStart = selectionHelper(state.selectionStart, action); const selectionEnd = selectionHelper(state.selectionEnd, action); if (selectionStart === state.selectionStart && selectionEnd === state.selectionEnd) { return state; } return { selectionStart, selectionEnd }; } function isMultiSelecting(state = false, action) { switch (action.type) { case "START_MULTI_SELECT": return true; case "STOP_MULTI_SELECT": return false; } return state; } function isSelectionEnabled(state = true, action) { switch (action.type) { case "TOGGLE_SELECTION": return action.isSelectionEnabled; } return state; } function removalPromptData(state = false, action) { switch (action.type) { case "DISPLAY_BLOCK_REMOVAL_PROMPT": const { clientIds, selectPrevious, message } = action; return { clientIds, selectPrevious, message }; case "CLEAR_BLOCK_REMOVAL_PROMPT": return false; } return state; } function blockRemovalRules(state = false, action) { switch (action.type) { case "SET_BLOCK_REMOVAL_RULES": return action.rules; } return state; } function initialPosition(state = null, action) { if (action.type === "REPLACE_BLOCKS" && action.initialPosition !== void 0) { return action.initialPosition; } else if ([ "MULTI_SELECT", "SELECT_BLOCK", "RESET_SELECTION", "INSERT_BLOCKS", "REPLACE_INNER_BLOCKS" ].includes(action.type)) { return action.initialPosition; } return state; } function blocksMode(state = {}, action) { if (action.type === "TOGGLE_BLOCK_MODE") { const { clientId } = action; return { ...state, [clientId]: state[clientId] && state[clientId] === "html" ? "visual" : "html" }; } return state; } function insertionCue(state = null, action) { switch (action.type) { case "SHOW_INSERTION_POINT": { const { rootClientId, index, __unstableWithInserter, operation, nearestSide } = action; const nextState = { rootClientId, index, __unstableWithInserter, operation, nearestSide }; return (0, import_es6.default)(state, nextState) ? state : nextState; } case "HIDE_INSERTION_POINT": return null; } return state; } function template(state = { isValid: true }, action) { switch (action.type) { case "SET_TEMPLATE_VALIDITY": return { ...state, isValid: action.isValid }; } return state; } function settings(state = import_defaults.SETTINGS_DEFAULTS, action) { switch (action.type) { case "UPDATE_SETTINGS": { const updatedSettings = action.reset ? { ...import_defaults.SETTINGS_DEFAULTS, ...action.settings } : { ...state, ...action.settings }; Object.defineProperty(updatedSettings, "__unstableIsPreviewMode", { get() { (0, import_deprecated.default)("__unstableIsPreviewMode", { since: "6.8", alternative: "isPreviewMode" }); return this.isPreviewMode; } }); return updatedSettings; } } return state; } function preferences(state = import_defaults.PREFERENCES_DEFAULTS, action) { switch (action.type) { case "INSERT_BLOCKS": case "REPLACE_BLOCKS": { const nextInsertUsage = action.blocks.reduce( (prevUsage, block) => { const { attributes, name: blockName } = block; let id = blockName; const match = (0, import_data.select)(import_blocks.store).getActiveBlockVariation( blockName, attributes ); if (match?.name) { id += "/" + match.name; } if (blockName === "core/block") { id += "/" + attributes.ref; } return { ...prevUsage, [id]: { time: action.time, count: prevUsage[id] ? prevUsage[id].count + 1 : 1 } }; }, state.insertUsage ); return { ...state, insertUsage: nextInsertUsage }; } } return state; } var blockListSettings = (state = {}, action) => { switch (action.type) { // Even if the replaced blocks have the same client ID, our logic // should correct the state. case "REPLACE_BLOCKS": case "REMOVE_BLOCKS": { return Object.fromEntries( Object.entries(state).filter( ([id]) => !action.clientIds.includes(id) ) ); } case "UPDATE_BLOCK_LIST_SETTINGS": { const updates = typeof action.clientId === "string" ? { [action.clientId]: action.settings } : action.clientId; for (const clientId in updates) { if (!updates[clientId]) { if (!state[clientId]) { delete updates[clientId]; } } else if ((0, import_es6.default)(state[clientId], updates[clientId])) { delete updates[clientId]; } } if (Object.keys(updates).length === 0) { return state; } const merged = { ...state, ...updates }; for (const clientId in updates) { if (!updates[clientId]) { delete merged[clientId]; } } return merged; } } return state; }; function lastBlockAttributesChange(state = null, action) { switch (action.type) { case "UPDATE_BLOCK": if (!action.updates.attributes) { break; } return { [action.clientId]: action.updates.attributes }; case "UPDATE_BLOCK_ATTRIBUTES": return action.clientIds.reduce( (accumulator, id) => ({ ...accumulator, [id]: !!action.options?.uniqueByBlock ? action.attributes[id] : action.attributes }), {} ); } return state; } function highlightedBlock(state, action) { switch (action.type) { case "TOGGLE_BLOCK_HIGHLIGHT": const { clientId, isHighlighted } = action; if (isHighlighted) { return clientId; } else if (state === clientId) { return null; } return state; case "SELECT_BLOCK": if (action.clientId !== state) { return null; } } return state; } function hasBlockSpotlight(state, action) { switch (action.type) { case "TOGGLE_BLOCK_SPOTLIGHT": const { clientId, hasBlockSpotlight: _hasBlockSpotlight } = action; if (_hasBlockSpotlight) { return clientId; } else if (state === clientId) { return null; } return state; case "SELECT_BLOCK": if (action.clientId !== state) { return null; } return state; case "SELECTION_CHANGE": if (action.start?.clientId !== state || action.end?.clientId !== state) { return null; } return state; case "CLEAR_SELECTED_BLOCK": return null; } return state; } function expandedBlock(state = null, action) { switch (action.type) { case "SET_BLOCK_EXPANDED_IN_LIST_VIEW": return action.clientId; case "SELECT_BLOCK": if (action.clientId !== state) { return null; } } return state; } function lastBlockInserted(state = {}, action) { switch (action.type) { case "INSERT_BLOCKS": case "REPLACE_BLOCKS": if (!action.blocks.length) { return state; } const clientIds = action.blocks.map((block) => { return block.clientId; }); const source = action.meta?.source; return { clientIds, source }; case "RESET_BLOCKS": return {}; } return state; } function editedContentOnlySection(state, action) { if (action.type === "EDIT_CONTENT_ONLY_SECTION") { return action.clientId; } return state; } function blockEditingModes(state = /* @__PURE__ */ new Map(), action) { switch (action.type) { case "SET_BLOCK_EDITING_MODE": if (state.get(action.clientId) === action.mode) { return state; } return new Map(state).set(action.clientId, action.mode); case "UNSET_BLOCK_EDITING_MODE": { if (!state.has(action.clientId)) { return state; } const newState = new Map(state); newState.delete(action.clientId); return newState; } case "RESET_BLOCKS": { return state.has("") ? (/* @__PURE__ */ new Map()).set("", state.get("")) : state; } } return state; } function openedBlockSettingsMenu(state = null, action) { if ("SET_OPENED_BLOCK_SETTINGS_MENU" === action.type) { return action?.clientId ?? null; } return state; } function styleOverrides(state = /* @__PURE__ */ new Map(), action) { switch (action.type) { case "SET_STYLE_OVERRIDE": return new Map(state).set(action.id, action.style); case "DELETE_STYLE_OVERRIDE": { const newState = new Map(state); newState.delete(action.id); return newState; } } return state; } function registeredInserterMediaCategories(state = [], action) { switch (action.type) { case "REGISTER_INSERTER_MEDIA_CATEGORY": return [...state, action.category]; } return state; } function lastFocus(state = false, action) { switch (action.type) { case "LAST_FOCUS": return action.lastFocus; } return state; } function zoomLevel(state = 100, action) { switch (action.type) { case "SET_ZOOM_LEVEL": return action.zoom; case "RESET_ZOOM_LEVEL": return 100; } return state; } function insertionPoint(state = null, action) { switch (action.type) { case "SET_INSERTION_POINT": return action.value; case "SELECT_BLOCK": return null; } return state; } var combinedReducers = (0, import_data.combineReducers)({ blocks, isDragging, isTyping, isBlockInterfaceHidden, draggedBlocks, selection, isMultiSelecting, isSelectionEnabled, initialPosition, blocksMode, blockListSettings, insertionPoint, insertionCue, template, settings, preferences, lastBlockAttributesChange, lastFocus, expandedBlock, highlightedBlock, lastBlockInserted, editedContentOnlySection, blockVisibility, blockEditingModes, styleOverrides, removalPromptData, blockRemovalRules, openedBlockSettingsMenu, registeredInserterMediaCategories, zoomLevel, hasBlockSpotlight }); function getBlockTreeBlock(state, clientId) { if (clientId === "") { const rootBlock = state.blocks.tree.get(clientId); if (!rootBlock) { return; } return { clientId: "", ...rootBlock }; } if (!state.blocks.controlledInnerBlocks[clientId]) { return state.blocks.tree.get(clientId); } const controlledTree = state.blocks.tree.get(`controlled||${clientId}`); const regularTree = state.blocks.tree.get(clientId); return { ...regularTree, innerBlocks: controlledTree?.innerBlocks }; } function traverseBlockTree(state, clientId, callback) { const tree = getBlockTreeBlock(state, clientId); if (!tree) { return; } callback(tree); if (!tree?.innerBlocks?.length) { return; } for (const innerBlock of tree?.innerBlocks) { traverseBlockTree(state, innerBlock.clientId, callback); } } function findParentInClientIdsList(state, clientId, clientIds) { if (!clientIds.length) { return; } let parent = state.blocks.parents.get(clientId); while (parent !== void 0) { if (clientIds.includes(parent)) { return parent; } parent = state.blocks.parents.get(parent); } } function hasBindings(block) { return block?.attributes?.metadata?.bindings && Object.keys(block?.attributes?.metadata?.bindings).length; } function getDerivedBlockEditingModesForTree(state, treeClientId = "") { const isZoomedOut = state?.zoomLevel < 100 || state?.zoomLevel === "auto-scaled"; const derivedBlockEditingModes = /* @__PURE__ */ new Map(); const sectionRootClientId = state.settings?.[import_private_keys.sectionRootClientIdKey]; const sectionClientIds = state.blocks.order.get(sectionRootClientId); const hasDisabledBlocks = Array.from(state.blockEditingModes).some( ([, mode]) => mode === "disabled" ); const templatePartClientIds = []; const syncedPatternClientIds = []; Object.keys(state.blocks.controlledInnerBlocks).forEach((clientId) => { const block = state.blocks.byClientId?.get(clientId); if (block?.name === "core/template-part") { templatePartClientIds.push(clientId); } if (block?.name === "core/block") { syncedPatternClientIds.push(clientId); } }); const contentOnlyTemplateLockedClientIds = Object.keys( state.blockListSettings ).filter( (clientId) => state.blockListSettings[clientId]?.templateLock === "contentOnly" ); const isIsolatedEditor = state.settings?.[import_private_keys.isIsolatedEditorKey]; const unsyncedPatternClientIds = !!window?.__experimentalContentOnlyPatternInsertion && !isIsolatedEditor ? Array.from(state.blocks.attributes.keys()).filter( (clientId) => state.blocks.attributes.get(clientId)?.metadata?.patternName ) : []; const contentOnlyParents = [ ...contentOnlyTemplateLockedClientIds, ...unsyncedPatternClientIds, ...window?.__experimentalContentOnlyPatternInsertion && !isIsolatedEditor ? templatePartClientIds : [] ]; traverseBlockTree(state, treeClientId, (block) => { const { clientId, name: blockName } = block; if (state.editedContentOnlySection) { if (state.editedContentOnlySection === clientId) { derivedBlockEditingModes.set(clientId, "default"); return; } const parentTempEditedClientId = findParentInClientIdsList( state, clientId, [state.editedContentOnlySection] ); if (parentTempEditedClientId) { derivedBlockEditingModes.set(clientId, "default"); return; } if (window?.__experimentalContentOnlyPatternInsertion) { derivedBlockEditingModes.set(clientId, "disabled"); return; } } if (state.blockEditingModes.has(clientId)) { return; } if (hasDisabledBlocks) { let ancestorBlockEditingMode; let parent = state.blocks.parents.get(clientId); while (parent !== void 0) { if (state.blockEditingModes.has(parent)) { ancestorBlockEditingMode = state.blockEditingModes.get(parent); } if (ancestorBlockEditingMode) { break; } parent = state.blocks.parents.get(parent); } if (ancestorBlockEditingMode === "disabled") { derivedBlockEditingModes.set(clientId, "disabled"); return; } } if (isZoomedOut) { if (clientId === sectionRootClientId) { derivedBlockEditingModes.set(clientId, "contentOnly"); return; } if (!sectionClientIds?.length) { derivedBlockEditingModes.set(clientId, "disabled"); return; } if (sectionClientIds.includes(clientId)) { derivedBlockEditingModes.set(clientId, "contentOnly"); return; } derivedBlockEditingModes.set(clientId, "disabled"); return; } if (syncedPatternClientIds.length) { if (syncedPatternClientIds.includes(clientId)) { if (findParentInClientIdsList( state, clientId, syncedPatternClientIds )) {