Unify toolbox drag and drop reorder behavior
All checks were successful
Deploy Sokko G / deploy (push) Successful in 7s
All checks were successful
Deploy Sokko G / deploy (push) Successful in 7s
This commit is contained in:
parent
a6d35c6e6b
commit
1879b245fb
17 changed files with 1258 additions and 929 deletions
|
|
@ -1,6 +1,7 @@
|
|||
// Rôle : fournit l'outil calculateur avec résultats enregistrés en arborescence.
|
||||
import { useLayoutEffect, useMemo, useRef, useState } from "react";
|
||||
import { Icon } from "../../../components/Icon.jsx";
|
||||
import { moveItem, useGroupedReorder } from "../../../hooks/useGroupedReorder.js";
|
||||
|
||||
function calculateExpression(expression) {
|
||||
const normalized = String(expression || "").replaceAll(",", ".").trim();
|
||||
|
|
@ -43,6 +44,17 @@ export function CalculatorModule({ toolboxId, moduleId, context }) {
|
|||
const calculatorCardRef = useRef(null);
|
||||
const result = useMemo(() => calculateExpression(expression), [expression]);
|
||||
const activeParent = data.entries.find((entry) => entry.id === activeParentId);
|
||||
const scopeParentId = (parentId = "") => `${moduleId}:${parentId}`;
|
||||
const reorder = useGroupedReorder({
|
||||
namespace: "calculator",
|
||||
items: data.entries,
|
||||
getItemId: (entry) => entry.id,
|
||||
getParentId: (entry) => scopeParentId(entry.parentId || ""),
|
||||
onItemMove: (operation) => {
|
||||
save(moveItem(data.entries, operation.sourceId, operation.targetId, operation.placement));
|
||||
},
|
||||
hierarchy: { enabled: true, stickyParents: true }
|
||||
});
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const element = calculatorCardRef.current;
|
||||
|
|
@ -165,7 +177,7 @@ export function CalculatorModule({ toolboxId, moduleId, context }) {
|
|||
</div>
|
||||
<div className={`tool-split-tree calculator-tree ${data.scrollResults ? "is-scrollable legacy-scrollbar" : ""}`}>
|
||||
{data.entries.length ? (
|
||||
<CalculatorEntries entries={data.entries} parentId="" activeParentId={activeParentId} textContent={textContent} onUse={useEntry} onRename={renameEntry} onDelete={deleteEntry} />
|
||||
<CalculatorEntries entries={data.entries} parentId="" getScopedParentId={scopeParentId} activeParentId={activeParentId} textContent={textContent} reorder={reorder} onUse={useEntry} onRename={renameEntry} onDelete={deleteEntry} />
|
||||
) : (
|
||||
<p className="muted">{textContent.emptyResults || "Aucun résultat enregistré."}</p>
|
||||
)}
|
||||
|
|
@ -175,16 +187,34 @@ export function CalculatorModule({ toolboxId, moduleId, context }) {
|
|||
);
|
||||
}
|
||||
|
||||
function CalculatorEntries({ entries, parentId, activeParentId, textContent, onUse, onRename, onDelete }) {
|
||||
function CalculatorEntries({ entries, parentId, getScopedParentId, activeParentId, textContent, reorder, onUse, onRename, onDelete }) {
|
||||
const children = getChildren(entries, parentId);
|
||||
const [editingId, setEditingId] = useState("");
|
||||
if (!children.length) return null;
|
||||
|
||||
return (
|
||||
<ul className="tool-split-entry-list calculator-entry-list">
|
||||
{children.map((entry) => (
|
||||
<li className={`${entry.id === activeParentId ? "active" : ""} ${entry.id === editingId ? "is-editing" : ""}`} key={entry.id}>
|
||||
<div className="tool-split-entry calculator-entry">
|
||||
{children.map((entry) => {
|
||||
const className = [
|
||||
entry.id === activeParentId ? "active" : "",
|
||||
entry.id === editingId ? "is-editing" : "",
|
||||
reorder.isItemDragging(entry.id) ? "is-dragging" : "",
|
||||
reorder.isItemDropTarget(entry.id) ? "is-drop-target" : "",
|
||||
reorder.getDropPlacement("item", entry.id, parentId) === "after" ? "drop-after" : ""
|
||||
].filter(Boolean).join(" ");
|
||||
|
||||
return (
|
||||
<li className={className} key={entry.id} {...reorder.getItemProps({ itemId: entry.id, parentId: getScopedParentId(parentId) })}>
|
||||
<div className="tool-split-entry calculator-entry has-drag-handle">
|
||||
<button
|
||||
className="calculator-drag-handle"
|
||||
type="button"
|
||||
onPointerDown={(event) => reorder.itemReorder.startDrag(event, entry.id)}
|
||||
aria-label={`${textContent.reorderTitle || "Déplacer"} ${entry.label || formatResult(entry.value)}`}
|
||||
title={textContent.reorderTitle || "Déplacer"}
|
||||
>
|
||||
<Icon name="drag" />
|
||||
</button>
|
||||
{entry.id === editingId ? (
|
||||
<>
|
||||
<span className="tool-split-entry-value is-readonly" title={textContent.readonlyValueTitle || "Quantité non modifiable"}>
|
||||
|
|
@ -204,9 +234,10 @@ function CalculatorEntries({ entries, parentId, activeParentId, textContent, onU
|
|||
<Icon name="trash" />
|
||||
</button>
|
||||
</div>
|
||||
<CalculatorEntries entries={entries} parentId={entry.id} activeParentId={activeParentId} textContent={textContent} onUse={onUse} onRename={onRename} onDelete={onDelete} />
|
||||
<CalculatorEntries entries={entries} parentId={entry.id} getScopedParentId={getScopedParentId} activeParentId={activeParentId} textContent={textContent} reorder={reorder} onUse={onUse} onRename={onRename} onDelete={onDelete} />
|
||||
</li>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue