var _excluded = ["x", "y", "zIndex", "width", "height"];
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
/**
 * 平面图编辑态：草稿配置、画布 Tab、选中、放置模式、落点、侧栏更新/删除/保存记录
 */
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { message } from 'antd';
import { locales } from '@pisell/utils';
import useEngineContext from "../../../hooks/useEngineContext";
import { createTranslationText } from "../../translation/utils";
import { mergeCanvasItems } from "../utils/floorMapConfigMerge";
import { STAGE_DECO_DEFAULT } from "../utils/floorMapStageDefaults";
import { useDraftConfigHistory } from "./useDraftConfigHistory";
import { floorMapViewConfigsEqual, normalizeFloorMapViewConfigFromProp } from "../utils/floorMapViewConfigDiff";
import { FLOOR_MAP_RESOURCE_PLACE_DEFAULT, getElementKindConfig, resolveDataBindingPolicy, isFloorMapBuiltinShapeElementKind, isFloorMapImageElementKind } from "../utils/floorMapElementKindUtils";
import { FLOOR_MAP_BUILTIN_SHAPES, getFloorMapBuiltinShapeDef } from "../utils/floorMapBuiltinShapes";
import { DEFAULT_CELL_SIZE, gapToPx } from "../utils/layoutMeasurements";
import { computeFloorMapContentStage } from "../utils/floorMapCanvasStage";
import { computeBatchScenePlacementPositions, getPlacementBoundingBox } from "../utils/batchScenePlacementLayout";
import { DEFAULT_BOUNDING_PADDING } from "./floorMapViewportPersistence";
import { FLOOR_MAP_STAGE_ELEMENT_KIND, FLOOR_MAP_SELECTION_ZONE_ELEMENT_KIND } from "../types";
import { getFloorMapDisplayLocale, initFloorMapLayoutLocales } from "../utils/floorMapCanvasDisplay";
var IMAGE_PLACE_DEFAULT = {
  width: 400,
  height: 240
};
/** 内置图形落点缺省尺寸（落点时若已选 builtinShapeKey 会按预设 defaultSize 替换） */
var BUILTIN_SHAPE_PLACE_DEFAULT = {
  width: 96,
  height: 96
};
var I18N_PLACEMENT_FALLBACK_IMAGE = 'pisell-floor-map-layout.placement.fallback-image-name';
var I18N_PLACEMENT_SELECTION_ZONE_NAME = 'pisell-floor-map-layout.selection-zone.unnamed';
var SELECTION_ZONE_PLACE_DEFAULT = {
  width: 320,
  height: 240
};
var GRID_VIS_STORAGE_PREFIX = 'pisell-floor-map-layout.grid-visible';

/**
 * 网格显隐缓存 key：可选 `namespace`（通常拼自业务/门店/平面图，与视口 `viewportPersistNamespace`
 * 同源）用于隔离不同场景。未传 namespace 时保持原 `prefix:canvasId`，向后兼容。
 */
function getGridVisStorageKey(canvasId, namespace) {
  return namespace ? "".concat(GRID_VIS_STORAGE_PREFIX, ":").concat(namespace, ":").concat(canvasId) : "".concat(GRID_VIS_STORAGE_PREFIX, ":").concat(canvasId);
}
function readStoredGridVisible(canvasId, namespace) {
  try {
    var raw = localStorage.getItem(getGridVisStorageKey(canvasId, namespace));
    if (raw == null) return null;
    if (raw === '1') return true;
    if (raw === '0') return false;
    return null;
  } catch (_unused) {
    return null;
  }
}
function writeStoredGridVisible(canvasId, visible, namespace) {
  try {
    localStorage.setItem(getGridVisStorageKey(canvasId, namespace), visible ? '1' : '0');
  } catch (_unused2) {
    // ignore localStorage failure (private mode / quota / sandbox)
  }
}

/** 与 props 同步 / dirty 基线一致：合并 localStorage 中的网格显隐偏好 */
function normalizeFloorMapConfigWithStoredGrid(floorMapConfigProp, namespace) {
  var baseConfig = normalizeFloorMapViewConfigFromProp(floorMapConfigProp);
  return _objectSpread(_objectSpread({}, baseConfig), {}, {
    canvases: baseConfig.canvases.map(function (canvas) {
      var _canvas$mapLayer;
      var stored = readStoredGridVisible(canvas.id, namespace);
      if (stored == null) return canvas;
      return _objectSpread(_objectSpread({}, canvas), {}, {
        mapLayer: _objectSpread(_objectSpread({}, (_canvas$mapLayer = canvas.mapLayer) !== null && _canvas$mapLayer !== void 0 ? _canvas$mapLayer : {}), {}, {
          showGrid: stored
        })
      });
    })
  });
}

