text: // @flow
  import * as React from 'react';
  import {
    type Filters,
    type TagsTreeNode,
  } from '../../Utils/GDevelopServices/Types.flow';
  import TreeView from '@material-ui/lab/TreeView';
  import TreeItem from '@material-ui/lab/TreeItem';
  import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
  import ChevronRightIcon from '@material-ui/icons/ChevronRight';
  import PlaceholderLoader from '../PlaceholderLoader';
  import { type FiltersState, type ChosenCategory } from './FiltersChooser';
  
  const nodeIdSeparator = ';-/>'; // A seemingly random string to ensure no clashes with tag names.
  const toNodeId = (nodes: Array<TagsTreeNode>) =>
    nodes.map(node => node.name).join(nodeIdSeparator);
  
  const TagsTreeItems = ({
    tagsTreeNodes,
    onChoose,
    parentNodes,
  }: {|
    parentNodes: Array<TagsTreeNode>,
    tagsTreeNodes: Array<TagsTreeNode>,
    onChoose: ChosenCategory => void,
  |}) => {
    if (!tagsTreeNodes.length) return null;
  
    return tagsTreeNodes.map(node => {
      const newParentNodes = [...parentNodes, node];
      return (
        <TreeItem
          nodeId={toNodeId(newParentNodes)}
          label={node.name}
          key={node.name}
          onLabelClick={() => onChoose({ node, parentNodes })}
          collapseIcon={node.children.length ? <ExpandMoreIcon /> : null}
          expandIcon={node.children.length ? <ChevronRightIcon /> : null}
        >
          <TagsTreeItems
            tagsTreeNodes={node.children}
            parentNodes={newParentNodes}
            onChoose={onChoose}
          />
        </TreeItem>
      );
    });
  };
  
  type MemoizedTagsTreeProps = {|
    allItemsLabel: React.Node,
    chosenCategory: ?ChosenCategory,
    setChosenCategory: (?ChosenCategory) => void,
    allFilters: Filters,
  |};
  
  const MemoizedTagsTree = React.memo<MemoizedTagsTreeProps>(function TagsTree({
    allItemsLabel,
    chosenCategory,
    setChosenCategory,
    allFilters,
  }: MemoizedTagsTreeProps) {
    return (
      <TreeView
        selected={
          chosenCategory
            ? toNodeId([...chosenCategory.parentNodes, chosenCategory.node])
            : ''
        }
        defaultExpanded={allFilters.tagsTree.map(node => toNodeId([node]))}
        onNodeSelect={() => {}}
      >
        <TreeItem
          nodeId=""
          label={allItemsLabel}
          onLabelClick={() => setChosenCategory(null)}
        />
        <TagsTreeItems
          tagsTreeNodes={allFilters.tagsTree}
          onChoose={setChosenCategory}
          parentNodes={[]}
        />
      </TreeView>
    );
  });
  
  type Props = {|
    allItemsLabel: React.Node,
    filtersState: FiltersState,
    allFilters: ?Filters,
    error: ?Error,
  |};
  
  export const CategoryChooser = ({
    filtersState,
    allFilters,
    error,
    allItemsLabel,
  }: Props) => {
    if (!allFilters) {
      return <PlaceholderLoader />;
    }
    if (error) {
      // Error and retry button shown somewhere else in the UI
      return null;
    }
  
    return (
      <MemoizedTagsTree
        allItemsLabel={allItemsLabel}
        chosenCategory={filtersState.chosenCategory}
        setChosenCategory={filtersState.setChosenCategory}
        allFilters={allFilters}
      />
    );
  };
  