fix(studio): выделение папки раскрывает дерево + Delete удаляет всю папку с содержимым
1) При выделении папки (клик по сцене / вставка кита) дерево авто-раскрывается: workspace + цепочка родителей + scrollIntoView к строке папки. Раньше папка выделялась на сцене, но в свёрнутом дереве её не было видно. 2) Delete на выделенной папке (type='folder') → removeFolder(id, true) удаляет всю папку со ВСЕМ содержимым + _cleanupOrphanScripts чистит осиротевшие скрипты привязанные к удалённым объектам. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
46414d874b
commit
2d669a3ff3
@ -376,6 +376,23 @@ const HierarchyPanel = ({
|
||||
useEffect(() => {
|
||||
if (!selection) return;
|
||||
const t = selection.type;
|
||||
// Выделена ПАПКА (клик по сцене / вставка кита из тулбокса) — раскрыть
|
||||
// «Сцену» и цепочку папок до неё, чтобы папка стала видна в дереве.
|
||||
if (t === 'folder') {
|
||||
setWorkspaceOpen(true);
|
||||
setOpenFolders(prev => {
|
||||
const n = new Set(prev);
|
||||
let cur = selection.folderId;
|
||||
const guard = new Set();
|
||||
while (cur != null && !guard.has(cur)) {
|
||||
guard.add(cur);
|
||||
const f = folders.find(ff => ff.id === cur);
|
||||
if (f && f.parentId != null) { n.add(f.parentId); cur = f.parentId; } else cur = null;
|
||||
}
|
||||
return n;
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Находим объект и его folderId по выделению.
|
||||
let obj = null, kind = null;
|
||||
if (t === 'block') {
|
||||
@ -486,10 +503,12 @@ const HierarchyPanel = ({
|
||||
const subUserModels = userModelsByFolder.get(folder.id) || [];
|
||||
const totalCount = subBlocks.length + subModels.length + subPrims.length + subUserModels.length + subFolders.length;
|
||||
|
||||
const folderSelected = selection?.type === 'folder' && selection?.folderId === folder.id;
|
||||
return (
|
||||
<div key={`folder-${folder.id}`} className={cl.folderWrap}>
|
||||
<div
|
||||
className={`${cl.folderHeader} ${selection?.type === 'folder' && selection?.folderId === folder.id ? cl.itemSelected : ''}`}
|
||||
ref={folderSelected ? (el) => { if (el) el.scrollIntoView({ block: 'nearest', behavior: 'smooth' }); } : null}
|
||||
className={`${cl.folderHeader} ${folderSelected ? cl.itemSelected : ''}`}
|
||||
style={{ paddingLeft: depth * 12 + 8 }}
|
||||
onClick={() => onSelectFolder?.(folder.id)}
|
||||
onContextMenu={(e) => handleContextMenu(e, { type: 'folder', ...folder })}
|
||||
|
||||
@ -6604,6 +6604,25 @@ export class BabylonScene {
|
||||
if (this._onSceneChange) this._onSceneChange();
|
||||
}
|
||||
|
||||
/** Удалить скрипты, чей объект-носитель больше не существует (после удаления
|
||||
* папки/объектов). Глобальные (target null/'game') не трогаем. */
|
||||
_cleanupOrphanScripts() {
|
||||
if (!Array.isArray(this._scripts)) return;
|
||||
const exists = (t) => {
|
||||
if (!t || t === 'game') return true;
|
||||
if (t.kind === 'primitive') return !!this.primitiveManager?.instances?.has(t.id);
|
||||
if (t.kind === 'model') return !!this.modelManager?.instances?.has(t.id);
|
||||
if (t.kind === 'userModel') return !!this.userModelManager?.instances?.has(t.id);
|
||||
return true; // block и пр. — не чистим
|
||||
};
|
||||
const before = this._scripts.length;
|
||||
this._scripts = this._scripts.filter(s => exists(s.target));
|
||||
if (this._scripts.length !== before) {
|
||||
this.history?.markChange();
|
||||
if (this._onSceneChange) this._onSceneChange();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Зарегистрировать колбэк для уведомлений об изменении режима Play
|
||||
* (вызывается когда player сам инициирует exit, например по Esc).
|
||||
|
||||
@ -724,6 +724,17 @@ export class SelectionManager {
|
||||
} else if (this._selection.type === 'spawn') {
|
||||
// Удаление точки спавна → игрок будет появляться в (0, высота, 0).
|
||||
this._scene3d?.deleteSpawn?.();
|
||||
} else if (this._selection.type === 'folder') {
|
||||
// Папка целиком — удаляем со ВСЕМ содержимым (рекурсивно).
|
||||
const fid = this._selection.folderId;
|
||||
this.clear();
|
||||
this._scene3d?.folderManager?.removeFolder?.(fid, true);
|
||||
// Удаляем скрипты, привязанные к объектам этой папки? Они привязаны
|
||||
// к примитивам, которые removeFolder удалит; скрипты на них чистятся
|
||||
// через _onSceneChange / при сохранении. Дополнительно пусть движок
|
||||
// подчистит «осиротевшие» скрипты.
|
||||
this._scene3d?._cleanupOrphanScripts?.();
|
||||
return;
|
||||
}
|
||||
this.clear();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user