You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Application-Web/src/components/editor/StepsTree.tsx

156 lines
4.5 KiB

import "../../style/steps_tree.css"
import { StepInfoNode } from "../../model/tactic/Tactic"
import BendableArrow from "../arrows/BendableArrow"
import { ReactNode, useMemo, useRef } from "react"
import AddSvg from "../../assets/icon/add.svg?react"
import RemoveSvg from "../../assets/icon/remove.svg?react"
import { getStepName } from "../../editor/StepsDomain.ts"
export interface StepsTreeProps {
root: StepInfoNode
selectedStepId: number
onAddChildren: (parent: StepInfoNode) => void
onRemoveNode: (node: StepInfoNode) => void
onStepSelected: (node: StepInfoNode) => void
}
export default function StepsTree({
root,
selectedStepId,
onAddChildren,
onRemoveNode,
onStepSelected,
}: StepsTreeProps) {
return (
<div className="steps-tree">
<StepsTreeNode
node={root}
rootNode={root}
selectedStepId={selectedStepId}
onAddChildren={onAddChildren}
onRemoveNode={onRemoveNode}
onStepSelected={onStepSelected}
/>
</div>
)
}
interface StepsTreeContentProps {
node: StepInfoNode
rootNode: StepInfoNode
selectedStepId: number
onAddChildren: (parent: StepInfoNode) => void
onRemoveNode: (node: StepInfoNode) => void
onStepSelected: (node: StepInfoNode) => void
}
function StepsTreeNode({
node,
rootNode,
selectedStepId,
onAddChildren,
onRemoveNode,
onStepSelected,
}: StepsTreeContentProps) {
const ref = useRef<HTMLDivElement>(null)
return (
<div ref={ref} className={"step-group"}>
{node.children.map((child) => (
<BendableArrow
key={child.id}
area={ref}
startPos={"step-piece-" + node.id}
segments={[
{
next: "step-piece-" + child.id,
},
]}
onSegmentsChanges={() => {}}
forceStraight={true}
wavy={false}
readOnly={true}
//TODO remove magic constants
startRadius={10}
endRadius={10}
/>
))}
<StepPiece
id={node.id}
isSelected={selectedStepId === node.id}
onAddButtonClicked={() => onAddChildren(node)}
onRemoveButtonClicked={
rootNode.id === node.id
? undefined
: () => onRemoveNode(node)
}
onSelected={() => onStepSelected(node)}>
<p>
{useMemo(
() => getStepName(rootNode, node.id),
[node.id, rootNode],
)}
</p>
</StepPiece>
<div className={"step-children"}>
{node.children.map((child) => (
<StepsTreeNode
key={child.id}
rootNode={rootNode}
selectedStepId={selectedStepId}
node={child}
onAddChildren={onAddChildren}
onRemoveNode={onRemoveNode}
onStepSelected={onStepSelected}
/>
))}
</div>
</div>
)
}
interface StepPieceProps {
id: number
isSelected: boolean
onAddButtonClicked?: () => void
onRemoveButtonClicked?: () => void
onSelected: () => void
children?: ReactNode
}
function StepPiece({
id,
isSelected,
onAddButtonClicked,
onRemoveButtonClicked,
onSelected,
children,
}: StepPieceProps) {
return (
<div
id={"step-piece-" + id}
tabIndex={1}
className={
"step-piece " + (isSelected ? "step-piece-selected" : "")
}
onClick={onSelected}>
<div className="step-piece-actions">
{onAddButtonClicked && (
<AddSvg
onClick={onAddButtonClicked}
className={"add-icon"}
/>
)}
{onRemoveButtonClicked && (
<RemoveSvg
onClick={onRemoveButtonClicked}
className={"remove-icon"}
/>
)}
</div>
{children}
</div>
)
}