import {FC, HTMLProps, PropsWithChildren, useMemo} from "react"; import styles from './ProducingGraph.module.css' import {EntityIcon} from "../../home/EntityIcon/EntityIcon"; import {sortByProperty} from "../../../src/utils"; import {EnrichedEntity, Recipe} from "../../../src/types"; interface GraphNodeBase { inputs: string[] outputs: string[] name: string } export type GraphNode> = GraphNodeBase & T interface Props { nodes: GraphNode[] inputs: string[] outputs?: string[] childType: FC & {node: GraphNode}> } export const ProducingGraph = ,>({nodes, inputs, outputs, childType: ChildType}: PropsWithChildren>) => { const rows: GraphNode[][] = useMemo(() => { const available = new Set(inputs) let todo = [...nodes] const result: GraphNode[][] = [] while (todo.length) { const amount = todo.length const thisRow: string[] = [] result.push([]) todo = todo.filter((node) => { if (node.inputs.every(input => available.has(input))) { result[result.length - 1].push(node) thisRow.push(...node.outputs) return false } return true }) thisRow.map(uid => available.add(uid)) result[result.length - 1].sort(sortByProperty(val => -val.outputs.length * 1000 + -val.inputs.length)) if (amount === todo.length) { console.warn("Loop detected! Left over:", todo) result.pop() break } } return result }, [inputs, nodes]) return {inputs.map((input, idx) => )} {rows.map((row, colIdx) => { return { row.map((node) => ) } })} {outputs ? {outputs.map((input, idx) => )} : null } }