@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.
Files changed (244) hide show
  1. package/dist/ExplorerLayout-CSIJd7N4.js +105 -0
  2. package/dist/ExplorerLayout-CSIJd7N4.js.map +1 -0
  3. package/dist/FileBrowserContext-B6jixa2j.js +11 -0
  4. package/dist/FileBrowserContext-B6jixa2j.js.map +1 -0
  5. package/dist/calendar-DSlrbHoj.js +761 -0
  6. package/dist/calendar-DSlrbHoj.js.map +1 -0
  7. package/dist/calendar.d.ts +3 -0
  8. package/dist/calendar.js +3 -0
  9. package/dist/contacts-DQXTZzHc.js +539 -0
  10. package/dist/contacts-DQXTZzHc.js.map +1 -0
  11. package/dist/contacts.d.ts +3 -0
  12. package/dist/contacts.js +3 -0
  13. package/dist/file-browser-m5atC3kF.js +6755 -0
  14. package/dist/file-browser-m5atC3kF.js.map +1 -0
  15. package/dist/file-browser.d.ts +11 -0
  16. package/dist/file-browser.js +9 -0
  17. package/dist/git-B55e6LL-.js +561 -0
  18. package/dist/git-B55e6LL-.js.map +1 -0
  19. package/dist/git.d.ts +2 -0
  20. package/dist/git.js +3 -0
  21. package/dist/iconMap-V4B8P-Uh.js +206 -0
  22. package/dist/iconMap-V4B8P-Uh.js.map +1 -0
  23. package/dist/icons-CIsIOZXR.js +0 -0
  24. package/dist/icons.d.ts +2 -0
  25. package/dist/icons.js +4 -0
  26. package/dist/index-BNmNIWBL.d.ts +71 -0
  27. package/dist/index-BNmNIWBL.d.ts.map +1 -0
  28. package/dist/index-Bryv_GCG.d.ts +1481 -0
  29. package/dist/index-Bryv_GCG.d.ts.map +1 -0
  30. package/dist/index-CuQIjSXs.d.ts +134 -0
  31. package/dist/index-CuQIjSXs.d.ts.map +1 -0
  32. package/dist/index-DSu19mq0.d.ts +153 -0
  33. package/dist/index-DSu19mq0.d.ts.map +1 -0
  34. package/dist/index-DmsyeHFr.d.ts +149 -0
  35. package/dist/index-DmsyeHFr.d.ts.map +1 -0
  36. package/dist/index-DxnJ8FYM.d.ts +17 -0
  37. package/dist/index-DxnJ8FYM.d.ts.map +1 -0
  38. package/dist/index-DzfY1Tok.d.ts +32 -0
  39. package/dist/index-DzfY1Tok.d.ts.map +1 -0
  40. package/dist/index-Ml_SgiKa.d.ts +1847 -0
  41. package/dist/index-Ml_SgiKa.d.ts.map +1 -0
  42. package/dist/index-kHr9udZD.d.ts +1025 -0
  43. package/dist/index-kHr9udZD.d.ts.map +1 -0
  44. package/dist/index.d.ts +11 -0
  45. package/dist/index.js +15 -0
  46. package/dist/layout-Ca_4r8ka.js +89 -0
  47. package/dist/layout-Ca_4r8ka.js.map +1 -0
  48. package/dist/layout.d.ts +2 -0
  49. package/dist/layout.js +5 -0
  50. package/dist/list-CxfT6hix.js +6831 -0
  51. package/dist/list-CxfT6hix.js.map +1 -0
  52. package/dist/list.d.ts +2 -0
  53. package/dist/list.js +5 -0
  54. package/dist/media-DZ292aKK.js +557 -0
  55. package/dist/media-DZ292aKK.js.map +1 -0
  56. package/dist/media.d.ts +3 -0
  57. package/dist/media.js +3 -0
  58. package/dist/tree-Dd9Z0Aso.js +3351 -0
  59. package/dist/tree-Dd9Z0Aso.js.map +1 -0
  60. package/dist/tree.d.ts +2 -0
  61. package/dist/tree.js +6 -0
  62. package/dist/types-common-CB3kRek8.d.ts +26 -0
  63. package/dist/types-common-CB3kRek8.d.ts.map +1 -0
  64. package/dist/utils-B4fdKKsy.js +3 -0
  65. package/package.json +109 -0
  66. package/src/calendar/AgendaView.tsx +37 -0
  67. package/src/calendar/CalendarBrowser.tsx +90 -0
  68. package/src/calendar/CalendarModel.ts +142 -0
  69. package/src/calendar/CalendarSidebar.tsx +81 -0
  70. package/src/calendar/DayView.tsx +76 -0
  71. package/src/calendar/EventCard.tsx +51 -0
  72. package/src/calendar/MockCalendarProvider.ts +98 -0
  73. package/src/calendar/MonthView.tsx +77 -0
  74. package/src/calendar/WeekView.tsx +129 -0
  75. package/src/calendar/index.ts +18 -0
  76. package/src/calendar/types.ts +25 -0
  77. package/src/contacts/ContactAvatar.tsx +35 -0
  78. package/src/contacts/ContactBrowser.tsx +56 -0
  79. package/src/contacts/ContactCard.tsx +37 -0
  80. package/src/contacts/ContactDetail.tsx +63 -0
  81. package/src/contacts/ContactGroupSidebar.tsx +40 -0
  82. package/src/contacts/ContactList.tsx +32 -0
  83. package/src/contacts/ContactListModel.ts +120 -0
  84. package/src/contacts/MockContactProvider.ts +77 -0
  85. package/src/contacts/index.ts +17 -0
  86. package/src/contacts/types.ts +26 -0
  87. package/src/demos/CalendarBrowserDemo.tsx +15 -0
  88. package/src/demos/ContactBrowserDemo.tsx +15 -0
  89. package/src/demos/MediaBrowserDemo.tsx +15 -0
  90. package/src/file-browser/adapters/DocumentViewerAdapter.ts +371 -0
  91. package/src/file-browser/adapters/FileSystemBridge.ts +168 -0
  92. package/src/file-browser/adapters/GitBrowserAdapter.ts +546 -0
  93. package/src/file-browser/adapters/README.md +504 -0
  94. package/src/file-browser/adapters/index.ts +27 -0
  95. package/src/file-browser/adapters/types.ts +70 -0
  96. package/src/file-browser/architecture.md +645 -0
  97. package/src/file-browser/components/CreateItemDialog.tsx +71 -0
  98. package/src/file-browser/components/DeleteConfirmDialog.tsx +58 -0
  99. package/src/file-browser/components/FileBrowser.tsx +473 -0
  100. package/src/file-browser/components/FileBrowserContent.tsx +209 -0
  101. package/src/file-browser/components/FileBrowserHeader.tsx +151 -0
  102. package/src/file-browser/components/FileBrowserToolbar.tsx +145 -0
  103. package/src/file-browser/components/LeftPanel/LeftPanel.tsx +103 -0
  104. package/src/file-browser/components/LeftPanel/LeftPanelTabs.tsx +70 -0
  105. package/src/file-browser/components/LeftPanel/TreeNavigationView.tsx +256 -0
  106. package/src/file-browser/components/PreviewPane.tsx +146 -0
  107. package/src/file-browser/components/RightPanel/FilePreview.tsx +219 -0
  108. package/src/file-browser/components/RightPanel/RightPanel.tsx +186 -0
  109. package/src/file-browser/components/RightPanel/RightPanelToolbar.tsx +113 -0
  110. package/src/file-browser/components/UploadProgress.tsx +123 -0
  111. package/src/file-browser/components/ViewerHost.tsx +208 -0
  112. package/src/file-browser/components/mobile/MobileNavigation.tsx +227 -0
  113. package/src/file-browser/components/navigation/NavigationButtons.tsx +171 -0
  114. package/src/file-browser/components/shared/ErrorBoundary.tsx +116 -0
  115. package/src/file-browser/components/shared/FileBrowserItem.tsx +195 -0
  116. package/src/file-browser/components/shared/FileIcon.tsx +169 -0
  117. package/src/file-browser/components/toolbar/ViewModeToggle.tsx +200 -0
  118. package/src/file-browser/components/views/ListView/ListView.tsx +484 -0
  119. package/src/file-browser/components/views/ThumbnailView/ThumbnailView.tsx +323 -0
  120. package/src/file-browser/components/views/TreeView/TreeNode.tsx +186 -0
  121. package/src/file-browser/components/views/TreeView/TreeNodeList.tsx +191 -0
  122. package/src/file-browser/components/views/TreeView/TreeView.tsx +200 -0
  123. package/src/file-browser/components/views/TreemapView/TreemapView.tsx +339 -0
  124. package/src/file-browser/context/FileBrowserContext.tsx +13 -0
  125. package/src/file-browser/examples/BasicUsage.tsx +20 -0
  126. package/src/file-browser/index.ts +98 -0
  127. package/src/file-browser/models/FileBrowserModel.ts +623 -0
  128. package/src/file-browser/models/LeftPanelManagerModel.ts +105 -0
  129. package/src/file-browser/models/NavigationManagerModel.ts +312 -0
  130. package/src/file-browser/models/ResponsiveLayoutManagerModel.ts +437 -0
  131. package/src/file-browser/models/RightPanelManagerModel.ts +190 -0
  132. package/src/file-browser/models/SelectionManagerModel.ts +252 -0
  133. package/src/file-browser/models/ToolbarManagerModel.ts +144 -0
  134. package/src/file-browser/models/UploadModel.ts +147 -0
  135. package/src/file-browser/models/ViewModeManagerModel.ts +185 -0
  136. package/src/file-browser/models/ViewerHostModel.ts +44 -0
  137. package/src/file-browser/models/ui/ListViewUIModel.ts +265 -0
  138. package/src/file-browser/models/ui/PreviewUIModel.ts +297 -0
  139. package/src/file-browser/models/ui/ThumbnailViewUIModel.ts +254 -0
  140. package/src/file-browser/models/ui/TreeViewUIModel.ts +128 -0
  141. package/src/file-browser/models/ui/TreemapViewUIModel.ts +350 -0
  142. package/src/file-browser/providers/FileSystemListProvider.ts +552 -0
  143. package/src/file-browser/providers/FileSystemProvider.ts +401 -0
  144. package/src/file-browser/providers/FileSystemTreeProvider.ts +231 -0
  145. package/src/file-browser/providers/GitProvider.ts +337 -0
  146. package/src/file-browser/providers/GitRepositoryProvider.ts +376 -0
  147. package/src/file-browser/providers/IFileBrowserProvider.ts +56 -0
  148. package/src/file-browser/providers/MemoryProvider.ts +303 -0
  149. package/src/file-browser/providers/index.ts +4 -0
  150. package/src/file-browser/registry/ViewerRegistry.ts +551 -0
  151. package/src/file-browser/registry/types.ts +144 -0
  152. package/src/file-browser/scripts/performanceBenchmark.ts +553 -0
  153. package/src/file-browser/services/ThumbnailCacheService.ts +128 -0
  154. package/src/file-browser/tasks.md +537 -0
  155. package/src/file-browser/types/FileBrowserTypes.ts +126 -0
  156. package/src/file-browser/types/ProviderTypes.ts +155 -0
  157. package/src/file-browser/types/UITypes.ts +235 -0
  158. package/src/file-browser/types/ViewModeTypes.ts +150 -0
  159. package/src/file-browser/utils/gestures.ts +327 -0
  160. package/src/file-browser/utils/performance.ts +563 -0
  161. package/src/file-browser/viewers/ImageViewer.tsx +163 -0
  162. package/src/file-browser/viewers/ImageViewerModel.ts +79 -0
  163. package/src/file-browser/viewers/TextViewer.tsx +95 -0
  164. package/src/file-browser/viewers/UnsupportedFileViewer.tsx +57 -0
  165. package/src/file-browser/viewers/index.ts +61 -0
  166. package/src/git/BranchList.tsx +128 -0
  167. package/src/git/CommitGraph.tsx +239 -0
  168. package/src/git/CommitList.tsx +258 -0
  169. package/src/git/DiffViewer.tsx +219 -0
  170. package/src/git/index.ts +4 -0
  171. package/src/icons/iconMap.ts +146 -0
  172. package/src/icons/index.ts +9 -0
  173. package/src/index.ts +13 -0
  174. package/src/layout/README.md +307 -0
  175. package/src/layout/components/ExplorerLayout/ExplorerLayout.tsx +178 -0
  176. package/src/layout/examples/SimpleExample.tsx +60 -0
  177. package/src/layout/index.ts +6 -0
  178. package/src/lib/utils.ts +1 -0
  179. package/src/list/README.md +303 -0
  180. package/src/list/architecture.md +807 -0
  181. package/src/list/components/CalculatedGridView.tsx +252 -0
  182. package/src/list/components/DragPreview.tsx +102 -0
  183. package/src/list/components/ListContextMenu.tsx +274 -0
  184. package/src/list/components/ListItem.tsx +761 -0
  185. package/src/list/components/ListItems.tsx +919 -0
  186. package/src/list/components/MasonryView.tsx +241 -0
  187. package/src/list/components/SearchFilter.tsx +44 -0
  188. package/src/list/components/TreemapView.tsx +709 -0
  189. package/src/list/components/ViewSizeControls.tsx +205 -0
  190. package/src/list/components/ViewTypeSelector.tsx +312 -0
  191. package/src/list/components/VirtualizedDetailsView.tsx +231 -0
  192. package/src/list/components/VirtualizedGrid.tsx +164 -0
  193. package/src/list/components/VirtualizedList.tsx +154 -0
  194. package/src/list/components/VirtualizedMasonryView.tsx +344 -0
  195. package/src/list/components/shared/EmptyState.tsx +103 -0
  196. package/src/list/components/shared/ErrorBoundary.tsx +123 -0
  197. package/src/list/components/shared/ErrorDisplay.tsx +100 -0
  198. package/src/list/components/shared/ListLoader.tsx +146 -0
  199. package/src/list/components/shared/LoadingIndicator.tsx +80 -0
  200. package/src/list/index.ts +92 -0
  201. package/src/list/models/ListItemsModel.ts +1301 -0
  202. package/src/list/models/TreemapModel.ts +204 -0
  203. package/src/list/providers/ListItemsProvider.ts +313 -0
  204. package/src/list/providers/TestListProvider.ts +604 -0
  205. package/src/list/tasks.md +937 -0
  206. package/src/list/types/ListTypes.ts +178 -0
  207. package/src/list/utils/BenchmarkLogger.ts +243 -0
  208. package/src/list/utils/DragDropManager.ts +320 -0
  209. package/src/list/utils/GridLayoutCalculator.ts +290 -0
  210. package/src/list/utils/ListAccessibility.ts +367 -0
  211. package/src/list/utils/ListKeyboard.ts +414 -0
  212. package/src/list/utils/MasonryLayoutCalculator.ts +302 -0
  213. package/src/list/utils/MasonryLayoutEngine.ts +401 -0
  214. package/src/list/utils/__tests__/MasonryLayoutEngine.test.ts +157 -0
  215. package/src/list/utils/__tests__/VirtualizedMasonryView.test.tsx +251 -0
  216. package/src/media/AlbumSidebar.tsx +48 -0
  217. package/src/media/MediaBrowser.tsx +92 -0
  218. package/src/media/MediaBrowserModel.ts +138 -0
  219. package/src/media/MediaGrid.tsx +50 -0
  220. package/src/media/MediaList.tsx +49 -0
  221. package/src/media/MediaPreview.tsx +63 -0
  222. package/src/media/MediaTimeline.tsx +38 -0
  223. package/src/media/MockMediaProvider.ts +70 -0
  224. package/src/media/index.ts +18 -0
  225. package/src/media/types.ts +21 -0
  226. package/src/styles/variables.css +60 -0
  227. package/src/tree/DEVELOPMENT_SUMMARY.md +170 -0
  228. package/src/tree/__tests__/TreeModel.test.ts +16 -0
  229. package/src/tree/architecture.md +530 -0
  230. package/src/tree/components/Tree.tsx +283 -0
  231. package/src/tree/components/TreeCheckbox.tsx +147 -0
  232. package/src/tree/components/TreeContextMenu.tsx +139 -0
  233. package/src/tree/components/TreeNodeList.tsx +329 -0
  234. package/src/tree/components/TreeTable.tsx +382 -0
  235. package/src/tree/index.ts +58 -0
  236. package/src/tree/models/TreeModel.ts +839 -0
  237. package/src/tree/providers/SimpleTreeProvider.ts +463 -0
  238. package/src/tree/providers/TestTreeProvider.ts +946 -0
  239. package/src/tree/providers/TreeProvider.ts +308 -0
  240. package/src/tree/tasks.md +2046 -0
  241. package/src/tree/types/TreeTypes.ts +279 -0
  242. package/src/tree/utils/SelectionTheme.ts +150 -0
  243. package/src/tree/utils/logger.ts +203 -0
  244. package/src/types-common.ts +21 -0
