Untitled

 avatar
unknown
plain_text
a year ago
4.5 kB
16
Indexable
interface Item {
  id: string;
  index: number;
  isRoot?: boolean;
  level: number; // Track the depth for rendering
  children: Item[];
}

class TreeNode {
  data: Item;
  children: TreeNode[];

  constructor(data: Item) {
    this.data = data;
    this.children = [];
    // Initialize level at the TreeNode for rendering purposes
    this.data.level = this.data.level ?? 0;
  }

  addChild(child: TreeNode): void {
    child.data.level = this.data.level + 1; // Increment child level based on parent
    this.children.push(child);
  }
}

class Forest {
  roots: TreeNode[];

  constructor() {
    this.roots = [];
  }

  addNode(newNodeData: Item, parentId: string | null): void {
    const newNode = new TreeNode(newNodeData);
    if (parentId === null) {
      this.roots.push(newNode);
    } else {
      let parentFound = false;
      for (const root of this.roots) {
        const parent = this.findNode(root, parentId);
        if (parent) {
          parent.addChild(newNode);
          parentFound = true;
          break;
        }
      }
      if (!parentFound) {
        throw new Error(`Parent with id ${parentId} not found.`);
      }
    }
  }

  findNode(current: TreeNode | null, id: string): TreeNode | null {
    if (!current) return null;
    if (current.data.id === id) {
      return current;
    }
    for (const child of current.children) {
      const result = this.findNode(child, id);
      if (result) {
        return result;
      }
    }
    return null;
  }

  flatten(): Item[] {
    return this.roots.flatMap(root => flat(root));
  }
}

function flat(node: TreeNode | null): Item[] {
  let result: Item[] = [];
  if (node) {
    result.push(node.data);
    node.children.forEach(child => {
      result = result.concat(flat(child));
    });
  }
  return result;
}

// Initialize the forest and add nodes
const forest = new Forest();
forest.addNode({ id: "item1", index: 0, isRoot: true, children: [], level: 0 }, null);
forest.addNode({ id: "item1child1", index: 1, children: [], level: 1 }, "item1");
forest.addNode({ id: "item1child2", index: 2, children: [], level: 1 }, "item1");
forest.addNode({ id: "item2", index: 3, isRoot: true, children: [], level: 0 }, null);
forest.addNode({ id: "item2child1", index: 4, children: [], level: 1 }, "item2");
forest.addNode({ id: "item2child2", index: 5, children: [], level: 1 }, "item2");
forest.addNode({ id: "item2child2child1", index: 6, children: [], level: 2 }, "item2child2");
forest.addNode({ id: "item2child1child1", index: 7, children: [], level: 2 }, "item2child1");
forest.addNode({ id: "item2child1child1child1", index: 8, children: [], level: 3 }, "item2child1child1");

// Flatten the forest for rendering
let items = forest.flatten();

const { DetailsList, Selection, SelectionMode, CheckboxVisibility } = window.FluentUIReact;

let defaultRenderFn;
const getColumns = (level: number) => {
  return [
    {
      key: "id",
      minWidth: 20,
      name: "ID",
      onRender: (item: Item) => <span style={{paddingLeft: `${20 * item.level}px`}}>{item.id}</span>
    }
  ];
};

const RowWithChildren = (props: any) => {
  return defaultRenderFn({
    ...props,
    itemIndex: props.item.index,
    key: props.item.id,
    columns: getColumns(props.item.level),
    styles: { root: { paddingLeft: `${20 * props.item.level}px` } },
  });
};

const onRenderRow = (props: any, defaultRender: any) => {
  defaultRenderFn = defaultRender;
  return <RowWithChildren {...props} item={props.item} level={props.item.level} />;
};

const Content = () => {
  const [count, setCount] = React.useState(0);
  const selection = new Selection({
    onSelectionChanged: () => {
      setCount(selection.getSelection().length);
    },
    getKey: (item: Item) => item.id
  });

  const styles = {
    root: {
      selectors: {
        ".ms-List-cell:empty": {
          display: "none"
        }
      }
    },
  };

  return (
    <div>
      <span>{count} rows selected</span>
      <DetailsList
        items={items}
        columns={getColumns(0)}
        onRenderRow={onRenderRow}
        selection={selection}
        selectionMode={SelectionMode.multiple}
        selectionPreservedOnEmptyClick={true}
        checkboxVisibility={CheckboxVisibility.always}
        styles={styles}
      />
    </div>
  );
};

ReactDOM.render(<Content />, document.getElementById("content"));
Editor is loading...
Leave a Comment