@anymux/ui-kit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ExplorerLayout-CSIJd7N4.js +105 -0
- package/dist/ExplorerLayout-CSIJd7N4.js.map +1 -0
- package/dist/FileBrowserContext-B6jixa2j.js +11 -0
- package/dist/FileBrowserContext-B6jixa2j.js.map +1 -0
- package/dist/calendar-DSlrbHoj.js +761 -0
- package/dist/calendar-DSlrbHoj.js.map +1 -0
- package/dist/calendar.d.ts +3 -0
- package/dist/calendar.js +3 -0
- package/dist/contacts-DQXTZzHc.js +539 -0
- package/dist/contacts-DQXTZzHc.js.map +1 -0
- package/dist/contacts.d.ts +3 -0
- package/dist/contacts.js +3 -0
- package/dist/file-browser-m5atC3kF.js +6755 -0
- package/dist/file-browser-m5atC3kF.js.map +1 -0
- package/dist/file-browser.d.ts +11 -0
- package/dist/file-browser.js +9 -0
- package/dist/git-B55e6LL-.js +561 -0
- package/dist/git-B55e6LL-.js.map +1 -0
- package/dist/git.d.ts +2 -0
- package/dist/git.js +3 -0
- package/dist/iconMap-V4B8P-Uh.js +206 -0
- package/dist/iconMap-V4B8P-Uh.js.map +1 -0
- package/dist/icons-CIsIOZXR.js +0 -0
- package/dist/icons.d.ts +2 -0
- package/dist/icons.js +4 -0
- package/dist/index-BNmNIWBL.d.ts +71 -0
- package/dist/index-BNmNIWBL.d.ts.map +1 -0
- package/dist/index-Bryv_GCG.d.ts +1481 -0
- package/dist/index-Bryv_GCG.d.ts.map +1 -0
- package/dist/index-CuQIjSXs.d.ts +134 -0
- package/dist/index-CuQIjSXs.d.ts.map +1 -0
- package/dist/index-DSu19mq0.d.ts +153 -0
- package/dist/index-DSu19mq0.d.ts.map +1 -0
- package/dist/index-DmsyeHFr.d.ts +149 -0
- package/dist/index-DmsyeHFr.d.ts.map +1 -0
- package/dist/index-DxnJ8FYM.d.ts +17 -0
- package/dist/index-DxnJ8FYM.d.ts.map +1 -0
- package/dist/index-DzfY1Tok.d.ts +32 -0
- package/dist/index-DzfY1Tok.d.ts.map +1 -0
- package/dist/index-Ml_SgiKa.d.ts +1847 -0
- package/dist/index-Ml_SgiKa.d.ts.map +1 -0
- package/dist/index-kHr9udZD.d.ts +1025 -0
- package/dist/index-kHr9udZD.d.ts.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +15 -0
- package/dist/layout-Ca_4r8ka.js +89 -0
- package/dist/layout-Ca_4r8ka.js.map +1 -0
- package/dist/layout.d.ts +2 -0
- package/dist/layout.js +5 -0
- package/dist/list-CxfT6hix.js +6831 -0
- package/dist/list-CxfT6hix.js.map +1 -0
- package/dist/list.d.ts +2 -0
- package/dist/list.js +5 -0
- package/dist/media-DZ292aKK.js +557 -0
- package/dist/media-DZ292aKK.js.map +1 -0
- package/dist/media.d.ts +3 -0
- package/dist/media.js +3 -0
- package/dist/tree-Dd9Z0Aso.js +3351 -0
- package/dist/tree-Dd9Z0Aso.js.map +1 -0
- package/dist/tree.d.ts +2 -0
- package/dist/tree.js +6 -0
- package/dist/types-common-CB3kRek8.d.ts +26 -0
- package/dist/types-common-CB3kRek8.d.ts.map +1 -0
- package/dist/utils-B4fdKKsy.js +3 -0
- package/package.json +109 -0
- package/src/calendar/AgendaView.tsx +37 -0
- package/src/calendar/CalendarBrowser.tsx +90 -0
- package/src/calendar/CalendarModel.ts +142 -0
- package/src/calendar/CalendarSidebar.tsx +81 -0
- package/src/calendar/DayView.tsx +76 -0
- package/src/calendar/EventCard.tsx +51 -0
- package/src/calendar/MockCalendarProvider.ts +98 -0
- package/src/calendar/MonthView.tsx +77 -0
- package/src/calendar/WeekView.tsx +129 -0
- package/src/calendar/index.ts +18 -0
- package/src/calendar/types.ts +25 -0
- package/src/contacts/ContactAvatar.tsx +35 -0
- package/src/contacts/ContactBrowser.tsx +56 -0
- package/src/contacts/ContactCard.tsx +37 -0
- package/src/contacts/ContactDetail.tsx +63 -0
- package/src/contacts/ContactGroupSidebar.tsx +40 -0
- package/src/contacts/ContactList.tsx +32 -0
- package/src/contacts/ContactListModel.ts +120 -0
- package/src/contacts/MockContactProvider.ts +77 -0
- package/src/contacts/index.ts +17 -0
- package/src/contacts/types.ts +26 -0
- package/src/demos/CalendarBrowserDemo.tsx +15 -0
- package/src/demos/ContactBrowserDemo.tsx +15 -0
- package/src/demos/MediaBrowserDemo.tsx +15 -0
- package/src/file-browser/adapters/DocumentViewerAdapter.ts +371 -0
- package/src/file-browser/adapters/FileSystemBridge.ts +168 -0
- package/src/file-browser/adapters/GitBrowserAdapter.ts +546 -0
- package/src/file-browser/adapters/README.md +504 -0
- package/src/file-browser/adapters/index.ts +27 -0
- package/src/file-browser/adapters/types.ts +70 -0
- package/src/file-browser/architecture.md +645 -0
- package/src/file-browser/components/CreateItemDialog.tsx +71 -0
- package/src/file-browser/components/DeleteConfirmDialog.tsx +58 -0
- package/src/file-browser/components/FileBrowser.tsx +473 -0
- package/src/file-browser/components/FileBrowserContent.tsx +209 -0
- package/src/file-browser/components/FileBrowserHeader.tsx +151 -0
- package/src/file-browser/components/FileBrowserToolbar.tsx +145 -0
- package/src/file-browser/components/LeftPanel/LeftPanel.tsx +103 -0
- package/src/file-browser/components/LeftPanel/LeftPanelTabs.tsx +70 -0
- package/src/file-browser/components/LeftPanel/TreeNavigationView.tsx +256 -0
- package/src/file-browser/components/PreviewPane.tsx +146 -0
- package/src/file-browser/components/RightPanel/FilePreview.tsx +219 -0
- package/src/file-browser/components/RightPanel/RightPanel.tsx +186 -0
- package/src/file-browser/components/RightPanel/RightPanelToolbar.tsx +113 -0
- package/src/file-browser/components/UploadProgress.tsx +123 -0
- package/src/file-browser/components/ViewerHost.tsx +208 -0
- package/src/file-browser/components/mobile/MobileNavigation.tsx +227 -0
- package/src/file-browser/components/navigation/NavigationButtons.tsx +171 -0
- package/src/file-browser/components/shared/ErrorBoundary.tsx +116 -0
- package/src/file-browser/components/shared/FileBrowserItem.tsx +195 -0
- package/src/file-browser/components/shared/FileIcon.tsx +169 -0
- package/src/file-browser/components/toolbar/ViewModeToggle.tsx +200 -0
- package/src/file-browser/components/views/ListView/ListView.tsx +484 -0
- package/src/file-browser/components/views/ThumbnailView/ThumbnailView.tsx +323 -0
- package/src/file-browser/components/views/TreeView/TreeNode.tsx +186 -0
- package/src/file-browser/components/views/TreeView/TreeNodeList.tsx +191 -0
- package/src/file-browser/components/views/TreeView/TreeView.tsx +200 -0
- package/src/file-browser/components/views/TreemapView/TreemapView.tsx +339 -0
- package/src/file-browser/context/FileBrowserContext.tsx +13 -0
- package/src/file-browser/examples/BasicUsage.tsx +20 -0
- package/src/file-browser/index.ts +98 -0
- package/src/file-browser/models/FileBrowserModel.ts +623 -0
- package/src/file-browser/models/LeftPanelManagerModel.ts +105 -0
- package/src/file-browser/models/NavigationManagerModel.ts +312 -0
- package/src/file-browser/models/ResponsiveLayoutManagerModel.ts +437 -0
- package/src/file-browser/models/RightPanelManagerModel.ts +190 -0
- package/src/file-browser/models/SelectionManagerModel.ts +252 -0
- package/src/file-browser/models/ToolbarManagerModel.ts +144 -0
- package/src/file-browser/models/UploadModel.ts +147 -0
- package/src/file-browser/models/ViewModeManagerModel.ts +185 -0
- package/src/file-browser/models/ViewerHostModel.ts +44 -0
- package/src/file-browser/models/ui/ListViewUIModel.ts +265 -0
- package/src/file-browser/models/ui/PreviewUIModel.ts +297 -0
- package/src/file-browser/models/ui/ThumbnailViewUIModel.ts +254 -0
- package/src/file-browser/models/ui/TreeViewUIModel.ts +128 -0
- package/src/file-browser/models/ui/TreemapViewUIModel.ts +350 -0
- package/src/file-browser/providers/FileSystemListProvider.ts +552 -0
- package/src/file-browser/providers/FileSystemProvider.ts +401 -0
- package/src/file-browser/providers/FileSystemTreeProvider.ts +231 -0
- package/src/file-browser/providers/GitProvider.ts +337 -0
- package/src/file-browser/providers/GitRepositoryProvider.ts +376 -0
- package/src/file-browser/providers/IFileBrowserProvider.ts +56 -0
- package/src/file-browser/providers/MemoryProvider.ts +303 -0
- package/src/file-browser/providers/index.ts +4 -0
- package/src/file-browser/registry/ViewerRegistry.ts +551 -0
- package/src/file-browser/registry/types.ts +144 -0
- package/src/file-browser/scripts/performanceBenchmark.ts +553 -0
- package/src/file-browser/services/ThumbnailCacheService.ts +128 -0
- package/src/file-browser/tasks.md +537 -0
- package/src/file-browser/types/FileBrowserTypes.ts +126 -0
- package/src/file-browser/types/ProviderTypes.ts +155 -0
- package/src/file-browser/types/UITypes.ts +235 -0
- package/src/file-browser/types/ViewModeTypes.ts +150 -0
- package/src/file-browser/utils/gestures.ts +327 -0
- package/src/file-browser/utils/performance.ts +563 -0
- package/src/file-browser/viewers/ImageViewer.tsx +163 -0
- package/src/file-browser/viewers/ImageViewerModel.ts +79 -0
- package/src/file-browser/viewers/TextViewer.tsx +95 -0
- package/src/file-browser/viewers/UnsupportedFileViewer.tsx +57 -0
- package/src/file-browser/viewers/index.ts +61 -0
- package/src/git/BranchList.tsx +128 -0
- package/src/git/CommitGraph.tsx +239 -0
- package/src/git/CommitList.tsx +258 -0
- package/src/git/DiffViewer.tsx +219 -0
- package/src/git/index.ts +4 -0
- package/src/icons/iconMap.ts +146 -0
- package/src/icons/index.ts +9 -0
- package/src/index.ts +13 -0
- package/src/layout/README.md +307 -0
- package/src/layout/components/ExplorerLayout/ExplorerLayout.tsx +178 -0
- package/src/layout/examples/SimpleExample.tsx +60 -0
- package/src/layout/index.ts +6 -0
- package/src/lib/utils.ts +1 -0
- package/src/list/README.md +303 -0
- package/src/list/architecture.md +807 -0
- package/src/list/components/CalculatedGridView.tsx +252 -0
- package/src/list/components/DragPreview.tsx +102 -0
- package/src/list/components/ListContextMenu.tsx +274 -0
- package/src/list/components/ListItem.tsx +761 -0
- package/src/list/components/ListItems.tsx +919 -0
- package/src/list/components/MasonryView.tsx +241 -0
- package/src/list/components/SearchFilter.tsx +44 -0
- package/src/list/components/TreemapView.tsx +709 -0
- package/src/list/components/ViewSizeControls.tsx +205 -0
- package/src/list/components/ViewTypeSelector.tsx +312 -0
- package/src/list/components/VirtualizedDetailsView.tsx +231 -0
- package/src/list/components/VirtualizedGrid.tsx +164 -0
- package/src/list/components/VirtualizedList.tsx +154 -0
- package/src/list/components/VirtualizedMasonryView.tsx +344 -0
- package/src/list/components/shared/EmptyState.tsx +103 -0
- package/src/list/components/shared/ErrorBoundary.tsx +123 -0
- package/src/list/components/shared/ErrorDisplay.tsx +100 -0
- package/src/list/components/shared/ListLoader.tsx +146 -0
- package/src/list/components/shared/LoadingIndicator.tsx +80 -0
- package/src/list/index.ts +92 -0
- package/src/list/models/ListItemsModel.ts +1301 -0
- package/src/list/models/TreemapModel.ts +204 -0
- package/src/list/providers/ListItemsProvider.ts +313 -0
- package/src/list/providers/TestListProvider.ts +604 -0
- package/src/list/tasks.md +937 -0
- package/src/list/types/ListTypes.ts +178 -0
- package/src/list/utils/BenchmarkLogger.ts +243 -0
- package/src/list/utils/DragDropManager.ts +320 -0
- package/src/list/utils/GridLayoutCalculator.ts +290 -0
- package/src/list/utils/ListAccessibility.ts +367 -0
- package/src/list/utils/ListKeyboard.ts +414 -0
- package/src/list/utils/MasonryLayoutCalculator.ts +302 -0
- package/src/list/utils/MasonryLayoutEngine.ts +401 -0
- package/src/list/utils/__tests__/MasonryLayoutEngine.test.ts +157 -0
- package/src/list/utils/__tests__/VirtualizedMasonryView.test.tsx +251 -0
- package/src/media/AlbumSidebar.tsx +48 -0
- package/src/media/MediaBrowser.tsx +92 -0
- package/src/media/MediaBrowserModel.ts +138 -0
- package/src/media/MediaGrid.tsx +50 -0
- package/src/media/MediaList.tsx +49 -0
- package/src/media/MediaPreview.tsx +63 -0
- package/src/media/MediaTimeline.tsx +38 -0
- package/src/media/MockMediaProvider.ts +70 -0
- package/src/media/index.ts +18 -0
- package/src/media/types.ts +21 -0
- package/src/styles/variables.css +60 -0
- package/src/tree/DEVELOPMENT_SUMMARY.md +170 -0
- package/src/tree/__tests__/TreeModel.test.ts +16 -0
- package/src/tree/architecture.md +530 -0
- package/src/tree/components/Tree.tsx +283 -0
- package/src/tree/components/TreeCheckbox.tsx +147 -0
- package/src/tree/components/TreeContextMenu.tsx +139 -0
- package/src/tree/components/TreeNodeList.tsx +329 -0
- package/src/tree/components/TreeTable.tsx +382 -0
- package/src/tree/index.ts +58 -0
- package/src/tree/models/TreeModel.ts +839 -0
- package/src/tree/providers/SimpleTreeProvider.ts +463 -0
- package/src/tree/providers/TestTreeProvider.ts +946 -0
- package/src/tree/providers/TreeProvider.ts +308 -0
- package/src/tree/tasks.md +2046 -0
- package/src/tree/types/TreeTypes.ts +279 -0
- package/src/tree/utils/SelectionTheme.ts +150 -0
- package/src/tree/utils/logger.ts +203 -0
- package/src/types-common.ts +21 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { observer } from 'mobx-react-lite';
|
|
3
|
+
import { cn } from '../../../../lib/utils';
|
|
4
|
+
import { FileBrowserItem } from '../../../types/FileBrowserTypes';
|
|
5
|
+
import { TreeViewUIModel } from '../../../models/ui/TreeViewUIModel';
|
|
6
|
+
import TreeNodeList from './TreeNodeList';
|
|
7
|
+
|
|
8
|
+
export interface TreeViewProps {
|
|
9
|
+
items: FileBrowserItem[];
|
|
10
|
+
treeModel: TreeViewUIModel;
|
|
11
|
+
onItemClick?: (item: FileBrowserItem) => void;
|
|
12
|
+
onItemDoubleClick?: (item: FileBrowserItem) => void;
|
|
13
|
+
onItemActivate?: (item: FileBrowserItem) => void;
|
|
14
|
+
onSelectionChange?: (selectedItems: FileBrowserItem[]) => void;
|
|
15
|
+
onPathChange?: (path: string) => void;
|
|
16
|
+
selectedItemIds?: Set<string>;
|
|
17
|
+
focusedItemId?: string;
|
|
18
|
+
className?: string;
|
|
19
|
+
getItemIcon?: (item: FileBrowserItem) => any;
|
|
20
|
+
loadFolder?: (path: string) => Promise<FileBrowserItem[]>;
|
|
21
|
+
virtualization?: boolean;
|
|
22
|
+
maxHeight?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const TreeView: React.FC<TreeViewProps> = observer(({
|
|
26
|
+
items,
|
|
27
|
+
treeModel,
|
|
28
|
+
onItemClick,
|
|
29
|
+
onItemDoubleClick,
|
|
30
|
+
onItemActivate,
|
|
31
|
+
onSelectionChange,
|
|
32
|
+
onPathChange,
|
|
33
|
+
selectedItemIds = new Set<string>(),
|
|
34
|
+
focusedItemId,
|
|
35
|
+
className,
|
|
36
|
+
getItemIcon,
|
|
37
|
+
loadFolder,
|
|
38
|
+
virtualization = false,
|
|
39
|
+
maxHeight,
|
|
40
|
+
}) => {
|
|
41
|
+
// Build hierarchical tree structure from flat items array
|
|
42
|
+
const buildTreeStructure = (items: FileBrowserItem[]): FileBrowserItem[] => {
|
|
43
|
+
const itemMap = new Map<string, FileBrowserItem>();
|
|
44
|
+
const rootItems: FileBrowserItem[] = [];
|
|
45
|
+
|
|
46
|
+
// First pass: create map of all items
|
|
47
|
+
items.forEach(item => {
|
|
48
|
+
itemMap.set(item.path, { ...item, children: [] });
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Second pass: build hierarchy
|
|
52
|
+
items.forEach(item => {
|
|
53
|
+
const itemCopy = itemMap.get(item.path);
|
|
54
|
+
if (!itemCopy) return;
|
|
55
|
+
|
|
56
|
+
// Find parent path
|
|
57
|
+
const pathParts = item.path.split('/').filter(Boolean);
|
|
58
|
+
if (pathParts.length === 1) {
|
|
59
|
+
// Root level item
|
|
60
|
+
rootItems.push(itemCopy);
|
|
61
|
+
} else {
|
|
62
|
+
// Find parent
|
|
63
|
+
const parentPath = '/' + pathParts.slice(0, -1).join('/');
|
|
64
|
+
const parent = itemMap.get(parentPath);
|
|
65
|
+
if (parent && parent.children) {
|
|
66
|
+
parent.children.push(itemCopy);
|
|
67
|
+
} else {
|
|
68
|
+
// Parent not found, treat as root item
|
|
69
|
+
rootItems.push(itemCopy);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return rootItems;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const treeItems = React.useMemo(() => {
|
|
78
|
+
return buildTreeStructure(items);
|
|
79
|
+
}, [items]);
|
|
80
|
+
|
|
81
|
+
const handleItemClick = (item: FileBrowserItem) => {
|
|
82
|
+
onItemClick?.(item);
|
|
83
|
+
|
|
84
|
+
// If it's a directory, handle expansion based on settings
|
|
85
|
+
if (item.type === 'directory') {
|
|
86
|
+
if (treeModel.expandOnSingleClick) {
|
|
87
|
+
treeModel.toggleFolder(item.path);
|
|
88
|
+
|
|
89
|
+
// Load folder contents if needed
|
|
90
|
+
if (!treeModel.isFolderExpanded(item.path) && loadFolder) {
|
|
91
|
+
handleFolderLoad(item.path);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const handleItemDoubleClick = (item: FileBrowserItem) => {
|
|
98
|
+
onItemDoubleClick?.(item);
|
|
99
|
+
onItemActivate?.(item);
|
|
100
|
+
|
|
101
|
+
// Handle directory navigation or file activation
|
|
102
|
+
if (item.type === 'directory') {
|
|
103
|
+
// Navigate to directory or toggle expansion
|
|
104
|
+
if (treeModel.collapseOnSecondClick && treeModel.isFolderExpanded(item.path)) {
|
|
105
|
+
treeModel.collapseFolder(item.path);
|
|
106
|
+
} else {
|
|
107
|
+
onPathChange?.(item.path);
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
// File activation
|
|
111
|
+
onItemActivate?.(item);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const handleFolderLoad = async (folderPath: string) => {
|
|
116
|
+
if (!loadFolder) return;
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
treeModel.logger?.info(`Loading folder: ${folderPath}`);
|
|
120
|
+
const folderItems = await loadFolder(folderPath);
|
|
121
|
+
|
|
122
|
+
// Update the item in the tree to include children
|
|
123
|
+
// This would need integration with the parent model
|
|
124
|
+
treeModel.logger?.info(`Loaded ${folderItems.length} items for ${folderPath}`);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
treeModel.logger?.error(`Failed to load folder ${folderPath}:`, error);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// Handle folder expansion when state changes
|
|
131
|
+
useEffect(() => {
|
|
132
|
+
const expandedFolders = treeModel.expandedFoldersArray;
|
|
133
|
+
|
|
134
|
+
// Load contents for newly expanded folders
|
|
135
|
+
expandedFolders.forEach((folderPath: string) => {
|
|
136
|
+
// Check if folder needs loading (doesn't have children but should)
|
|
137
|
+
const item = items.find(item => item.path === folderPath);
|
|
138
|
+
if (item &&
|
|
139
|
+
item.type === 'directory' &&
|
|
140
|
+
(!item.children || item.children.length === 0) &&
|
|
141
|
+
item.hasChildren &&
|
|
142
|
+
loadFolder) {
|
|
143
|
+
handleFolderLoad(folderPath);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}, [items, loadFolder]);
|
|
147
|
+
|
|
148
|
+
// Keyboard shortcuts
|
|
149
|
+
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
150
|
+
switch (e.key) {
|
|
151
|
+
case 'a':
|
|
152
|
+
if (e.ctrlKey || e.metaKey) {
|
|
153
|
+
e.preventDefault();
|
|
154
|
+
treeModel.expandAll();
|
|
155
|
+
}
|
|
156
|
+
break;
|
|
157
|
+
case 'c':
|
|
158
|
+
if (e.ctrlKey || e.metaKey) {
|
|
159
|
+
e.preventDefault();
|
|
160
|
+
treeModel.collapseAll();
|
|
161
|
+
}
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
if (!treeItems || treeItems.length === 0) {
|
|
167
|
+
return (
|
|
168
|
+
<div className={cn('p-4 text-center text-muted-foreground', className)}>
|
|
169
|
+
<p className="text-sm">No folders or files to display</p>
|
|
170
|
+
</div>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return (
|
|
175
|
+
<div
|
|
176
|
+
className={cn('tree-view h-full overflow-hidden', className)}
|
|
177
|
+
onKeyDown={handleKeyDown}
|
|
178
|
+
role="tree"
|
|
179
|
+
aria-label="File tree view"
|
|
180
|
+
>
|
|
181
|
+
<TreeNodeList
|
|
182
|
+
items={treeItems}
|
|
183
|
+
treeModel={treeModel}
|
|
184
|
+
onItemClick={handleItemClick}
|
|
185
|
+
onItemDoubleClick={handleItemDoubleClick}
|
|
186
|
+
onSelectionChange={onSelectionChange}
|
|
187
|
+
selectedItemIds={selectedItemIds}
|
|
188
|
+
focusedItemId={focusedItemId}
|
|
189
|
+
getItemIcon={getItemIcon}
|
|
190
|
+
virtualization={virtualization}
|
|
191
|
+
maxHeight={maxHeight}
|
|
192
|
+
className="h-full"
|
|
193
|
+
/>
|
|
194
|
+
</div>
|
|
195
|
+
);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
TreeView.displayName = 'TreeView';
|
|
199
|
+
|
|
200
|
+
export default TreeView;
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import React, { useRef, useEffect, useState } from 'react';
|
|
2
|
+
import { observer } from 'mobx-react-lite';
|
|
3
|
+
import { cn } from '../../../../lib/utils';
|
|
4
|
+
import { FileBrowserItem } from '../../../types/FileBrowserTypes';
|
|
5
|
+
import { TreemapViewUIModel, TreemapNode } from '../../../models/ui/TreemapViewUIModel';
|
|
6
|
+
import { EmptyState } from '@anymux/ui/components/empty-state';
|
|
7
|
+
|
|
8
|
+
export interface TreemapViewProps {
|
|
9
|
+
items: FileBrowserItem[];
|
|
10
|
+
treemapModel: TreemapViewUIModel;
|
|
11
|
+
onItemClick?: (item: FileBrowserItem) => void;
|
|
12
|
+
onItemDoubleClick?: (item: FileBrowserItem) => void;
|
|
13
|
+
onItemActivate?: (item: FileBrowserItem) => void;
|
|
14
|
+
onSelectionChange?: (selectedItems: FileBrowserItem[]) => void;
|
|
15
|
+
selectedItemIds?: Set<string>;
|
|
16
|
+
focusedItemId?: string;
|
|
17
|
+
className?: string;
|
|
18
|
+
maxHeight?: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const TreemapView: React.FC<TreemapViewProps> = observer(({
|
|
22
|
+
items,
|
|
23
|
+
treemapModel,
|
|
24
|
+
onItemClick,
|
|
25
|
+
onItemDoubleClick,
|
|
26
|
+
onItemActivate,
|
|
27
|
+
onSelectionChange,
|
|
28
|
+
selectedItemIds = new Set<string>(),
|
|
29
|
+
focusedItemId,
|
|
30
|
+
className,
|
|
31
|
+
maxHeight,
|
|
32
|
+
}) => {
|
|
33
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
34
|
+
const [containerSize, setContainerSize] = useState({ width: 0, height: 0 });
|
|
35
|
+
const [treemapNodes, setTreemapNodes] = useState<TreemapNode[]>([]);
|
|
36
|
+
|
|
37
|
+
// Handle container resize
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const updateContainerSize = () => {
|
|
40
|
+
if (containerRef.current) {
|
|
41
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
42
|
+
setContainerSize({
|
|
43
|
+
width: rect.width,
|
|
44
|
+
height: rect.height || 400, // Default height
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
updateContainerSize();
|
|
50
|
+
|
|
51
|
+
const resizeObserver = new ResizeObserver(updateContainerSize);
|
|
52
|
+
if (containerRef.current) {
|
|
53
|
+
resizeObserver.observe(containerRef.current);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return () => {
|
|
57
|
+
resizeObserver.disconnect();
|
|
58
|
+
};
|
|
59
|
+
}, []);
|
|
60
|
+
|
|
61
|
+
// Calculate treemap layout when items or container size changes
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (containerSize.width > 0 && containerSize.height > 0 && items.length > 0) {
|
|
64
|
+
const nodes = treemapModel.calculateTreemapLayout(
|
|
65
|
+
items,
|
|
66
|
+
containerSize.width,
|
|
67
|
+
containerSize.height
|
|
68
|
+
);
|
|
69
|
+
setTreemapNodes(nodes);
|
|
70
|
+
}
|
|
71
|
+
}, [items, containerSize, treemapModel]);
|
|
72
|
+
|
|
73
|
+
const handleItemClick = (item: FileBrowserItem, event: React.MouseEvent) => {
|
|
74
|
+
event.stopPropagation();
|
|
75
|
+
onItemClick?.(item);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const handleItemDoubleClick = (item: FileBrowserItem, event: React.MouseEvent) => {
|
|
79
|
+
event.stopPropagation();
|
|
80
|
+
onItemDoubleClick?.(item);
|
|
81
|
+
onItemActivate?.(item);
|
|
82
|
+
|
|
83
|
+
// Handle drill-down for directories
|
|
84
|
+
if (item.type === 'directory' && treemapModel.enableDrillDown) {
|
|
85
|
+
treemapModel.drillDown(item.id);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const handleNodeClick = (node: TreemapNode, event: React.MouseEvent) => {
|
|
90
|
+
const item = items.find(item => item.id === node.id);
|
|
91
|
+
if (item) {
|
|
92
|
+
handleItemClick(item, event);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const handleNodeDoubleClick = (node: TreemapNode, event: React.MouseEvent) => {
|
|
97
|
+
const item = items.find(item => item.id === node.id);
|
|
98
|
+
if (item) {
|
|
99
|
+
handleItemDoubleClick(item, event);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const renderTreemapNode = (node: TreemapNode) => {
|
|
104
|
+
const isSelected = selectedItemIds.has(node.id);
|
|
105
|
+
const isFocused = focusedItemId === node.id;
|
|
106
|
+
const item = items.find(item => item.id === node.id);
|
|
107
|
+
|
|
108
|
+
if (!item || node.width < treemapModel.effectiveMinTileSize || node.height < treemapModel.effectiveMinTileSize) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const showLabel = treemapModel.showLabels &&
|
|
113
|
+
node.width > 60 &&
|
|
114
|
+
node.height > 30;
|
|
115
|
+
|
|
116
|
+
const showSize = treemapModel.showSizes &&
|
|
117
|
+
node.width > 80 &&
|
|
118
|
+
node.height > 50;
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<div
|
|
122
|
+
key={node.id}
|
|
123
|
+
className={cn(
|
|
124
|
+
'absolute cursor-pointer transition-all duration-200',
|
|
125
|
+
'border border-border/50 hover:border-border',
|
|
126
|
+
'flex flex-col items-center justify-center text-center',
|
|
127
|
+
isSelected && 'ring-2 ring-primary ring-offset-1',
|
|
128
|
+
isFocused && 'ring-2 ring-offset-2 ring-primary'
|
|
129
|
+
)}
|
|
130
|
+
style={{
|
|
131
|
+
left: node.x,
|
|
132
|
+
top: node.y,
|
|
133
|
+
width: node.width,
|
|
134
|
+
height: node.height,
|
|
135
|
+
backgroundColor: node.color || '#e5e7eb',
|
|
136
|
+
borderWidth: treemapModel.borderWidth,
|
|
137
|
+
padding: treemapModel.padding,
|
|
138
|
+
}}
|
|
139
|
+
onClick={(e) => handleNodeClick(node, e)}
|
|
140
|
+
onDoubleClick={(e) => handleNodeDoubleClick(node, e)}
|
|
141
|
+
tabIndex={0}
|
|
142
|
+
role="button"
|
|
143
|
+
aria-label={`${node.type === 'directory' ? 'Folder' : 'File'}: ${node.name}`}
|
|
144
|
+
aria-selected={isSelected}
|
|
145
|
+
title={`${node.name}${showSize ? ` (${formatFileSize(node.size)})` : ''}`}
|
|
146
|
+
>
|
|
147
|
+
{/* Label */}
|
|
148
|
+
{showLabel && (
|
|
149
|
+
<div className="text-xs font-medium text-foreground/80 truncate px-1 max-w-full">
|
|
150
|
+
{node.name}
|
|
151
|
+
</div>
|
|
152
|
+
)}
|
|
153
|
+
|
|
154
|
+
{/* Size */}
|
|
155
|
+
{showSize && (
|
|
156
|
+
<div className="text-xs text-foreground/60 mt-1">
|
|
157
|
+
{formatFileSize(node.size)}
|
|
158
|
+
</div>
|
|
159
|
+
)}
|
|
160
|
+
|
|
161
|
+
{/* Directory indicator */}
|
|
162
|
+
{node.type === 'directory' && node.width > 40 && node.height > 40 && (
|
|
163
|
+
<div className="absolute top-1 right-1 w-3 h-3 bg-primary/60 rounded-full" />
|
|
164
|
+
)}
|
|
165
|
+
|
|
166
|
+
{/* Selection overlay */}
|
|
167
|
+
{isSelected && (
|
|
168
|
+
<div className="absolute inset-0 bg-primary/20 pointer-events-none" />
|
|
169
|
+
)}
|
|
170
|
+
</div>
|
|
171
|
+
);
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const formatFileSize = (bytes: number): string => {
|
|
175
|
+
if (bytes === 0) return '0 B';
|
|
176
|
+
|
|
177
|
+
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
178
|
+
let size = bytes;
|
|
179
|
+
let unitIndex = 0;
|
|
180
|
+
|
|
181
|
+
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
182
|
+
size /= 1024;
|
|
183
|
+
unitIndex++;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return `${size.toFixed(unitIndex === 0 ? 0 : 1)} ${units[unitIndex]}`;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const handleContainerClick = (event: React.MouseEvent) => {
|
|
190
|
+
// Clear selection when clicking on empty space
|
|
191
|
+
if (event.target === event.currentTarget) {
|
|
192
|
+
onSelectionChange?.([]);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const handleKeyDown = (event: React.KeyboardEvent) => {
|
|
197
|
+
switch (event.key) {
|
|
198
|
+
case 'Escape':
|
|
199
|
+
if (treemapModel.currentRoot) {
|
|
200
|
+
treemapModel.drillUp();
|
|
201
|
+
}
|
|
202
|
+
break;
|
|
203
|
+
case 'r':
|
|
204
|
+
if (event.ctrlKey || event.metaKey) {
|
|
205
|
+
event.preventDefault();
|
|
206
|
+
treemapModel.resetView();
|
|
207
|
+
}
|
|
208
|
+
break;
|
|
209
|
+
case '+':
|
|
210
|
+
case '=':
|
|
211
|
+
if (treemapModel.enableZoom) {
|
|
212
|
+
event.preventDefault();
|
|
213
|
+
treemapModel.setZoomLevel(treemapModel.zoomLevel * 1.2);
|
|
214
|
+
}
|
|
215
|
+
break;
|
|
216
|
+
case '-':
|
|
217
|
+
if (treemapModel.enableZoom) {
|
|
218
|
+
event.preventDefault();
|
|
219
|
+
treemapModel.setZoomLevel(treemapModel.zoomLevel / 1.2);
|
|
220
|
+
}
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
if (!items || items.length === 0) {
|
|
226
|
+
return (
|
|
227
|
+
<div className={cn('h-full', className)}>
|
|
228
|
+
<EmptyState
|
|
229
|
+
preset="empty-folder"
|
|
230
|
+
className="h-full"
|
|
231
|
+
/>
|
|
232
|
+
</div>
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return (
|
|
237
|
+
<div
|
|
238
|
+
ref={containerRef}
|
|
239
|
+
className={cn('treemap-view h-full relative overflow-hidden', className)}
|
|
240
|
+
onClick={handleContainerClick}
|
|
241
|
+
onKeyDown={handleKeyDown}
|
|
242
|
+
tabIndex={0}
|
|
243
|
+
role="application"
|
|
244
|
+
aria-label="Treemap view"
|
|
245
|
+
style={{
|
|
246
|
+
...(maxHeight && { maxHeight }),
|
|
247
|
+
transform: `scale(${treemapModel.zoomLevel})`,
|
|
248
|
+
transformOrigin: 'top left',
|
|
249
|
+
}}
|
|
250
|
+
>
|
|
251
|
+
{/* Treemap nodes */}
|
|
252
|
+
{treemapNodes.map(renderTreemapNode)}
|
|
253
|
+
|
|
254
|
+
{/* Controls overlay */}
|
|
255
|
+
<div className="absolute top-2 right-2 flex gap-2 bg-background/80 backdrop-blur-sm rounded-md p-2">
|
|
256
|
+
{/* Zoom controls */}
|
|
257
|
+
{treemapModel.enableZoom && (
|
|
258
|
+
<div className="flex gap-1">
|
|
259
|
+
<button
|
|
260
|
+
onClick={() => treemapModel.setZoomLevel(treemapModel.zoomLevel * 1.2)}
|
|
261
|
+
className="w-6 h-6 flex items-center justify-center text-xs bg-primary text-primary-foreground rounded hover:bg-primary/90"
|
|
262
|
+
title="Zoom in (+)"
|
|
263
|
+
>
|
|
264
|
+
+
|
|
265
|
+
</button>
|
|
266
|
+
<button
|
|
267
|
+
onClick={() => treemapModel.setZoomLevel(treemapModel.zoomLevel / 1.2)}
|
|
268
|
+
className="w-6 h-6 flex items-center justify-center text-xs bg-primary text-primary-foreground rounded hover:bg-primary/90"
|
|
269
|
+
title="Zoom out (-)"
|
|
270
|
+
>
|
|
271
|
+
-
|
|
272
|
+
</button>
|
|
273
|
+
</div>
|
|
274
|
+
)}
|
|
275
|
+
|
|
276
|
+
{/* Reset button */}
|
|
277
|
+
<button
|
|
278
|
+
onClick={() => treemapModel.resetView()}
|
|
279
|
+
className="px-2 py-1 text-xs bg-secondary text-secondary-foreground rounded hover:bg-secondary/90"
|
|
280
|
+
title="Reset view (Ctrl+R)"
|
|
281
|
+
>
|
|
282
|
+
Reset
|
|
283
|
+
</button>
|
|
284
|
+
|
|
285
|
+
{/* Drill up button */}
|
|
286
|
+
{treemapModel.currentRoot && (
|
|
287
|
+
<button
|
|
288
|
+
onClick={() => treemapModel.drillUp()}
|
|
289
|
+
className="px-2 py-1 text-xs bg-secondary text-secondary-foreground rounded hover:bg-secondary/90"
|
|
290
|
+
title="Go back (Esc)"
|
|
291
|
+
>
|
|
292
|
+
Back
|
|
293
|
+
</button>
|
|
294
|
+
)}
|
|
295
|
+
</div>
|
|
296
|
+
|
|
297
|
+
{/* Color scheme legend */}
|
|
298
|
+
<div className="absolute bottom-2 left-2 bg-background/80 backdrop-blur-sm rounded-md p-2">
|
|
299
|
+
<div className="text-xs font-medium text-foreground mb-1">
|
|
300
|
+
Color: {treemapModel.colorScheme}
|
|
301
|
+
</div>
|
|
302
|
+
<div className="flex gap-2 text-xs text-muted-foreground">
|
|
303
|
+
{treemapModel.colorScheme === 'type' && (
|
|
304
|
+
<>
|
|
305
|
+
<div className="flex items-center gap-1">
|
|
306
|
+
<div className="w-3 h-3 bg-blue-500 rounded" />
|
|
307
|
+
<span>Folders</span>
|
|
308
|
+
</div>
|
|
309
|
+
<div className="flex items-center gap-1">
|
|
310
|
+
<div className="w-3 h-3 bg-green-500 rounded" />
|
|
311
|
+
<span>Files</span>
|
|
312
|
+
</div>
|
|
313
|
+
</>
|
|
314
|
+
)}
|
|
315
|
+
{treemapModel.colorScheme === 'size' && (
|
|
316
|
+
<>
|
|
317
|
+
<div className="flex items-center gap-1">
|
|
318
|
+
<div className="w-3 h-3 bg-green-400 rounded" />
|
|
319
|
+
<span>Small</span>
|
|
320
|
+
</div>
|
|
321
|
+
<div className="flex items-center gap-1">
|
|
322
|
+
<div className="w-3 h-3 bg-yellow-500 rounded" />
|
|
323
|
+
<span>Medium</span>
|
|
324
|
+
</div>
|
|
325
|
+
<div className="flex items-center gap-1">
|
|
326
|
+
<div className="w-3 h-3 bg-red-500 rounded" />
|
|
327
|
+
<span>Large</span>
|
|
328
|
+
</div>
|
|
329
|
+
</>
|
|
330
|
+
)}
|
|
331
|
+
</div>
|
|
332
|
+
</div>
|
|
333
|
+
</div>
|
|
334
|
+
);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
TreemapView.displayName = 'TreemapView';
|
|
338
|
+
|
|
339
|
+
export default TreemapView;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface FileBrowserContextValue {
|
|
4
|
+
renameState: { itemId: string; currentName: string; source: 'list' | 'tree' } | null;
|
|
5
|
+
onRenameCommit: (newName: string) => void;
|
|
6
|
+
onRenameCancel: () => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const FileBrowserContext = createContext<FileBrowserContextValue | null>(null);
|
|
10
|
+
|
|
11
|
+
export function useFileBrowserContext() {
|
|
12
|
+
return useContext(FileBrowserContext);
|
|
13
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FileBrowser } from '../components/FileBrowser';
|
|
3
|
+
import { IFileSystem } from '@anymux/file-system';
|
|
4
|
+
|
|
5
|
+
interface BasicUsageProps {
|
|
6
|
+
fileSystem: IFileSystem;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const BasicUsage: React.FC<BasicUsageProps> = ({ fileSystem }) => {
|
|
10
|
+
return (
|
|
11
|
+
<div className="w-full h-96 border border-gray-300 rounded-lg">
|
|
12
|
+
<FileBrowser
|
|
13
|
+
fileSystem={fileSystem}
|
|
14
|
+
initialPath="/"
|
|
15
|
+
showBreadcrumbs
|
|
16
|
+
showNavigation
|
|
17
|
+
/>
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Main component
|
|
2
|
+
export { FileBrowser } from './components/FileBrowser';
|
|
3
|
+
|
|
4
|
+
// Shared components
|
|
5
|
+
export { default as FileBrowserItemComponent } from './components/shared/FileBrowserItem';
|
|
6
|
+
export { ErrorBoundary, type ErrorBoundaryProps } from './components/shared/ErrorBoundary';
|
|
7
|
+
export { default as FileIcon } from './components/shared/FileIcon';
|
|
8
|
+
|
|
9
|
+
// Types
|
|
10
|
+
export type {
|
|
11
|
+
FileBrowserProps,
|
|
12
|
+
FileBrowserItem,
|
|
13
|
+
FileBrowserItemDetails,
|
|
14
|
+
FileBrowserEventHandlers,
|
|
15
|
+
LoadingState,
|
|
16
|
+
ErrorState,
|
|
17
|
+
FilterCriteria,
|
|
18
|
+
SortCriteria,
|
|
19
|
+
NavigationState,
|
|
20
|
+
SelectionState,
|
|
21
|
+
IconDefinition,
|
|
22
|
+
PreviewData,
|
|
23
|
+
ItemChange
|
|
24
|
+
} from './types/FileBrowserTypes';
|
|
25
|
+
|
|
26
|
+
// Provider interface and implementations
|
|
27
|
+
export type { IFileBrowserProvider, ProviderCapabilities } from './providers/IFileBrowserProvider';
|
|
28
|
+
export { FileSystemProvider } from './providers/FileSystemProvider';
|
|
29
|
+
export { GitRepositoryProvider } from './providers/GitRepositoryProvider';
|
|
30
|
+
export { GitProvider } from './providers/GitProvider';
|
|
31
|
+
|
|
32
|
+
// Models
|
|
33
|
+
export { FileBrowserModel } from './models/FileBrowserModel';
|
|
34
|
+
export { UploadModel } from './models/UploadModel';
|
|
35
|
+
export type { UploadFileEntry } from './models/UploadModel';
|
|
36
|
+
export { ViewerHostModel } from './models/ViewerHostModel';
|
|
37
|
+
export { SelectionManagerModel } from './models/SelectionManagerModel';
|
|
38
|
+
export { NavigationManagerModel } from './models/NavigationManagerModel';
|
|
39
|
+
export { ToolbarManagerModel } from './models/ToolbarManagerModel';
|
|
40
|
+
export { ViewModeManagerModel } from './models/ViewModeManagerModel';
|
|
41
|
+
|
|
42
|
+
// Adapters
|
|
43
|
+
export { FileSystemBridge } from './adapters/FileSystemBridge';
|
|
44
|
+
|
|
45
|
+
// Providers (bridge)
|
|
46
|
+
export { FileSystemTreeProvider } from './providers/FileSystemTreeProvider';
|
|
47
|
+
export { FileSystemListProvider } from './providers/FileSystemListProvider';
|
|
48
|
+
|
|
49
|
+
// Viewer registry and plugin API
|
|
50
|
+
export { globalViewerRegistry, ViewerRegistry, viewerConfigToPlugin } from './registry/ViewerRegistry';
|
|
51
|
+
export type { ViewerConfig, ViewerProps } from './registry/ViewerRegistry';
|
|
52
|
+
export type { FileViewerPlugin, FileMatchContext, ResolvedViewer, ToolbarAction, KeyboardShortcut } from './registry/types';
|
|
53
|
+
|
|
54
|
+
// ViewerHost component
|
|
55
|
+
export { ViewerHost, type ViewerHostProps } from './components/ViewerHost';
|
|
56
|
+
|
|
57
|
+
// UI Models
|
|
58
|
+
export { TreeViewUIModel } from './models/ui/TreeViewUIModel';
|
|
59
|
+
export { ListViewUIModel, type ColumnDefinition } from './models/ui/ListViewUIModel';
|
|
60
|
+
export { ThumbnailViewUIModel } from './models/ui/ThumbnailViewUIModel';
|
|
61
|
+
|
|
62
|
+
// Layout Components
|
|
63
|
+
export { default as FileBrowserHeader, type FileBrowserHeaderProps } from './components/FileBrowserHeader';
|
|
64
|
+
export { default as FileBrowserContent, type FileBrowserContentProps } from './components/FileBrowserContent';
|
|
65
|
+
|
|
66
|
+
// View Components
|
|
67
|
+
export { default as FileBrowserTreeView, type TreeViewProps as FileBrowserTreeViewProps } from './components/views/TreeView/TreeView';
|
|
68
|
+
export { default as ListView, type ListViewProps } from './components/views/ListView/ListView';
|
|
69
|
+
|
|
70
|
+
// Navigation Components
|
|
71
|
+
export { default as NavigationButtons, type NavigationButtonsProps } from './components/navigation/NavigationButtons';
|
|
72
|
+
|
|
73
|
+
// Toolbar Components
|
|
74
|
+
export { default as ViewModeToggle, type ViewModeToggleProps } from './components/toolbar/ViewModeToggle';
|
|
75
|
+
|
|
76
|
+
// View mode types (for extensions)
|
|
77
|
+
export type {
|
|
78
|
+
ViewModeDefinition,
|
|
79
|
+
ViewModeCapabilities,
|
|
80
|
+
ViewModeSettings,
|
|
81
|
+
TreeViewSettings,
|
|
82
|
+
ListViewSettings,
|
|
83
|
+
ThumbnailViewSettings
|
|
84
|
+
} from './types/ViewModeTypes';
|
|
85
|
+
|
|
86
|
+
// Provider types
|
|
87
|
+
export * from './types/ProviderTypes';
|
|
88
|
+
|
|
89
|
+
// UI types (for custom components)
|
|
90
|
+
export type {
|
|
91
|
+
UIComponentProps,
|
|
92
|
+
FileIconProps as FileIconUIProps,
|
|
93
|
+
BreadcrumbProps,
|
|
94
|
+
ToolbarActionConfig
|
|
95
|
+
} from './types/UITypes';
|
|
96
|
+
|
|
97
|
+
// Utils
|
|
98
|
+
export { cn } from '../lib/utils';
|