/** 复制单个图元时的错位偏移（内容坐标） */
var DUPLICATE_PLACE_OFFSET = 16;
function newInstanceId() {
  return "elm_".concat(Date.now(), "_").concat(Math.random().toString(36).slice(2, 9));
}
function duplicateBinding(elements, binding, exceptInstanceId) {
  return (elements !== null && elements !== void 0 ? elements : []).some(function (e) {
    var _e$dataBinding, _e$dataBinding2;
    return e.instanceId !== exceptInstanceId && ((_e$dataBinding = e.dataBinding) === null || _e$dataBinding === void 0 ? void 0 : _e$dataBinding.dataSourceKey) === binding.dataSourceKey && ((_e$dataBinding2 = e.dataBinding) === null || _e$dataBinding2 === void 0 ? void 0 : _e$dataBinding2.recordId) === binding.recordId;
  });
}
/** 解析落点图元的默认像素尺寸（与 applyScenePlacementAtCoords 一致） */
function resolveScenePlacementDimensions(config, scene) {
  var _scene$builtinShapeKe, _FLOOR_MAP_BUILTIN_SH, _builtinDef$defaultSi, _builtinDef$defaultSi2;
  var defaultPlacementWidth = FLOOR_MAP_RESOURCE_PLACE_DEFAULT.width;
  var defaultPlacementHeight = FLOOR_MAP_RESOURCE_PLACE_DEFAULT.height;
  var defaultDecoSize = 48;
  var kindConfig = getElementKindConfig(config, scene.elementKind);
  var policy = resolveDataBindingPolicy(kindConfig);
  var isStage = scene.elementKind === FLOOR_MAP_STAGE_ELEMENT_KIND;
  var isSelectionZone = scene.elementKind === FLOOR_MAP_SELECTION_ZONE_ELEMENT_KIND;
  var isImage = isFloorMapImageElementKind(scene.elementKind);
  var isBuiltinShape = isFloorMapBuiltinShapeElementKind(scene.elementKind);
  var initialBuiltinShapeKey = isBuiltinShape ? (_scene$builtinShapeKe = scene.builtinShapeKey) !== null && _scene$builtinShapeKe !== void 0 ? _scene$builtinShapeKe : (_FLOOR_MAP_BUILTIN_SH = FLOOR_MAP_BUILTIN_SHAPES[0]) === null || _FLOOR_MAP_BUILTIN_SH === void 0 ? void 0 : _FLOOR_MAP_BUILTIN_SH.key : undefined;
  var builtinDef = isBuiltinShape ? getFloorMapBuiltinShapeDef(initialBuiltinShapeKey) : undefined;
  var width = isImage ? IMAGE_PLACE_DEFAULT.width : isSelectionZone ? SELECTION_ZONE_PLACE_DEFAULT.width : isStage ? STAGE_DECO_DEFAULT.width : isBuiltinShape ? (_builtinDef$defaultSi = builtinDef === null || builtinDef === void 0 ? void 0 : builtinDef.defaultSize.width) !== null && _builtinDef$defaultSi !== void 0 ? _builtinDef$defaultSi : BUILTIN_SHAPE_PLACE_DEFAULT.width : defaultPlacementWidth;
  var height = isImage ? IMAGE_PLACE_DEFAULT.height : isSelectionZone ? SELECTION_ZONE_PLACE_DEFAULT.height : isStage ? STAGE_DECO_DEFAULT.height : isBuiltinShape ? (_builtinDef$defaultSi2 = builtinDef === null || builtinDef === void 0 ? void 0 : builtinDef.defaultSize.height) !== null && _builtinDef$defaultSi2 !== void 0 ? _builtinDef$defaultSi2 : BUILTIN_SHAPE_PLACE_DEFAULT.height : defaultPlacementHeight;
  var useDecoSize = policy === 'none' && !isStage && !isSelectionZone && !isImage && !isBuiltinShape;
  return {
    width: useDecoSize ? defaultDecoSize : width,
    height: useDecoSize ? defaultDecoSize : height,
    useDecoSize: useDecoSize,
    isStage: isStage,
    isSelectionZone: isSelectionZone,
    isImage: isImage,
    isBuiltinShape: isBuiltinShape,
    initialBuiltinShapeKey: initialBuiltinShapeKey,
    kindConfig: kindConfig
  };
}
function buildPlacedSceneElement(params, dims) {
  var canvasId = params.canvasId,
    scene = params.scene,
    x = params.x,
    y = params.y,
    name = params.name,
    dataBinding = params.dataBinding;
  var width = dims.width,
    height = dims.height,
    isStage = dims.isStage,
    isSelectionZone = dims.isSelectionZone,
    isImage = dims.isImage,
    isBuiltinShape = dims.isBuiltinShape,
    initialBuiltinShapeKey = dims.initialBuiltinShapeKey,
    kindConfig = dims.kindConfig;
  return _objectSpread(_objectSpread({
    instanceId: newInstanceId(),
    canvasId: canvasId,
    x: Math.round(x),
    y: Math.round(y),
    name: name,
    zIndex: isSelectionZone ? -50 : isImage || isBuiltinShape ? -5 : 0,
    width: Math.round(width),
    height: Math.round(height),
    elementKind: scene.elementKind,
    shape: isStage || isSelectionZone || isImage || isBuiltinShape ? 'rect' : kindConfig === null || kindConfig === void 0 ? void 0 : kindConfig.defaultShape,
    dataBinding: dataBinding
  }, isImage ? {
    imageUrl: ''
  } : {}), isBuiltinShape ? {
    builtinShapeKey: initialBuiltinShapeKey
  } : {});
}
export function useFloorMapEditState(params) {
  var _selectedItem$_sceneE;
  var floorMapConfigProp = params.floorMapConfigProp,
    isFloorMapView = params.isFloorMapView,
    itemsProp = params.itemsProp,
    cellSizeProp = params.cellSizeProp,
    dataSources = params.dataSources,
    onSave = params.onSave,
    onDataSourceRecordSave = params.onDataSourceRecordSave,
    dataSourceFormColumns = params.dataSourceFormColumns,
    dataSourceRecordForm = params.dataSourceRecordForm,
    dataSourceLabels = params.dataSourceLabels,
    layoutPrefix = params.layoutPrefix,
    contentOffsetRef = params.contentOffsetRef,
    showDataSourceRecordFormBlock = params.showDataSourceRecordFormBlock,
    focusViewportOnBoundsRef = params.focusViewportOnBoundsRef,
    gridPersistNamespace = params.gridPersistNamespace;
  var scheduleFocusOnPlacements = useCallback(function (positions, sizes) {
    var _focusViewportOnBound;
    var box = getPlacementBoundingBox(positions, sizes);
    if (!box) return;
    focusViewportOnBoundsRef === null || focusViewportOnBoundsRef === void 0 || (_focusViewportOnBound = focusViewportOnBoundsRef.current) === null || _focusViewportOnBound === void 0 || _focusViewportOnBound.call(focusViewportOnBoundsRef, box);
  }, [focusViewportOnBoundsRef]);
  var engineCtx = useEngineContext();
  var engineLocale = getFloorMapDisplayLocale(engineCtx);

  /**
   * 草稿历史栈：所有可撤销的编辑操作都通过 `commitDraft` 写入；
   * 上游 props 同步走 `replaceDraft`（不入栈、清空历史）。
   */
  var draftHistory = useDraftConfigHistory();
  var draftConfig = draftHistory.present;
  var commitDraft = draftHistory.commit;
  var replaceDraft = draftHistory.replace;
  var undoDraft = draftHistory.undo;
  var redoDraft = draftHistory.redo;
  var canUndo = draftHistory.canUndo;
  var canRedo = draftHistory.canRedo;
  var _useState = useState(null),
    _useState2 = _slicedToArray(_useState, 2),
    currentCanvasId = _useState2[0],
    setCurrentCanvasId = _useState2[1];
  var _useState3 = useState(null),
    _useState4 = _slicedToArray(_useState3, 2),
    selectedId = _useState4[0],
    setSelectedId = _useState4[1];
  var _useState5 = useState(null),
    _useState6 = _slicedToArray(_useState5, 2),
    placeMode = _useState6[0],
    setPlaceMode = _useState6[1];
  var _useState7 = useState(false),
    _useState8 = _slicedToArray(_useState7, 2),
    saving = _useState8[0],
    setSaving = _useState8[1];
  var _useState9 = useState(false),
    _useState10 = _slicedToArray(_useState9, 2),
    savingRecord = _useState10[0],
    setSavingRecord = _useState10[1];
  /**
   * 本地“已提交保存”的基线快照：
   * - 点击「完成编辑/保存」后立即置为当前 draft，避免等待上游 props 回写期间仍显示“未持久化”提示；
   * - 用户后续再改动 draft 时，dirty 会再次为 true。
   */
  var _useState11 = useState(null),
    _useState12 = _slicedToArray(_useState11, 2),
    savedBaselineConfig = _useState12[0],
    setSavedBaselineConfig = _useState12[1];
  var config = isFloorMapView ? draftConfig !== null && draftConfig !== void 0 ? draftConfig : floorMapConfigProp : null;
  var configRef = useRef(config);
  configRef.current = config;

  /** 上一次已从 props 写入草稿的配置；用于区分「接口刚下发」与「用户本地改过」 */
  var lastSyncedPropConfigRef = useRef(null);
  useEffect(function () {
    if (!floorMapConfigProp) {
      lastSyncedPropConfigRef.current = null;
      return;
    }
    var nextConfig = normalizeFloorMapConfigWithStoredGrid(floorMapConfigProp, gridPersistNamespace);
    var lastSynced = lastSyncedPropConfigRef.current;
    /**
     * 仅当「自上次 props 同步后用户又改过草稿」时拒绝覆盖：
     * - 接口/订阅首次带回 layout：草稿仍等于上次 props → 必须 replace，否则会空白；
     * - 编辑中落了新图元：草稿已与 lastSynced 不同 → 拒绝旧 props 覆盖。
     */
    if (draftConfig && lastSynced != null) {
      var propMatchesDraft = floorMapViewConfigsEqual(draftConfig, nextConfig);
      var draftMatchesLastSynced = floorMapViewConfigsEqual(draftConfig, lastSynced);
      if (!propMatchesDraft && !draftMatchesLastSynced) {
        return;
      }
    }

    /**
     * 上游配置变更：直接 replace（不进入历史栈），并清空 undo/redo；
     * 同时清空本地临时保存基线，让 dirty/未保存提示与上游对齐。
     */
    replaceDraft(nextConfig);
    lastSyncedPropConfigRef.current = nextConfig;
    setSavedBaselineConfig(function (prev) {
      return prev != null && floorMapViewConfigsEqual(prev, nextConfig) ? prev : null;
    });
    var enabled = nextConfig.canvases.filter(function (c) {
      return c.enabled;
    }).sort(function (a, b) {
      return a.order - b.order;
    });
    setCurrentCanvasId(function (prev) {
      var _enabled$0$id, _enabled$;
      return prev && enabled.some(function (c) {
        return c.id === prev;
      }) ? prev : (_enabled$0$id = (_enabled$ = enabled[0]) === null || _enabled$ === void 0 ? void 0 : _enabled$.id) !== null && _enabled$0$id !== void 0 ? _enabled$0$id : null;
    });
    // replaceDraft 是稳定引用；上游 props 或网格命名空间（切门店/平面图）变化时同步
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [floorMapConfigProp, gridPersistNamespace]);

  /** 当前草稿与上游持久化 `floorMapConfig`（经同等规范化）是否不一致 */
  var isLayoutDirty = useMemo(function () {
    if (!isFloorMapView || !draftConfig || !floorMapConfigProp) return false;
    var baseline = savedBaselineConfig !== null && savedBaselineConfig !== void 0 ? savedBaselineConfig : normalizeFloorMapConfigWithStoredGrid(floorMapConfigProp, gridPersistNamespace);
    return !floorMapViewConfigsEqual(draftConfig, baseline);
  }, [isFloorMapView, draftConfig, floorMapConfigProp, savedBaselineConfig, gridPersistNamespace]);

  /**
   * 撤销/重做后：若选中的图元已不存在于新草稿（如撤回了刚复制/新建的元素），
   * 自动清理 selectedId，避免侧栏/快捷栏停留在「悬空选中」状态。
   */
  useEffect(function () {
    var _draftConfig$sceneEle;
    if (!selectedId || !draftConfig) return;
    var exists = ((_draftConfig$sceneEle = draftConfig.sceneElements) !== null && _draftConfig$sceneEle !== void 0 ? _draftConfig$sceneEle : []).some(function (e) {
      return e.instanceId === selectedId;
    });
    if (!exists) setSelectedId(null);
  }, [selectedId, draftConfig]);

  /**
   * 撤销/重做后：若当前画布在新草稿中已被删除或禁用，回退到第一张启用画布。
   */
  useEffect(function () {
    var _enabled$0$id2, _enabled$2;
    if (!draftConfig) return;
    if (!currentCanvasId) return;
    var stillUsable = draftConfig.canvases.some(function (c) {
      return c.id === currentCanvasId && c.enabled;
    });
    if (stillUsable) return;
    var enabled = draftConfig.canvases.filter(function (c) {
      return c.enabled;
    }).sort(function (a, b) {
      return a.order - b.order;
    });
    setCurrentCanvasId((_enabled$0$id2 = (_enabled$2 = enabled[0]) === null || _enabled$2 === void 0 ? void 0 : _enabled$2.id) !== null && _enabled$0$id2 !== void 0 ? _enabled$0$id2 : null);
  }, [currentCanvasId, draftConfig]);
  var handleAddCanvas = useCallback(function () {
    initFloorMapLayoutLocales(engineLocale);
    var label = locales.getText('pisell-floor-map-layout.canvas-tabs.default-new-canvas-name');
    var defaultName = createTranslationText(label, true);
    var newId = "floor_".concat(Date.now());
    var newCanvas = {
      id: newId,
      name: defaultName,
      order: 0,
      enabled: true
    };
    commitDraft(function (prev) {
      if (!prev) return prev;
      var list = prev.canvases.filter(function (c) {
        return c.enabled;
      }).sort(function (a, b) {
        return a.order - b.order;
      });
      newCanvas.order = list.length > 0 ? Math.max.apply(Math, _toConsumableArray(list.map(function (c) {
        return c.order;
      }))) + 1 : 0;
      return _objectSpread(_objectSpread({}, prev), {}, {
        canvases: [].concat(_toConsumableArray(prev.canvases), [newCanvas])
      });
    });
    setCurrentCanvasId(newId);
  }, [engineLocale]);
  var handleRemoveCanvas = useCallback(function (canvasId) {
    commitDraft(function (prev) {
      var _prev$sceneElements;
      if (!prev) return prev;
      var nextCanvases = prev.canvases.filter(function (c) {
        return c.id !== canvasId;
      });
      if (nextCanvases.length === 0) return prev;
      return _objectSpread(_objectSpread({}, prev), {}, {
        canvases: nextCanvases,
        sceneElements: ((_prev$sceneElements = prev.sceneElements) !== null && _prev$sceneElements !== void 0 ? _prev$sceneElements : []).filter(function (e) {
          return e.canvasId !== canvasId;
        })
      });
    });
    setCurrentCanvasId(function (prev) {
      var _enabled$0$id3, _enabled$3;
      if (prev !== canvasId) return prev;
      var cfg = configRef.current;
      if (!cfg) return prev;
      var enabled = cfg.canvases.filter(function (c) {
        return c.id !== canvasId && c.enabled;
      }).sort(function (a, b) {
        return a.order - b.order;
      });
      return (_enabled$0$id3 = (_enabled$3 = enabled[0]) === null || _enabled$3 === void 0 ? void 0 : _enabled$3.id) !== null && _enabled$0$id3 !== void 0 ? _enabled$0$id3 : null;
    });
  }, []);
  var handleRenameCanvas = useCallback(function (canvasId, name) {
    if (typeof name === 'string') {
      var trimmed = name.trim();
      if (!trimmed) return;
      commitDraft(function (prev) {
        if (!prev) return prev;
        return _objectSpread(_objectSpread({}, prev), {}, {
          canvases: prev.canvases.map(function (c) {
            return c.id === canvasId ? _objectSpread(_objectSpread({}, c), {}, {
              name: trimmed,
              nameKey: undefined
            }) : c;
          })
        });
      });
      return;
    }
    var hasAny = Object.values(name).some(function (s) {
      return typeof s === 'string' && s.trim();
    });
    if (!hasAny) return;
    commitDraft(function (prev) {
      if (!prev) return prev;
      return _objectSpread(_objectSpread({}, prev), {}, {
        canvases: prev.canvases.map(function (c) {
          return c.id === canvasId ? _objectSpread(_objectSpread({}, c), {}, {
            name: name,
            nameKey: undefined
          }) : c;
        })
      });
    });
  }, []);
  var mergedItems = useMemo(function () {
    if (!isFloorMapView || !config || !currentCanvasId) return [];
    return mergeCanvasItems(currentCanvasId, config, cellSizeProp !== null && cellSizeProp !== void 0 ? cellSizeProp : DEFAULT_CELL_SIZE);
  }, [isFloorMapView, config, currentCanvasId, cellSizeProp]);
  var items = isFloorMapView ? mergedItems : itemsProp;
  var getBatchPlacementLayoutContext = useCallback(function () {
    var _config$sceneElements, _config$mapLayer, _canvas$mapLayer2;
    var elements = ((_config$sceneElements = config === null || config === void 0 ? void 0 : config.sceneElements) !== null && _config$sceneElements !== void 0 ? _config$sceneElements : []).filter(function (e) {
      return e.canvasId === currentCanvasId;
    });
    var existingElements = elements.map(function (e) {
      var _e$x, _e$y, _e$width, _e$height;
      return {
        x: Math.round((_e$x = e.x) !== null && _e$x !== void 0 ? _e$x : 0),
        y: Math.round((_e$y = e.y) !== null && _e$y !== void 0 ? _e$y : 0),
        width: Math.round((_e$width = e.width) !== null && _e$width !== void 0 ? _e$width : FLOOR_MAP_RESOURCE_PLACE_DEFAULT.width),
        height: Math.round((_e$height = e.height) !== null && _e$height !== void 0 ? _e$height : FLOOR_MAP_RESOURCE_PLACE_DEFAULT.height)
      };
    });
    var canvas = config === null || config === void 0 ? void 0 : config.canvases.find(function (c) {
      return c.id === currentCanvasId;
    });
    var mapLayer = _objectSpread(_objectSpread({}, (_config$mapLayer = config === null || config === void 0 ? void 0 : config.mapLayer) !== null && _config$mapLayer !== void 0 ? _config$mapLayer : {}), (_canvas$mapLayer2 = canvas === null || canvas === void 0 ? void 0 : canvas.mapLayer) !== null && _canvas$mapLayer2 !== void 0 ? _canvas$mapLayer2 : {});
    var padSingle = typeof mapLayer.boundingPadding === 'number' ? mapLayer.boundingPadding : DEFAULT_BOUNDING_PADDING;
    var cellSize = cellSizeProp !== null && cellSizeProp !== void 0 ? cellSizeProp : DEFAULT_CELL_SIZE;
    var itemGap = gapToPx(mapLayer.gap);
    var stage = computeFloorMapContentStage({
      items: mergedItems,
      cellSize: cellSize,
      itemGap: itemGap,
      itemUnit: 'pixel',
      boundingPadding: padSingle,
      preferPixelBoundingBox: true
    });
    return {
      existingElements: existingElements,
      contentWidth: stage.contentWidth,
      contentHeight: stage.contentHeight,
      boundingPadding: padSingle
    };
  }, [config, currentCanvasId, mergedItems, cellSizeProp]);
  var updateDraftSceneElement = useCallback(function (instanceId, patch) {
    commitDraft(function (prev) {
      var _prev$sceneElements2, _prev$sceneElements3;
      if (!prev) return prev;
      var current = ((_prev$sceneElements2 = prev.sceneElements) !== null && _prev$sceneElements2 !== void 0 ? _prev$sceneElements2 : []).find(function (e) {
        return e.instanceId === instanceId;
      });
      var normalized = _objectSpread({}, patch);
      var unlocking = patch.layoutTransformLocked === false;
      if (current !== null && current !== void 0 && current.layoutTransformLocked && !unlocking) {
        var _normalized = normalized,
          _x = _normalized.x,
          _y = _normalized.y,
          _z = _normalized.zIndex,
          _w = _normalized.width,
          _h = _normalized.height,
          rest = _objectWithoutProperties(_normalized, _excluded);
        normalized = rest;
      }
      if (normalized.x !== undefined) normalized.x = Math.round(normalized.x);
      if (normalized.y !== undefined) normalized.y = Math.round(normalized.y);
      if (normalized.width !== undefined) normalized.width = Math.round(normalized.width);
      if (normalized.height !== undefined) normalized.height = Math.round(normalized.height);
      var list = ((_prev$sceneElements3 = prev.sceneElements) !== null && _prev$sceneElements3 !== void 0 ? _prev$sceneElements3 : []).map(function (e) {
        return e.instanceId === instanceId ? _objectSpread(_objectSpread({}, e), normalized) : e;
      });
      return _objectSpread(_objectSpread({}, prev), {}, {
        sceneElements: list
      });
    });
  }, []);
  var handleUpdateItem = useCallback(function (itemId, patch) {
    updateDraftSceneElement(itemId, patch);
  }, [updateDraftSceneElement]);

  /**
   * 一次提交多个图元的坐标/尺寸变更（选区分组拖拽时整组落库），单次 `commitDraft`，
   * 一步可整体撤销。锁定图元（layoutTransformLocked）被跳过。
   */
  var handleUpdateItemsBatch = useCallback(function (patches) {
    if (!patches.length) return;
    commitDraft(function (prev) {
      var _prev$sceneElements4;
      if (!prev) return prev;
      var byId = new Map(patches.map(function (p) {
        return [p.id, p.patch];
      }));
      var list = ((_prev$sceneElements4 = prev.sceneElements) !== null && _prev$sceneElements4 !== void 0 ? _prev$sceneElements4 : []).map(function (e) {
        var patch = byId.get(e.instanceId);
        if (!patch) return e;
        if (e.layoutTransformLocked) return e;
        var np = _objectSpread({}, patch);
        if (np.x !== undefined) np.x = Math.round(np.x);
        if (np.y !== undefined) np.y = Math.round(np.y);
        if (np.width !== undefined) np.width = Math.round(np.width);
        if (np.height !== undefined) np.height = Math.round(np.height);
        return _objectSpread(_objectSpread({}, e), np);
      });
      return _objectSpread(_objectSpread({}, prev), {}, {
        sceneElements: list
      });
    });
  }, [commitDraft]);
  var placeOverlayClass = "".concat(layoutPrefix, "-place-overlay");

  /**
   * 在内容坐标系下按「新建图元」模式落 sceneElement（支持 recordIds 批量；点击与拖拽共用）
   * @returns 是否已成功写入草稿（校验失败时为 false）
   */
  var applyScenePlacementAtCoords = useCallback(function (contentX, contentY, scene) {
    var _kindConfig$allowedDa, _ref, _scene$dataSourceKey;
    if (!config || !currentCanvasId) return false;
    var dims = resolveScenePlacementDimensions(config, scene);
    var kindConfig = dims.kindConfig;
    var policy = resolveDataBindingPolicy(kindConfig);
    var allKeys = Object.keys(dataSources !== null && dataSources !== void 0 ? dataSources : {});
    var allowedKeys = kindConfig !== null && kindConfig !== void 0 && (_kindConfig$allowedDa = kindConfig.allowedDataSourceKeys) !== null && _kindConfig$allowedDa !== void 0 && _kindConfig$allowedDa.length ? kindConfig.allowedDataSourceKeys.filter(function (k) {
      return allKeys.includes(k);
    }) : allKeys;
    var pickKey = (_ref = (_scene$dataSourceKey = scene.dataSourceKey) !== null && _scene$dataSourceKey !== void 0 ? _scene$dataSourceKey : allowedKeys[0]) !== null && _ref !== void 0 ? _ref : allKeys[0];
    var recordIdsToPlace = scene.recordIds && scene.recordIds.length > 0 ? scene.recordIds : scene.recordId ? [scene.recordId] : [];
    var dataBinding;
    if (policy !== 'none' && pickKey) {
      var _dataSources$pickKey;
      var dsList = (_dataSources$pickKey = dataSources === null || dataSources === void 0 ? void 0 : dataSources[pickKey]) !== null && _dataSources$pickKey !== void 0 ? _dataSources$pickKey : [];
      if (dsList.length === 0) {
        dataBinding = {
          dataSourceKey: pickKey,
          recordId: "new_".concat(Date.now())
        };
      } else if (recordIdsToPlace.length === 0) {
        if (policy === 'required') {
          message.warning('请先在侧栏选择数据源与数据行，再落位');
          return false;
        }
      } else if (recordIdsToPlace.length === 1) {
        var rid = recordIdsToPlace[0];
        var record = dsList.find(function (r) {
          return r.id === rid;
        });
        if (!record) {
          message.error('所选记录不存在，请重新选择数据行');
          return false;
        }
        var cand = {
          dataSourceKey: pickKey,
          recordId: rid
        };
        if (duplicateBinding(config.sceneElements, cand)) {
          message.warning('该数据记录已在平面图中绑定，请勿重复添加');
          return false;
        }
        dataBinding = cand;
      } else {
        var pending = [];
        var skippedDup = 0;
        var skippedMissing = 0;
        var seenInBatch = new Set();
        recordIdsToPlace.forEach(function (rid) {
          var _row$name;
          var record = dsList.find(function (r) {
            return r.id === rid;
          });
          if (!record) {
            skippedMissing += 1;
            return;
          }
          var cand = {
            dataSourceKey: pickKey,
            recordId: rid
          };
          if (seenInBatch.has(rid) || duplicateBinding(config.sceneElements, cand)) {
            skippedDup += 1;
            return;
          }
          seenInBatch.add(rid);
          var row = record;
          pending.push({
            binding: cand,
            name: String((_row$name = row === null || row === void 0 ? void 0 : row.name) !== null && _row$name !== void 0 ? _row$name : rid)
          });
        });
        if (skippedDup > 0) {
          message.warning("\u5DF2\u8DF3\u8FC7 ".concat(skippedDup, " \u6761\u5DF2\u5728\u5E73\u9762\u56FE\u4E2D\u7ED1\u5B9A\u7684\u8BB0\u5F55"));
        }
        if (skippedMissing > 0) {
          message.warning("\u6709 ".concat(skippedMissing, " \u6761\u8BB0\u5F55\u4E0D\u5B58\u5728\uFF0C\u5DF2\u8DF3\u8FC7"));
        }
        if (pending.length === 0) {
          message.warning('没有可落位的记录');
          return false;
        }
        var sizes = pending.map(function () {
          return {
            width: dims.width,
            height: dims.height
          };
        });
        var positions = computeBatchScenePlacementPositions(sizes, getBatchPlacementLayoutContext());
        var newEls = pending.map(function (p, i) {
          return buildPlacedSceneElement({
            canvasId: currentCanvasId,
            scene: scene,
            x: positions[i].x,
            y: positions[i].y,
            name: p.name,
            dataBinding: p.binding
          }, dims);
        });
        commitDraft(function (prev) {
          var _prev$sceneElements5;
          return prev ? _objectSpread(_objectSpread({}, prev), {}, {
            sceneElements: [].concat(_toConsumableArray((_prev$sceneElements5 = prev.sceneElements) !== null && _prev$sceneElements5 !== void 0 ? _prev$sceneElements5 : []), _toConsumableArray(newEls))
          }) : prev;
        });
        scheduleFocusOnPlacements(positions, sizes);
        return true;
      }
    }
    var placementName = function (_kindConfig$defaultPr, _kindConfig$defaultPr2) {
      if (dims.isStage) return STAGE_DECO_DEFAULT.name;
      if (dims.isSelectionZone) return locales.getText(I18N_PLACEMENT_SELECTION_ZONE_NAME);
      if (dims.isImage) return locales.getText(I18N_PLACEMENT_FALLBACK_IMAGE);
      var db = dataBinding;
      var rid = recordIdsToPlace[0];
      if (db && rid) {
        var _dataSources$db$dataS, _row$name2;
        var row = dataSources === null || dataSources === void 0 || (_dataSources$db$dataS = dataSources[db.dataSourceKey]) === null || _dataSources$db$dataS === void 0 ? void 0 : _dataSources$db$dataS.find(function (r) {
          return r.id === rid;
        });
        return String((_row$name2 = row === null || row === void 0 ? void 0 : row.name) !== null && _row$name2 !== void 0 ? _row$name2 : rid);
      }
      return (_kindConfig$defaultPr = kindConfig === null || kindConfig === void 0 || (_kindConfig$defaultPr2 = kindConfig.defaultPresentation) === null || _kindConfig$defaultPr2 === void 0 ? void 0 : _kindConfig$defaultPr2.title) !== null && _kindConfig$defaultPr !== void 0 ? _kindConfig$defaultPr : '';
    }();
    var newEl = buildPlacedSceneElement({
      canvasId: currentCanvasId,
      scene: scene,
      x: contentX,
      y: contentY,
      name: placementName,
      dataBinding: dataBinding
    }, dims);
    commitDraft(function (prev) {
      var _prev$sceneElements6;
      return prev ? _objectSpread(_objectSpread({}, prev), {}, {
        sceneElements: [].concat(_toConsumableArray((_prev$sceneElements6 = prev.sceneElements) !== null && _prev$sceneElements6 !== void 0 ? _prev$sceneElements6 : []), [newEl])
      }) : prev;
    });
    scheduleFocusOnPlacements([{
      x: contentX,
      y: contentY
    }], [{
      width: dims.width,
      height: dims.height
    }]);
    return true;
  }, [config, currentCanvasId, dataSources, getBatchPlacementLayoutContext, commitDraft, scheduleFocusOnPlacements]);
  var handleCanvasPlaceClick = useCallback(function (e) {
    if (!placeMode || placeMode.type !== 'scene' || !config || !currentCanvasId) return;
    var target = e.target;
    if (!target.classList.contains(placeOverlayClass)) return;
    var _contentOffsetRef$cur = contentOffsetRef.current,
      ox = _contentOffsetRef$cur.x,
      oy = _contentOffsetRef$cur.y;
    var contentX = Math.round(e.nativeEvent.offsetX - ox);
    var contentY = Math.round(e.nativeEvent.offsetY - oy);
    if (applyScenePlacementAtCoords(contentX, contentY, placeMode)) {
      setPlaceMode(null);
    }
  }, [placeMode, config, currentCanvasId, applyScenePlacementAtCoords, placeOverlayClass]);

  /** 从左侧图元栏拖拽到画布落位（与点击落点规则一致） */
  var placeSceneElementFromPaletteDrop = useCallback(function (contentX, contentY, scene) {
    var ok = applyScenePlacementAtCoords(contentX, contentY, scene);
    if (ok) setPlaceMode(null);
    return ok;
  }, [applyScenePlacementAtCoords]);

  /**
   * 批量落点（弹窗多选、侧栏多选数据行等）：在画布右侧空白区按近方阵网格排列。
   */
  var bulkPlacePaletteItems = useCallback(function (items) {
    if (!items.length || !config || !currentCanvasId) return;
    var scenes = items.map(function (item) {
      return _objectSpread({
        type: 'scene',
        elementKind: item.elementKind
      }, item.builtinShapeKey ? {
        builtinShapeKey: item.builtinShapeKey
      } : {});
    });
    var dimsList = scenes.map(function (scene) {
      return resolveScenePlacementDimensions(config, scene);
    });
    var sizes = dimsList.map(function (d) {
      return {
        width: d.width,
        height: d.height
      };
    });
    var positions = computeBatchScenePlacementPositions(sizes, getBatchPlacementLayoutContext());
    var newEls = scenes.map(function (scene, i) {
      var _ref2, _dimsList$i$kindConfi, _dimsList$i$kindConfi2, _dimsList$i$kindConfi3;
      return buildPlacedSceneElement({
        canvasId: currentCanvasId,
        scene: scene,
        x: positions[i].x,
        y: positions[i].y,
        name: (_ref2 = (_dimsList$i$kindConfi = (_dimsList$i$kindConfi2 = dimsList[i].kindConfig) === null || _dimsList$i$kindConfi2 === void 0 ? void 0 : _dimsList$i$kindConfi2.label) !== null && _dimsList$i$kindConfi !== void 0 ? _dimsList$i$kindConfi : (_dimsList$i$kindConfi3 = dimsList[i].kindConfig) === null || _dimsList$i$kindConfi3 === void 0 || (_dimsList$i$kindConfi3 = _dimsList$i$kindConfi3.defaultPresentation) === null || _dimsList$i$kindConfi3 === void 0 ? void 0 : _dimsList$i$kindConfi3.title) !== null && _ref2 !== void 0 ? _ref2 : scene.elementKind
      }, dimsList[i]);
    });
    commitDraft(function (prev) {
      var _prev$sceneElements7;
      return prev ? _objectSpread(_objectSpread({}, prev), {}, {
        sceneElements: [].concat(_toConsumableArray((_prev$sceneElements7 = prev.sceneElements) !== null && _prev$sceneElements7 !== void 0 ? _prev$sceneElements7 : []), _toConsumableArray(newEls))
      }) : prev;
    });
    scheduleFocusOnPlacements(positions, sizes);
    setPlaceMode(null);
  }, [config, currentCanvasId, getBatchPlacementLayoutContext, commitDraft, scheduleFocusOnPlacements]);
  var handleSave = useCallback(function () {
    if (!draftConfig || !onSave) return;
    setSaving(true);
    try {
      onSave(draftConfig);
      /** 先本地确认“已提交保存”，让提示即时消失；后续以 props 回写为准 */
      setSavedBaselineConfig(draftConfig);
    } finally {
      setSaving(false);
    }
  }, [draftConfig, onSave]);

  /**
   * 丢弃所有未保存的草稿改动，把 `draftConfig` 重置回上游 `floorMapConfigProp` 的当前值。
   *
   * 用途：编辑态下点击「取消编辑」（不保存退出）时调用，否则 `config` 仍取
   * `draftConfig ?? floorMapConfigProp`，回到阅读态会继续看到编辑后的脏数据。
   *
   * 实现要点：
   * - 与上游 props 同步 effect（line 165）使用相同的规范化路径与 `replaceDraft`，
   *   保证「取消」后状态等价于「上游 props 重新落地一次」；
   * - `replaceDraft` 内部已清空 undo/redo 历史栈，避免取消后又能 redo 出旧 draft；
   * - 同步清空 `savedBaselineConfig`，让 dirty 判定回到「以上游 props 为基线」。
   */
  var discardDraft = useCallback(function () {
    if (!floorMapConfigProp) {
      replaceDraft(null);
      lastSyncedPropConfigRef.current = null;
      setSavedBaselineConfig(null);
      return;
    }
    var nextConfig = normalizeFloorMapConfigWithStoredGrid(floorMapConfigProp, gridPersistNamespace);
    replaceDraft(nextConfig);
    lastSyncedPropConfigRef.current = nextConfig;
    setSavedBaselineConfig(null);
  }, [floorMapConfigProp, replaceDraft, gridPersistNamespace]);

  /** 切换当前画布草稿中的 mapLayer.showGrid（随布局保存持久化） */
  var toggleDraftCanvasShowGrid = useCallback(function () {
    commitDraft(function (prev) {
      if (!prev || !currentCanvasId) return prev;
      return _objectSpread(_objectSpread({}, prev), {}, {
        canvases: prev.canvases.map(function (c) {
          var _c$mapLayer;
          if (c.id !== currentCanvasId) return c;
          var nextShow = !Boolean((_c$mapLayer = c.mapLayer) === null || _c$mapLayer === void 0 ? void 0 : _c$mapLayer.showGrid);
          writeStoredGridVisible(currentCanvasId, nextShow, gridPersistNamespace);
          return _objectSpread(_objectSpread({}, c), {}, {
            mapLayer: _objectSpread(_objectSpread({}, c.mapLayer), {}, {
              showGrid: nextShow
            })
          });
        })
      });
    });
  }, [currentCanvasId, gridPersistNamespace]);
  var handleEditPanelUpdate = useCallback(function (patch) {
    if (!selectedId) return;
    var bindingPatch = patch.dataBinding;
    if (bindingPatch !== null && bindingPatch !== void 0 && bindingPatch.dataSourceKey && bindingPatch !== null && bindingPatch !== void 0 && bindingPatch.recordId) {
      var _configRef$current;
      var cand = bindingPatch;
      if (duplicateBinding((_configRef$current = configRef.current) === null || _configRef$current === void 0 ? void 0 : _configRef$current.sceneElements, cand, selectedId)) {
        message.warning('该数据记录已被其他图元绑定');
        return;
      }
    }
    updateDraftSceneElement(selectedId, patch);
  }, [selectedId, updateDraftSceneElement]);
  var handleSaveRecord = useCallback(function (dataSourceKey, id, newData) {
    onDataSourceRecordSave === null || onDataSourceRecordSave === void 0 || onDataSourceRecordSave(dataSourceKey, id, newData);
    setSavingRecord(true);
    setTimeout(function () {
      return setSavingRecord(false);
    }, 500);
  }, [onDataSourceRecordSave]);
  var handleEditPanelDelete = useCallback(function () {
    if (!selectedId) return;
    commitDraft(function (prev) {
      var _prev$sceneElements8, _prev$edges;
      if (!prev) return prev;
      return _objectSpread(_objectSpread({}, prev), {}, {
        sceneElements: ((_prev$sceneElements8 = prev.sceneElements) !== null && _prev$sceneElements8 !== void 0 ? _prev$sceneElements8 : []).filter(function (e) {
          return e.instanceId !== selectedId;
        }),
        edges: ((_prev$edges = prev.edges) !== null && _prev$edges !== void 0 ? _prev$edges : []).filter(function (edge) {
          return edge.sourceId !== selectedId && edge.targetId !== selectedId;
        })
      });
    });
    setSelectedId(null);
  }, [selectedId, commitDraft]);

  /** 与编辑侧栏锁定按钮同源：切换 `layoutTransformLocked` */
  var toggleSelectedLayoutLock = useCallback(function () {
    var _configRef$current2;
    if (!selectedId) return;
    var el = (_configRef$current2 = configRef.current) === null || _configRef$current2 === void 0 || (_configRef$current2 = _configRef$current2.sceneElements) === null || _configRef$current2 === void 0 ? void 0 : _configRef$current2.find(function (e) {
      return e.instanceId === selectedId;
    });
    updateDraftSceneElement(selectedId, {
      layoutTransformLocked: !(el !== null && el !== void 0 && el.layoutTransformLocked)
    });
  }, [selectedId, updateDraftSceneElement]);

  /**
   * 复制选中图元：新实例 + 位移，**清除 dataBinding**（避免与侧栏一致的「同一记录不可重复绑定」冲突）。
   */
  var duplicateSelectedElement = useCallback(function () {
    var _prev$sceneElements9, _el$x, _el$y, _prev$sceneElements10;
    if (!selectedId) return;
    var prev = configRef.current;
    if (!prev) return;
    var el = ((_prev$sceneElements9 = prev.sceneElements) !== null && _prev$sceneElements9 !== void 0 ? _prev$sceneElements9 : []).find(function (e) {
      return e.instanceId === selectedId;
    });
    if (!el) return;
    var newId = newInstanceId();
    var copy = _objectSpread(_objectSpread({}, el), {}, {
      instanceId: newId,
      x: Math.round(((_el$x = el.x) !== null && _el$x !== void 0 ? _el$x : 0) + DUPLICATE_PLACE_OFFSET),
      y: Math.round(((_el$y = el.y) !== null && _el$y !== void 0 ? _el$y : 0) + DUPLICATE_PLACE_OFFSET),
      dataBinding: undefined,
      layoutTransformLocked: false
    });
    commitDraft(_objectSpread(_objectSpread({}, prev), {}, {
      sceneElements: [].concat(_toConsumableArray((_prev$sceneElements10 = prev.sceneElements) !== null && _prev$sceneElements10 !== void 0 ? _prev$sceneElements10 : []), [copy])
    }));
    setSelectedId(newId);
  }, [selectedId]);
  var selectedItem = selectedId ? mergedItems.find(function (m) {
    return m.id === selectedId;
  }) : null;

  /** 布局锁定中的图元仍可选中，但不展开右侧编辑面板（解锁后再展） */
  var editPanelParams = selectedItem && config && selectedId && !((_selectedItem$_sceneE = selectedItem._sceneElement) !== null && _selectedItem$_sceneE !== void 0 && _selectedItem$_sceneE.layoutTransformLocked) ? {
    itemId: selectedId,
    sceneElement: selectedItem._sceneElement,
    onUpdate: handleEditPanelUpdate,
    onSaveRecord: onDataSourceRecordSave ? handleSaveRecord : undefined,
    onClose: function onClose() {
      return setSelectedId(null);
    },
    onDelete: config.canvasUi.canEdit ? handleEditPanelDelete : undefined,
    recordFormColumns: dataSourceFormColumns,
    dataSourceRecordForm: dataSourceRecordForm,
    dataSourceLabels: dataSourceLabels,
    layoutDraftDirty: isLayoutDirty,
    showDataSourceRecordFormBlock: showDataSourceRecordFormBlock
  } : null;
  return {
    config: config,
    currentCanvasId: currentCanvasId,
    setCurrentCanvasId: setCurrentCanvasId,
    selectedId: selectedId,
    setSelectedId: setSelectedId,
    placeMode: placeMode,
    setPlaceMode: setPlaceMode,
    mergedItems: mergedItems,
    items: items,
    saving: saving,
    savingRecord: savingRecord,
    handleAddCanvas: handleAddCanvas,
    handleRemoveCanvas: handleRemoveCanvas,
    handleRenameCanvas: handleRenameCanvas,
    handleUpdateItem: handleUpdateItem,
    handleUpdateItemsBatch: handleUpdateItemsBatch,
    handleCanvasPlaceClick: handleCanvasPlaceClick,
    handleSave: handleSave,
    discardDraft: discardDraft,
    placeSceneElementFromPaletteDrop: placeSceneElementFromPaletteDrop,
    bulkPlacePaletteItems: bulkPlacePaletteItems,
    editPanelParams: editPanelParams,
    placeOverlayClass: placeOverlayClass,
    isLayoutDirty: isLayoutDirty,
    toggleDraftCanvasShowGrid: toggleDraftCanvasShowGrid,
    toggleSelectedLayoutLock: toggleSelectedLayoutLock,
    duplicateSelectedElement: duplicateSelectedElement,
    deleteSelectedElement: handleEditPanelDelete,
    undoDraft: undoDraft,
    redoDraft: redoDraft,
    canUndo: canUndo,
    canRedo: canRedo,
    commitDraft: commitDraft
  };
}