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.
156 lines
4.5 KiB
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>
|
|
)
|
|
}
|