Split combos list rendering from module state
All checks were successful
Deploy Sokko G / deploy (push) Successful in 15s

This commit is contained in:
Shinuwa 2026-08-24 21:54:43 +02:00
parent 602486a1d7
commit 73e84ee703
3 changed files with 168 additions and 122 deletions

View file

@ -7,7 +7,8 @@ import {
useGroupedReorder
} from "../../../hooks/useGroupedReorder.js";
import { TextExchangeActions } from "./TextExchangeActions.jsx";
import { ComboInputToken, ComboSequence, InlineTextInput } from "./CombosParts.jsx";
import { ComboInputToken, ComboSequence } from "./CombosParts.jsx";
import { CombosList } from "./CombosList.jsx";
import {
DEVICE_OPTIONS,
createCombo,
@ -322,122 +323,6 @@ export function CombosModule({ toolboxId, moduleId, context, editing, textExchan
save({ ...data, collapsedCategories });
}
function renderCombo(combo) {
const category = getComboCategory(combo);
const comboClassName = [
"combo-card",
"is-editing",
isItemDragging(combo.id) ? "is-dragging" : "",
isItemDropTarget(combo.id) ? "is-drop-target" : "",
getDropPlacement("item", combo.id) === "after" ? "drop-after" : ""
].filter(Boolean).join(" ");
return (
<article className={comboClassName} key={combo.id} {...getItemProps({ itemId: combo.id, groupId: category })}>
<button
className="task-planner-drag-handle combo-drag-handle"
type="button"
onPointerDown={(event) => itemReorder.startDrag(event, combo.id)}
aria-label={`${textContent.reorderComboTitle || "Déplacer le combo"} ${combo.name}`}
title={textContent.reorderComboTitle || "Déplacer le combo"}
>
<Icon name="drag" />
</button>
<div className="combo-card-main">
<InlineTextInput
className="tool-split-entry-label combo-title-input"
value={combo.name}
onCommit={(name) => updateCombo(combo.id, (current) => ({ ...current, name: name || current.name }))}
ariaLabel={textContent.comboNameLabel || "Nom"}
/>
<ComboSequence inputs={combo.inputs} device={combo.device || data.device} emptyLabel={textContent.emptySequence || "Combo sans touches"} />
</div>
<div className="combo-card-actions">
<button type="button" className="checklist-delete-button" onClick={() => startComboEdit(combo)} aria-label={`${textContent.editComboTitle || "Modifier le combo"} ${combo.name}`} title={textContent.editComboTitle || "Modifier le combo"}>
<Icon name="edit" />
</button>
<button type="button" className="checklist-delete-button danger" onClick={() => deleteCombo(combo.id)} aria-label={`${textContent.deleteComboTitle || "Supprimer le combo"} ${combo.name}`} title={textContent.deleteComboTitle || "Supprimer le combo"}>
<Icon name="trash" />
</button>
</div>
</article>
);
}
function renderCategory(group, index, groupCount) {
const category = group.category;
const isCollapsed = data.collapsedCategories.includes(category);
const isLastCategory = index === groupCount - 1;
const categoryClassName = [
"combos-category checklist-section is-grouped",
isCollapsed ? "is-collapsed" : "",
isGroupDragging(category) ? "is-dragging" : "",
isGroupDropTarget(category) ? "is-drop-target" : "",
getDropPlacement("group", category) === "after" ? "drop-after" : ""
].filter(Boolean).join(" ");
const showBoundaryDropZones = shouldShowGroupBoundaries();
const beforeDropZone = showBoundaryDropZones ? (
<div
className={`combos-category-boundary-drop-zone ${isBoundaryDropTarget({ groupId: category, placement: "before" }) ? "is-drop-target" : ""}`}
key={`${category}:before-drop`}
{...getGroupBoundaryProps({ groupId: category, placement: "before" })}
/>
) : null;
const afterDropZone = showBoundaryDropZones ? (
<div
className={`combos-category-boundary-drop-zone ${isBoundaryDropTarget({ groupId: category, placement: "after" }) ? "is-drop-target" : ""}`}
key={`${category}:after-drop`}
{...getGroupBoundaryProps({ groupId: category, placement: "after" })}
/>
) : null;
return [
beforeDropZone,
<section className={categoryClassName} key={category} {...getGroupProps({ groupId: category })}>
<div className="checklist-section-header combos-category-header">
<div className="combos-category-title">
<button
className="task-planner-category-drag-handle"
type="button"
onPointerDown={(event) => groupReorder.startDrag(event, { groupId: category })}
aria-label={`${textContent.reorderCategoryTitle || "Déplacer la catégorie"} ${category}`}
title={textContent.reorderCategoryTitle || "Déplacer la catégorie"}
>
<Icon name="drag" />
</button>
<h3>{category}</h3>
</div>
<div className="checklist-section-actions">
<span>{group.combos.length}</span>
<button
className="checklist-section-collapse-button"
type="button"
onClick={() => toggleCategoryCollapsed(category)}
aria-expanded={!isCollapsed}
aria-label={isCollapsed ? textContent.showCategoryTitle || "Afficher la catégorie" : textContent.hideCategoryTitle || "Réduire la catégorie"}
title={isCollapsed ? textContent.showCategoryTitle || "Afficher la catégorie" : textContent.hideCategoryTitle || "Réduire la catégorie"}
>
<Icon name={isCollapsed ? "chevron-down" : "chevron-up"} />
</button>
</div>
</div>
{!isCollapsed && (
<div className="combos-list">
{group.combos.map((combo) => renderCombo(combo))}
</div>
)}
</section>,
showBoundaryDropZones && isLastCategory ? afterDropZone : null
];
}
const categoryCount = entries.filter((entry) => entry.type === "group").length;
let renderedCategoryIndex = -1;
function renderEntry(entry) {
if (entry.type !== "group") return renderCombo(entry.item);
renderedCategoryIndex += 1;
return renderCategory(entry.group, renderedCategoryIndex, categoryCount);
}
return (
<div className="combos-module">
{(editing || editingComboId) && (
@ -601,9 +486,29 @@ export function CombosModule({ toolboxId, moduleId, context, editing, textExchan
<p className="empty-state">{textContent.emptyCombos || "Aucun combo enregistré."}</p>
)}
<div className="combos-category-list">
{entries.map(renderEntry)}
</div>
<CombosList
entries={entries}
data={data}
textContent={textContent}
reorder={{
itemReorder,
groupReorder,
getItemProps,
getGroupProps,
getGroupBoundaryProps,
isItemDragging,
isItemDropTarget,
isGroupDragging,
isGroupDropTarget,
isBoundaryDropTarget,
getDropPlacement,
shouldShowGroupBoundaries
}}
onComboUpdate={updateCombo}
onComboEdit={startComboEdit}
onComboDelete={deleteCombo}
onCategoryToggle={toggleCategoryCollapsed}
/>
</div>
);
}