// Rôle : rend l'en-tête, les contrôles et le contenu repliable d'un outil toolbox.
import { Suspense, useEffect, useId, useRef, useState } from "react";
import { Icon } from "../../../components/Icon.jsx";
import { useInlineEdit } from "../../../hooks/useInlineEdit.js";
import { GuideChecklistControls } from "../../games/GuideChecklistControls.jsx";
import { useGuideChecklistPanel } from "../../games/useGuideChecklist.js";
import { ModuleDataGate, ModuleLoadingFallback } from "./ModuleDataGate.jsx";
import { supportsTextExchange } from "./textImport.js";
import { MODULE_COMPONENTS } from "./toolboxModuleComponents.jsx";
export function ModuleShell({ toolbox, module, context, reorder, itemGroup = "", spaces = [], activeSpaceId = "", moveText = "Déplacer vers", configurationText = {}, scrollIntoView = false, onScrolledIntoView, onRename, onUpdateModule, onDelete, onMoveToSpace }) {
const definition = MODULE_COMPONENTS[module.type] || MODULE_COMPONENTS.notepad;
const Component = definition.Component;
const label = definition.label || module.type;
const [editing, setEditing] = useState(false);
const [configurationOpen, setConfigurationOpen] = useState(false);
const [configurationTarget, setConfigurationTarget] = useState(null);
const configurationId = useId();
const moduleRef = useRef(null);
const guidePanel = useGuideChecklistPanel(context.guideChecklist, module);
const hasAddPanel = definition.editable && definition.addable !== false;
const hasTextExchange = supportsTextExchange(module.type);
const hasConfiguration = spaces.length > 1 || Boolean(guidePanel.list) || hasTextExchange;
const scrollable = definition.scrollable && module.scrollable === true;
const collapsed = module.collapsed === true;
const className = [
"module",
reorder.isItemDragging(module.id) ? "is-dragging" : "",
reorder.isItemDropTarget(module.id) ? "is-drop-target" : "",
reorder.getDropPlacement("item", module.id) === "after" ? "drop-after" : "",
scrollable ? "is-scrollable" : "",
collapsed ? "is-collapsed" : ""
].filter(Boolean).join(" ");
const componentProps = {
toolboxId: toolbox.id,
moduleId: module.id,
context,
editing,
setEditing,
openEditor: () => {
setConfigurationOpen(false);
setEditing(true);
},
configurationTarget
};
useEffect(() => {
if (!scrollIntoView) return undefined;
const frame = window.requestAnimationFrame(() => {
moduleRef.current?.scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest" });
onScrolledIntoView?.();
});
return () => window.cancelAnimationFrame(frame);
}, [onScrolledIntoView, scrollIntoView]);
useEffect(() => {
if (!configurationOpen) return undefined;
const closeOnEscape = (event) => {
if (event.key === "Escape" && !document.querySelector('[aria-modal="true"]')) setConfigurationOpen(false);
};
window.addEventListener("keydown", closeOnEscape);
return () => window.removeEventListener("keydown", closeOnEscape);
}, [configurationOpen]);
function toggleCollapsed() {
if (!collapsed) {
setEditing(false);
setConfigurationOpen(false);
}
onUpdateModule(module.id, (currentModule) => {
const nextModule = { ...currentModule };
if (collapsed) {
delete nextModule.collapsed;
} else {
nextModule.collapsed = true;
}
return nextModule;
});
}
return (
{configurationText.organizationTitle || "Espace"}
{configurationText.guideTitle || "Guide"}