@@ -0,0 +1,604 @@
1
+ import {
2
+ ListItemsProvider,
3
+ ListItemsProviderListener,
4
+ LIST_VIEW_TYPE,
5
+ GRID_VIEW_TYPE,
6
+ DETAILS_VIEW_TYPE,
7
+ MASONRY_HORIZONTAL_VIEW_TYPE,
8
+ MASONRY_VERTICAL_VIEW_TYPE,
9
+ type ListViewType
10
+ } from './ListItemsProvider';
11
+ import type {
12
+ ListItemData,
13
+ ListLoadOptions,
14
+ ListLoadResult,
15
+ ListSelectionInfo,
16
+ ListContextMenuItem,
17
+ ListDragDropInfo,
18
+ VirtualizationConfig
19
+ } from '../types/ListTypes';
20
+ import React from 'react';
21
+ import {
22
+ FileText, Image, Video, Music, Folder, Archive,
23
+ File, Settings, Code, Database, Globe, Palette,
24
+ Package, BookOpen, TestTube, GitBranch, Key,
25
+ Braces, Play, Zap, Component
26
+ } from 'lucide-react';
27
+ import { makeAutoObservable } from 'mobx';
28
+
29
+ // AICODE-NOTE: Simple test provider for development and testing with mock data
30
+ export class TestListProvider implements ListItemsProvider {
31
+ // =====================
32
+ // Basic Configuration
33
+ // =====================
34
+
35
+ readonly id = 'test-list-provider';
36
+ readonly name = 'Test List Provider';
37
+ readonly isMultiSelectEnabled = true;
38
+ readonly isVirtualizationEnabled = true;
39
+ readonly isDragDropEnabled = true;
40
+
41
+ readonly supportedViewTypes: ListViewType[] = [
42
+ LIST_VIEW_TYPE,
43
+ GRID_VIEW_TYPE,
44
+ DETAILS_VIEW_TYPE,
45
+ MASONRY_HORIZONTAL_VIEW_TYPE,
46
+ MASONRY_VERTICAL_VIEW_TYPE
47
+ ];
48
+
49
+ // AICODE-NOTE: Mock data for testing - different types of items
50
+ private items: ListItemData[] = [];
51
+ private listener?: ListItemsProviderListener;
52
+
53
+ constructor() {
54
+ makeAutoObservable(this, {});
55
+ // AICODE-NOTE: Generate large dataset with 10,000 items for performance testing
56
+ this.generateLargeDataset();
57
+ }
58
+
59
+ // =====================
60
+ // Mock Data Generation
61
+ // =====================
62
+
63
+ private generateLargeDataset(): void {
64
+ // AICODE-NOTE: Generate 10,000 items with varied dimensions and images
65
+ const start = performance.now();
66
+ const fileTypes = [
67
+ { ext: 'jpg', icon: '🖼️', type: 'Image' },
68
+ { ext: 'png', icon: '🖼️', type: 'Image' },
69
+ { ext: 'pdf', icon: '📄', type: 'Document' },
70
+ { ext: 'doc', icon: '📝', type: 'Document' },
71
+ { ext: 'mp4', icon: '🎬', type: 'Video' },
72
+ { ext: 'mp3', icon: '🎵', type: 'Audio' },
73
+ { ext: 'zip', icon: '📦', type: 'Archive' },
74
+ { ext: 'txt', icon: '📄', type: 'Text' },
75
+ { ext: 'js', icon: '⚡', type: 'Code' },
76
+ { ext: 'css', icon: '🎨', type: 'Style' }
77
+ ];
78
+
79
+ const adjectives = ['Amazing', 'Beautiful', 'Creative', 'Dynamic', 'Elegant', 'Fantastic', 'Gorgeous', 'Incredible', 'Lovely', 'Magnificent'];
80
+ const nouns = ['Photo', 'Document', 'Project', 'Design', 'Artwork', 'Report', 'Presentation', 'Video', 'Music', 'Archive'];
81
+
82
+ for (let i = 0; i < 10000; i++) {
83
+ const fileType = fileTypes[i % fileTypes.length]!;
84
+ const adjective = adjectives[i % adjectives.length]!;
85
+ const noun = nouns[Math.floor(i / adjectives.length) % nouns.length]!;
86
+
87
+ // Generate variable dimensions for realistic masonry layout
88
+ const baseWidth = 200 + (i % 5) * 40; // 200-360px width
89
+ const aspectRatios = [1, 1.2, 1.5, 0.8, 0.6, 1.8]; // Various aspect ratios
90
+ const aspectRatio = aspectRatios[i % aspectRatios.length]!;
91
+ const height = Math.round(baseWidth / aspectRatio);
92
+
93
+ // Generate image URL for visual items
94
+ const isImageType = fileType.type === 'Image' || (i % 3 === 0); // Show images for image types and every 3rd item
95
+ const thumbnailUrl = isImageType
96
+ ? `https://picsum.photos/${baseWidth}/${height}?random=${i}`
97
+ : undefined;
98
+
99
+ const item: ListItemData = {
100
+ id: `item-${i}`,
101
+ name: `${adjective} ${noun} ${i + 1}.${fileType.ext}`,
102
+ type: fileType.type,
103
+ icon: fileType.icon,
104
+ size: Math.floor(Math.random() * 10000000) + 1000, // 1KB to 10MB
105
+ modified: new Date(Date.now() - Math.random() * 365 * 24 * 60 * 60 * 1000), // Random date within last year
106
+ thumbnailUrl,
107
+ aspectRatio,
108
+ getDimensions: () => ({ width: baseWidth, height })
109
+ };
110
+
111
+ this.items.push(item);
112
+ }
113
+ console.log('Generated 10,000 items in', performance.now() - start, 'ms');
114
+ }
115
+
116
+ private getIconForType(type: string): string {
117
+ const iconMap: Record<string, string> = {
118
+ document: 'file-text',
119
+ image: 'image',
120
+ video: 'video',
121
+ audio: 'music',
122
+ folder: 'folder',
123
+ archive: 'archive'
124
+ };
125
+ return iconMap[type] || 'file';
126
+ }
127
+
128
+ /**
129
+ * Get custom icon for an item based on file type and extension
130
+ */
131
+ getItemIcon(item: ListItemData): string | React.ComponentType<any> {
132
+ // If it's a folder, use folder icon
133
+ if (item.type === 'folder') {
134
+ return Folder;
135
+ }
136
+
137
+ // Get file extension
138
+ const extension = item.name.split('.').pop()?.toLowerCase() || '';
139
+
140
+ // Return appropriate icon based on extension
141
+ switch (extension) {
142
+ // Web Development
143
+ case 'js':
144
+ case 'jsx':
145
+ return Code; // JavaScript icon
146
+
147
+ case 'ts':
148
+ case 'tsx':
149
+ return FileText; // TypeScript icon
150
+
151
+ case 'html':
152
+ case 'htm':
153
+ return Globe; // HTML icon
154
+
155
+ case 'css':
156
+ case 'scss':
157
+ case 'sass':
158
+ case 'less':
159
+ return Palette; // Stylesheet icon
160
+
161
+ // Documentation
162
+ case 'md':
163
+ case 'mdx':
164
+ return BookOpen; // Markdown icon
165
+
166
+ case 'txt':
167
+ return FileText;
168
+
169
+ case 'pdf':
170
+ return FileText;
171
+
172
+ // Data & Configuration
173
+ case 'json':
174
+ return Braces; // JSON icon
175
+
176
+ case 'yml':
177
+ case 'yaml':
178
+ return Settings; // YAML icon
179
+
180
+ case 'xml':
181
+ return Code; // XML icon
182
+
183
+ case 'env':
184
+ return Key; // Environment file icon
185
+
186
+ case 'config':
187
+ return Settings; // Config file icon
188
+
189
+ // Images
190
+ case 'jpg':
191
+ case 'jpeg':
192
+ case 'png':
193
+ case 'gif':
194
+ case 'webp':
195
+ case 'bmp':
196
+ case 'tiff':
197
+ case 'ico':
198
+ return Image; // Image icon
199
+
200
+ case 'svg':
201
+ return Zap; // SVG icon (special since it's vector)
202
+
203
+ // Media
204
+ case 'mp4':
205
+ case 'avi':
206
+ case 'mov':
207
+ case 'mkv':
208
+ return Play; // Video icon
209
+
210
+ case 'mp3':
211
+ case 'wav':
212
+ case 'flac':
213
+ case 'ogg':
214
+ return Music; // Audio icon
215
+
216
+ // Archives
217
+ case 'zip':
218
+ case 'tar':
219
+ case 'gz':
220
+ case '7z':
221
+ case 'rar':
222
+ return Archive; // Archive icon
223
+
224
+ // Executables
225
+ case 'exe':
226
+ case 'app':
227
+ case 'deb':
228
+ case 'dmg':
229
+ return Zap; // Executable icon
230
+
231
+ // Development Tools
232
+ case 'git':
233
+ case 'gitignore':
234
+ return GitBranch;
235
+
236
+ case 'dockerfile':
237
+ return Package; // Docker icon
238
+
239
+ case 'sql':
240
+ return Database; // Database icon
241
+
242
+ case 'log':
243
+ return FileText; // Log file icon
244
+
245
+ // Default file icon
246
+ default:
247
+ return File; // Use default File icon
248
+ }
249
+ }
250
+
251
+ // =====================
252
+ // Data Loading Methods
253
+ // =====================
254
+
255
+ async loadItems(options?: ListLoadOptions): Promise<ListLoadResult> {
256
+ // AICODE-NOTE: Simulate async loading with small delay
257
+ await new Promise(resolve => setTimeout(resolve, 100));
258
+
259
+ let items = [...this.items];
260
+
261
+ // Apply search filter
262
+ if (options?.searchQuery) {
263
+ const query = options.searchQuery.toLowerCase();
264
+ items = items.filter(item =>
265
+ item.name.toLowerCase().includes(query) ||
266
+ item.type?.toLowerCase().includes(query)
267
+ );
268
+ }
269
+
270
+ // Apply sorting
271
+ if (options?.sortBy) {
272
+ const sortField = options.sortBy;
273
+ items.sort((a, b) => {
274
+ const aVal = a[sortField];
275
+ const bVal = b[sortField];
276
+
277
+ if (aVal === undefined) return 1;
278
+ if (bVal === undefined) return -1;
279
+
280
+ let comparison = 0;
281
+ if (aVal < bVal) comparison = -1;
282
+ if (aVal > bVal) comparison = 1;
283
+
284
+ return options.sortDirection === 'desc' ? -comparison : comparison;
285
+ });
286
+ }
287
+
288
+ // Apply pagination
289
+ const limit = options?.limit || items.length;
290
+ const offset = options?.offset || 0;
291
+ const paginatedItems = items.slice(offset, offset + limit);
292
+
293
+ return {
294
+ items: paginatedItems,
295
+ totalCount: items.length,
296
+ hasMore: offset + limit < items.length
297
+ };
298
+ }
299
+
300
+ async getItemCount(): Promise<number> {
301
+ return this.items.length;
302
+ }
303
+
304
+ async loadItemRange(start: number, end: number): Promise<ListLoadResult> {
305
+ // AICODE-NOTE: Simulate async range loading with delay
306
+ await new Promise(resolve => setTimeout(resolve, 200));
307
+
308
+ const items: ListItemData[] = [];
309
+
310
+ // AICODE-NOTE: Generate items on demand for the requested range
311
+ for (let i = start; i < end && i < this.items.length; i++) {
312
+ // AICODE-NOTE: Check if item already exists in cache
313
+ const existingItem = i < this.items.length ? this.items[i] : null;
314
+ if (existingItem) {
315
+ items.push(existingItem);
316
+ } else {
317
+ // AICODE-NOTE: Item should already exist from generateLargeDataset
318
+ // If we reach here, something is wrong with the data generation
319
+ console.warn(`Item at index ${i} not found in pre-generated dataset`);
320
+ continue;
321
+ }
322
+ }
323
+
324
+ return {
325
+ items,
326
+ totalCount: this.items.length,
327
+ hasMore: end < this.items.length
328
+ };
329
+ }
330
+
331
+ async refresh(): Promise<ListLoadResult> {
332
+ // AICODE-NOTE: For testing, just return all items
333
+ return this.loadItems();
334
+ }
335
+
336
+ // =====================
337
+ // View Configuration
338
+ // =====================
339
+
340
+ getItemHeight(viewType: ListViewType): number {
341
+ // AICODE-NOTE: Different heights for different view types
342
+ switch (viewType.id) {
343
+ case 'list': return 40;
344
+ case 'grid': return 120;
345
+ case 'details': return 32;
346
+ default: return 40;
347
+ }
348
+ }
349
+
350
+ getItemWidth(viewType: ListViewType): number {
351
+ // AICODE-NOTE: Fixed widths for grid layouts
352
+ switch (viewType.id) {
353
+ case 'grid': return 200;
354
+ default: return 200;
355
+ }
356
+ }
357
+
358
+ getVirtualizationConfig(): VirtualizationConfig {
359
+ return {
360
+ itemHeight: 40,
361
+ overscan: 5,
362
+ threshold: 50,
363
+ rangeSize: 20
364
+ };
365
+ }
366
+
367
+ // =====================
368
+ // Event Callbacks
369
+ // =====================
370
+
371
+ onSelectionChange(selectionInfo: ListSelectionInfo): void {
372
+ // AICODE-NOTE: Log selection changes for debugging
373
+ console.log('Selection changed:', {
374
+ selectedCount: selectionInfo.selectedItems.length,
375
+ selectionType: selectionInfo.selectionType,
376
+ trigger: selectionInfo.trigger
377
+ });
378
+ }
379
+
380
+ onViewTypeChange(viewType: ListViewType): void {
381
+ console.log('View type changed to:', viewType.name);
382
+ }
383
+
384
+ onItemDoubleClick(item: ListItemData): void {
385
+ console.log('Item double-clicked:', item.name);
386
+ }
387
+
388
+ // =====================
389
+ // Context Menu Support
390
+ // =====================
391
+
392
+ getItemContextMenu(item: ListItemData): ListContextMenuItem[] {
393
+ // AICODE-NOTE: Basic context menu for testing
394
+ const baseMenu: ListContextMenuItem[] = [
395
+ { id: 'open', label: 'Open', icon: 'eye' },
396
+ { id: 'rename', label: 'Rename', icon: 'edit' },
397
+ { id: 'separator', label: '', type: 'separator' },
398
+ { id: 'delete', label: 'Delete', icon: 'trash', destructive: true }
399
+ ];
400
+
401
+ // Add type-specific items
402
+ if (item.type === 'folder') {
403
+ baseMenu.unshift({ id: 'open-folder', label: 'Open Folder', icon: 'folder-open' });
404
+ }
405
+
406
+ return baseMenu;
407
+ }
408
+
409
+ getMultiItemContextMenu(items: ListItemData[]): ListContextMenuItem[] {
410
+ // AICODE-NOTE: Context menu for multiple selected items
411
+ const multiMenu: ListContextMenuItem[] = [
412
+ {
413
+ id: 'delete-multiple',
414
+ label: `Delete ${items.length} items`,
415
+ icon: 'trash',
416
+ destructive: true,
417
+ shortcut: 'Del'
418
+ },
419
+ { id: 'separator', label: '', type: 'separator' },
420
+ {
421
+ id: 'copy-multiple',
422
+ label: `Copy ${items.length} items`,
423
+ icon: 'copy',
424
+ shortcut: 'Ctrl+C'
425
+ },
426
+ {
427
+ id: 'cut-multiple',
428
+ label: `Cut ${items.length} items`,
429
+ icon: 'scissors',
430
+ shortcut: 'Ctrl+X'
431
+ }
432
+ ];
433
+
434
+ // AICODE-NOTE: Add archive option if multiple files selected
435
+ const hasFiles = items.some(item => item.type !== 'folder');
436
+ if (hasFiles) {
437
+ multiMenu.push(
438
+ { id: 'separator2', label: '', type: 'separator' },
439
+ {
440
+ id: 'archive-multiple',
441
+ label: `Archive ${items.length} items`,
442
+ icon: 'archive',
443
+ tooltip: 'Create a zip archive of selected items'
444
+ }
445
+ );
446
+ }
447
+
448
+ return multiMenu;
449
+ }
450
+
451
+ onContextMenuAction(menuItemId: string, items: ListItemData[]): void {
452
+ console.log(`Context menu action '${menuItemId}' on items:`, items.map(i => i.name));
453
+
454
+ switch (menuItemId) {
455
+ case 'delete':
456
+ case 'delete-multiple':
457
+ // AICODE-NOTE: For testing, just log - real provider would delete items
458
+ console.log('Would delete items:', items.map(i => i.name));
459
+ break;
460
+ case 'rename':
461
+ console.log('Would rename item:', items[0]?.name);
462
+ break;
463
+ case 'copy-multiple':
464
+ console.log('Would copy items to clipboard:', items.map(i => i.name));
465
+ break;
466
+ case 'cut-multiple':
467
+ console.log('Would cut items to clipboard:', items.map(i => i.name));
468
+ break;
469
+ case 'archive-multiple':
470
+ console.log('Would create archive of items:', items.map(i => i.name));
471
+ break;
472
+ case 'open':
473
+ case 'open-folder':
474
+ console.log('Would open item:', items[0]?.name);
475
+ break;
476
+ default:
477
+ console.log('Unhandled menu action:', menuItemId);
478
+ }
479
+ }
480
+
481
+ // =====================
482
+ // Drag and Drop Support
483
+ // =====================
484
+
485
+ canDragItem(item: ListItemData): boolean {
486
+ // AICODE-NOTE: For testing, allow dragging all items except system files
487
+ return !item.name.startsWith('.');
488
+ }
489
+
490
+ canDropItems(draggedItems: ListItemData[], targetItem: ListItemData | null, position: 'before' | 'after' | 'inside'): boolean {
491
+ // AICODE-NOTE: For testing, allow most drops with some restrictions
492
+
493
+ // Can't drop on itself
494
+ if (targetItem && draggedItems.some(item => item.id === targetItem.id)) {
495
+ return false;
496
+ }
497
+
498
+ // Can only drop inside folders
499
+ if (position === 'inside' && targetItem?.type !== 'folder') {
500
+ return false;
501
+ }
502
+
503
+ return true;
504
+ }
505
+
506
+ onDragStart(draggedItems: ListItemData[], event: DragEvent): void {
507
+ console.log('Drag started with items:', draggedItems.map(i => i.name));
508
+ }
509
+
510
+ onDrop(dragDropInfo: ListDragDropInfo): void {
511
+ const { draggedItems, targetItem, position } = dragDropInfo;
512
+
513
+ console.log('Drop operation:', {
514
+ draggedItems: draggedItems.map((i: ListItemData) => i.name),
515
+ targetItem: targetItem?.name || 'empty space',
516
+ position
517
+ });
518
+
519
+ // AICODE-NOTE: For testing, simulate reordering by logging
520
+ if (position === 'before' || position === 'after') {
521
+ console.log(`Would reorder items ${position} ${targetItem?.name}`);
522
+ } else if (position === 'inside' && targetItem?.type === 'folder') {
523
+ console.log(`Would move items into folder: ${targetItem.name}`);
524
+ }
525
+ }
526
+
527
+ onDragEnd(draggedItems: ListItemData[], success: boolean): void {
528
+ console.log('Drag ended:', {
529
+ items: draggedItems.map(i => i.name),
530
+ success
531
+ });
532
+ }
533
+
534
+ // =====================
535
+ // Legacy Listener Support
536
+ // =====================
537
+
538
+ addListener(listener: ListItemsProviderListener): void {
539
+ this.listener = listener;
540
+ }
541
+
542
+ removeListener(listener: ListItemsProviderListener): void {
543
+ this.listener = undefined;
544
+ }
545
+
546
+ // =====================
547
+ // Helper Methods for Testing
548
+ // =====================
549
+
550
+ /**
551
+ * Add a new mock item (useful for testing dynamic updates)
552
+ */
553
+ addMockItem(item: Partial<ListItemData>): void {
554
+ const { id, name, ...rest } = item;
555
+ const newItem: ListItemData = {
556
+ id: id || `item-${Date.now()}`,
557
+ name: name || 'New Item',
558
+ type: 'document',
559
+ modified: new Date(),
560
+ icon: 'file',
561
+ ...rest
562
+ };
563
+
564
+ this.items.push(newItem);
565
+
566
+ // Notify listeners
567
+ this.listener?.onItemsCountChanged(this.items.length);
568
+ }
569
+
570
+ /**
571
+ * Remove an item by ID (useful for testing dynamic updates)
572
+ */
573
+ removeMockItem(itemId: string): void {
574
+ const index = this.items.findIndex(item => item.id === itemId);
575
+ if (index >= 0) {
576
+ this.items.splice(index, 1);
577
+
578
+ // Notify listeners
579
+ this.listener?.onItemsCountChanged(this.items.length);
580
+ }
581
+ }
582
+
583
+ /**
584
+ * Update an existing item (useful for testing dynamic updates)
585
+ */
586
+ updateMockItem(itemId: string, updates: Partial<ListItemData>): void {
587
+ const index = this.items.findIndex(item => item.id === itemId);
588
+ if (index >= 0) {
589
+ const currentItem = this.items[index]!;
590
+ const { id, name, ...rest } = updates;
591
+
592
+ this.items[index] = {
593
+ ...currentItem,
594
+ ...rest,
595
+ // Ensure required fields are never undefined
596
+ id: id || currentItem.id,
597
+ name: name || currentItem.name
598
+ };
599
+
600
+ // Notify listeners
601
+ this.listener?.onItemChanged(index);
602
+ }
603
+ }
604
+ }