xref: /expo/docs/ui/components/FileTree/index.tsx (revision ae9cd511)
1import { FileCode01Icon, FolderIcon } from '@expo/styleguide-icons';
2import { HTMLAttributes, ReactNode } from 'react';
3
4type FileTreeProps = HTMLAttributes<HTMLDivElement> & {
5  files?: string[];
6};
7
8type FileObject = {
9  [key: string]: FileObject;
10};
11
12export function FileTree({ files = [], ...rest }: FileTreeProps) {
13  return (
14    <div className="text-xs border border-default rounded-md bg-default mb-4 p-2 pb-4" {...rest}>
15      {renderStructure(generateStructure(files))}
16    </div>
17  );
18}
19
20function generateStructure(files: string[]): FileObject {
21  const structure = {};
22  files.forEach(path =>
23    path.split('/').reduce((acc: FileObject, key) => acc[key] ?? (acc[key] = {}), structure)
24  );
25  return structure;
26}
27
28function renderStructure(structure: FileObject, level = 0): ReactNode {
29  return Object.entries(structure).map(([key, value]) => {
30    return Object.keys(value).length ? (
31      <div className="mt-1 pt-1 px-2 rounded-sm flex flex-col">
32        <div className="flex items-center">
33          {' '.repeat(level)}
34          <FolderIcon className="text-icon-tertiary mr-2 opacity-60" />
35          <code className="text-secondary">{key}</code>
36        </div>
37        {renderStructure(value, level + 1)}
38      </div>
39    ) : (
40      <div className="mt-1 pl-3 pt-1 px-2 rounded-sm flex items-center">
41        {' '.repeat(level - 1)}
42        <FileCode01Icon className="text-icon-tertiary mr-2" />
43        <code className="text-default">{key}</code>
44      </div>
45    );
46  });
47}
48