directory_tree 1.0.0
directory_tree: ^1.0.0 copied to clipboard
Deterministic directory tree builder for Dart.
Directory Tree #
Deterministic virtual tree builder for Dart and Flutter UIs. The package keeps track of source paths, selection state, and expansion flags so you can render a consistent file browser, diff viewer, or project navigator across platforms.
Why use it? #
- maps flat file scans into a stable hierarchical structure
- supports virtual nodes alongside real files
- works with multiple source roots and custom root labels
- canonicalizes Windows and POSIX paths into a single deterministic shape
- deterministic folder IDs (including nested folders) that survive rebuilds for smooth UI updates
Quick start #
Add the dependency to your pubspec.yaml:
dependencies:
directory_tree: ^1.0.0
Build a tree:
final builder = TreeBuilder();
final tree = builder.build(
entries: [
const TreeEntry(
id: 'readme',
name: 'README.md',
fullPath: '/repo/README.md',
),
],
sourceRoots: const ['/repo'],
);
final repoFolderId = tree.nodes.values
.firstWhere((n) => n.type == NodeType.folder && n.name == 'repo')
.id;
final children = tree.nodes[repoFolderId]!.childIds;
// Render from the smart visible root
final startId = tree.visibleRootId;
Flattening & Rendering #
To render the tree (e.g., in a ListView), convert the graph into a flat list using a FlattenStrategy.
// 1. Define which nodes are expanded
final expandedIds = <String>{tree.rootId, ...};
// 2. Flatten the tree
final strategy = const DefaultFlattenStrategy();
final visibleRows = strategy.flatten(
data: tree,
expandedIds: expandedIds,
);
// 3. Render
for (final row in visibleRows) {
print('${" " * row.depth} ${row.name}');
}
Efficient Updates #
Use diffVisibleNodes to compute the minimal changes between two states. This is ideal for Flutter's AnimatedList:
final diff = diffVisibleNodes(oldList, newList);
// diff.removeIndicesDesc -> Remove items
// diff.insertIndicesAsc -> Insert items
Configuration options #
TreeBuilder.build accepts flags to fine-tune output:
expandFoldersByDefaulttoggles initial expansion stateselectNewFilesByDefaultselects files the first time they appearpreferDeepestRootbreaks ties when multiple source roots matchstripPrefixesnormalizes absolute paths into project-relative onessortChildrenByNameenforces alphabetical folder-then-file orderingautoPickVisibleRoothoists away redundant single-folder chains for displayvisibleRootMaxHoistLevelslimits how far hoisting can travel (default 2)visibleRootIgnoreVirtualFileskeeps scratch entries from blocking hoistsmergeVirtualIntoRealFolderslets metadata folders reuse matching real directories- Virtual entries can set
metadata['virtualParent'](e.g.notes/daily) to group them inside virtual folders under/treeor attach to existing real folders (e.g.repo/notes)
Example #
Run the console sample in example/ for a full demonstration:
cd example
dart pub get
dart run
Development #
dart format .dart analyzedart test
Pull requests are welcome -- please include tests for new behaviors.