Skip to content

Commit f5f3b80

Browse files
feat(file-tree): Enable dynamic addition of file tree elements via symbol parsing
1 parent 9f44b4c commit f5f3b80

2 files changed

Lines changed: 66 additions & 30 deletions

File tree

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,48 @@
11
export const joinTextContent = (text: string): string[] => {
22
return text.split(', ');
33
};
4+
5+
// Symbol -> + Folder - Subfolder * File
6+
export interface FileTreeItem {
7+
type: 'folder' | 'subfolder' | 'file';
8+
text: string;
9+
}
10+
11+
export const parseFileTreeText = (text: string): FileTreeItem[] => {
12+
return text
13+
.split(',')
14+
.map(line => {
15+
const trimmed = line.trim();
16+
17+
if (trimmed === '') return null;
18+
19+
// Detect symbol
20+
if (trimmed.startsWith('+ ')) {
21+
return {
22+
type: 'folder',
23+
text: trimmed.substring(2).trim(),
24+
};
25+
}
26+
27+
if (trimmed.startsWith('- ')) {
28+
return {
29+
type: 'subfolder',
30+
text: trimmed.substring(2).trim(),
31+
};
32+
}
33+
34+
if (trimmed.startsWith('* ')) {
35+
return {
36+
type: 'file',
37+
text: trimmed.substring(2).trim(),
38+
};
39+
}
40+
41+
// No symbol: will be treated as a folder
42+
return {
43+
type: 'folder',
44+
text: trimmed,
45+
};
46+
})
47+
.filter((item): item is FileTreeItem => item !== null);
48+
};

src/common/components/mock-components/front-rich-components/file-tree/file-tree.tsx

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { useGroupShapeProps } from '../../mock-components.utils';
77
import { loadSvgWithFill } from '@/common/utils/svg.utils';
88
import { useShapeProps } from '@/common/components/shapes/use-shape-props.hook';
99
import { BASIC_SHAPE } from '../../front-components/shape.const';
10-
import { joinTextContent } from './file-tree.business';
10+
import { parseFileTreeText } from './file-tree.business';
1111

1212
const fileTreeShapeRestrictions: ShapeSizeRestrictions = {
1313
minWidth: 220,
@@ -22,13 +22,6 @@ interface FileTreeShapeProps extends ShapeProps {
2222
text: string;
2323
}
2424

25-
type IconType = 'folder' | 'subfolder' | 'file';
26-
27-
interface IconState {
28-
type: IconType;
29-
value: HTMLImageElement | null;
30-
}
31-
3225
const shapeType: ShapeType = 'fileTree';
3326

3427
export const getFileTreeShapeSizeRestrictions = (): ShapeSizeRestrictions =>
@@ -48,14 +41,15 @@ export const FileTreeShape = forwardRef<any, FileTreeShapeProps>(
4841
...shapeProps
4942
} = props;
5043

51-
const treeTitles = joinTextContent(text);
44+
const treeItems = parseFileTreeText(text);
5245

53-
const [icons, setIcons] = useState<IconState[]>([
54-
{ type: 'folder', value: null },
55-
{ type: 'subfolder', value: null },
56-
{ type: 'file', value: null },
57-
{ type: 'folder', value: null },
58-
]);
46+
const [icons, setIcons] = useState<Record<string, HTMLImageElement | null>>(
47+
{
48+
folder: null,
49+
subfolder: null,
50+
file: null,
51+
}
52+
);
5953

6054
const restrictedSize = fitSizeToShapeSizeRestrictions(
6155
fileTreeShapeRestrictions,
@@ -93,12 +87,11 @@ export const FileTreeShape = forwardRef<any, FileTreeShapeProps>(
9387
loadSvgWithFill('/icons/open.svg', stroke),
9488
loadSvgWithFill('/icons/new.svg', stroke),
9589
]).then(([folder, subfolder, file]) => {
96-
setIcons([
97-
{ type: 'folder', value: folder },
98-
{ type: 'subfolder', value: subfolder },
99-
{ type: 'file', value: file },
100-
{ type: 'folder', value: folder },
101-
]);
90+
setIcons({
91+
folder,
92+
subfolder,
93+
file,
94+
});
10295
});
10396
}, [stroke]);
10497

@@ -117,25 +110,23 @@ export const FileTreeShape = forwardRef<any, FileTreeShapeProps>(
117110
cornerRadius={borderRadius}
118111
/>
119112

120-
{treeTitles.map((title, index) => (
113+
{treeItems.map((item, index) => (
121114
<Group key={index}>
122-
{icons[index]?.value && (
115+
{icons[item.type] && (
123116
<Image
124-
image={icons[index].value}
125-
x={icons[index].type === 'file' ? fileX : paddingX}
117+
image={icons[item.type]!}
118+
x={item.type === 'file' ? fileX : paddingX}
126119
y={paddingTop + elementHeight * index}
127120
width={iconWidth}
128121
height={iconWidth}
129122
/>
130123
)}
131124
<Text
132-
x={icons[index].type === 'file' ? fileTextX : folderTextX}
125+
x={item.type === 'file' ? fileTextX : folderTextX}
133126
y={paddingTop + elementHeight * index + 20}
134-
text={title}
127+
text={item.text}
135128
width={
136-
icons[index].type === 'file'
137-
? fileAvailableWidth
138-
: folderAvailableWidth
129+
item.type === 'file' ? fileAvailableWidth : folderAvailableWidth
139130
}
140131
height={elementHeight}
141132
fontFamily={BASIC_SHAPE.DEFAULT_FONT_FAMILY}

0 commit comments

Comments
 (0)