@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,807 @@
1
+ # ListItemsComponent Architecture
2
+
3
+ ## Overview
4
+
5
+ The ListItemsComponent is a high-performance, virtualized list component built with React, MobX, and TypeScript. It provides a flexible, accessible, and extensible list interface that can work with any data source through the Provider pattern. The component supports multiple view types (list, grid, details, thumbnails) and can handle massive datasets through virtualization. The provider can work with or without React, supporting both web and non-web environments.
6
+
7
+ **🎯 Primary Use Cases**: File explorers (Windows Explorer, macOS Finder), media galleries, data tables, search results, any large dataset display requiring multiple view modes.
8
+
9
+ ## Design Principles
10
+
11
+ - **Provider-Driven Architecture**: ListItemsProvider model drives ALL behavior (selection, rendering, virtualization, view types)
12
+ - **Direct Provider Injection**: No registry pattern - provider passed directly to ListItems component
13
+ - **MobX Best Practices**:
14
+ - Use `makeAutoObservable(this, {})` in constructors (NO decorators)
15
+ - Use `flow` for async actions
16
+ - Use `observable.map()` instead of plain Map for reactive collections
17
+ - Use composition over inheritance
18
+ - **All State in Provider**: multiSelect, dragDrop, virtualization, view types configured in provider
19
+ - **Callback-Based**: ListItems component calls provider callbacks for all interactions
20
+ - **Item-Level Customization**: Per-item context menus and render overrides
21
+ - **Environment Agnostic**: Provider works with and without React
22
+ - **Component Composition**: Small, focused components for maintainability
23
+ - **Accessibility First**: Full ARIA support for screen readers and keyboard navigation
24
+ - **Performance**: Mandatory virtualization support for huge datasets (react-window/react-virtualized)
25
+ - **Type Safety**: Comprehensive TypeScript coverage
26
+ - **Responsive Design**: Grid layouts adapt to container width, thumbnail sizes configurable
27
+
28
+ ## MobX Best Practices (CRITICAL)
29
+
30
+ **⚠️ STRICT REQUIREMENTS - These patterns must be followed exactly:**
31
+
32
+ ### 1. No Decorators - Use makeAutoObservable
33
+ ```typescript
34
+ // ❌ NEVER use decorators
35
+ class ListItemsModel {
36
+ @observable items = []
37
+ @action selectItem() {}
38
+ }
39
+
40
+ // ✅ ALWAYS use makeAutoObservable
41
+ class ListItemsModel {
42
+ items = []
43
+
44
+ constructor() {
45
+ makeAutoObservable(this, {}); // Empty overrides object
46
+ }
47
+
48
+ selectItem() {} // Automatically becomes action
49
+ }
50
+ ```
51
+
52
+ ### 2. Observable Collections - Use observable.map()
53
+ ```typescript
54
+ // ❌ NEVER use plain Map/Set
55
+ selectedItems = new Map<string, ListItemData>()
56
+ itemStates = new Set<string>()
57
+
58
+ // ✅ ALWAYS use observable.map()
59
+ selectedItems = observable.map<string, ListItemData>()
60
+ itemStates = observable.map<string, ItemState>()
61
+ ```
62
+
63
+ ### 3. Async Actions - Use flow
64
+ ```typescript
65
+ // ❌ NEVER use async/await directly in actions
66
+ async loadItems() {
67
+ this.isLoading = true;
68
+ const result = await api.loadItems();
69
+ this.items = result; // ⚠️ Not in action!
70
+ }
71
+
72
+ // ✅ ALWAYS use flow for async operations
73
+ loadItems = flow(function* (this: ListItemsModel) {
74
+ this.isLoading = true;
75
+ const result = yield api.loadItems();
76
+ this.items = result; // ✅ Automatically in action
77
+ });
78
+ ```
79
+
80
+ ### 4. Composition Over Inheritance
81
+ ```typescript
82
+ // ❌ NEVER use inheritance (MobX issues)
83
+ class BaseModel {}
84
+ class ListItemsModel extends BaseModel {}
85
+
86
+ // ✅ ALWAYS use composition
87
+ class ListItemsModel {
88
+ selectionManager: ListSelectionModel;
89
+ viewManager: ViewTypeManager;
90
+ virtualizationManager: VirtualizationModel;
91
+
92
+ constructor() {
93
+ makeAutoObservable(this, {});
94
+ this.selectionManager = new ListSelectionModel(this);
95
+ this.viewManager = new ViewTypeManager(this);
96
+ this.virtualizationManager = new VirtualizationModel(this);
97
+ }
98
+ }
99
+ ```
100
+
101
+ ### 5. Observer Components for Lists
102
+ ```typescript
103
+ // ❌ NEVER render observables directly in map
104
+ const ItemList = observer(() => (
105
+ <div>
106
+ {items.map(item => <div key={item.id}>{item.name}</div>)} {/* Won't react! */}
107
+ </div>
108
+ ))
109
+
110
+ // ✅ ALWAYS extract to separate observer components
111
+ const ListItem = observer(({ item }) => <div>{item.name}</div>)
112
+
113
+ const ItemList = observer(() => (
114
+ <div>
115
+ {items.map(item => <ListItem key={item.id} item={item} />)}
116
+ </div>
117
+ ))
118
+ ```
119
+
120
+ ### 6. Icon Handling Pattern (CRITICAL)
121
+ ```typescript
122
+ // AICODE-NOTE: Icon handling pattern to avoid React component rendering bugs
123
+
124
+ // ❌ NEVER try to render React components directly from string props
125
+ {menuItem.icon && <menuItem.icon className="w-4 h-4" />} // JSX element type error!
126
+
127
+ // ✅ ALWAYS check type and handle appropriately
128
+ {menuItem.icon && (
129
+ <span className="w-4 h-4 flex-shrink-0 flex items-center justify-center">
130
+ {typeof menuItem.icon === 'string' ? (
131
+ <span className="text-sm">{getIconEmoji(menuItem.icon)}</span>
132
+ ) : (
133
+ React.createElement(menuItem.icon, { className: 'w-4 h-4' })
134
+ )}
135
+ </span>
136
+ )}
137
+
138
+ // ✅ Provider pattern: Return string identifiers, map to emojis/components in UI
139
+ const getIconEmoji = (iconName: string): string => {
140
+ const iconMap: Record<string, string> = {
141
+ 'eye': '👁️', 'edit': '✏️', 'trash': '🗑️', 'folder-open': '📂',
142
+ 'copy': '📋', 'scissors': '✂️', 'archive': '📦'
143
+ };
144
+ return iconMap[iconName] || iconName;
145
+ };
146
+
147
+ // ✅ For complex icons, use React.createElement instead of JSX
148
+ React.createElement(IconComponent, { className: 'w-4 h-4' })
149
+ ```
150
+
151
+ ## Architecture Overview
152
+
153
+ ```
154
+ ListItemsComponent
155
+ ↓ receives
156
+ ListItemsProvider (MobX Model)
157
+ ↓ provides data & callbacks
158
+ ListItemsModel (MobX State)
159
+ ↓ manages
160
+ ListItems Components (React UI + Virtualization)
161
+ ```
162
+
163
+ ## Core Components
164
+
165
+ ### 1. ListItemsProvider (Model Layer)
166
+ **Location**: `/providers/ListItemsProvider.ts`
167
+
168
+ **Purpose**: Defines the contract for data loading, item rendering, view types, and interaction callbacks. Works independently of React.
169
+
170
+ **Key Features**:
171
+ - Data loading methods (`loadItems`, `loadRange`, `refresh`, `search`)
172
+ - View type management (`getSupportedViewTypes`, `getViewTypeConfig`)
173
+ - Per-item context menus (`getItemContextMenu`, `getMultiItemContextMenu`)
174
+ - Item rendering overrides (`getItemRenderer`, `getDefaultRenderer`)
175
+ - Capability checks (`canSelect`, `canDrag`, `canDrop`, `canEdit`)
176
+ - Event callbacks (`onSelectionChange`, `onDragDrop`, `onContextMenuAction`, `onViewTypeChange`)
177
+ - Non-React item rendering (`ListItemRenderer.renderText`, `renderIcon`, `renderThumbnail`)
178
+ - Virtualization configuration (`getVirtualizationConfig`, `getItemHeight`)
179
+
180
+ ### 2. ListItemsModel (State Layer)
181
+ **Location**: `/models/ListItemsModel.ts`
182
+
183
+ **Purpose**: MobX observable state container that manages list data, selection, view types, and UI state.
184
+
185
+ **State Management**:
186
+ ```typescript
187
+ class ListItemsModel {
188
+ // Core Data - using observable collections
189
+ items: ListItemData[] = []
190
+ itemMap = observable.map<string, ListItemData>()
191
+ totalItemCount: number = 0
192
+
193
+ // View State
194
+ currentViewType: ListViewType = LIST_VIEW_TYPE
195
+ availableViewTypes: ListViewType[] = []
196
+ gridColumnsCount: number = 4
197
+ thumbnailSize: ThumbnailSize = 'medium'
198
+
199
+ // UI State - using observable.map instead of Set/Map
200
+ selectedItems = observable.map<string, ListItemData>()
201
+ focusedItem: string | null = null
202
+ hoveredItem: string | null = null
203
+
204
+ // Loading State
205
+ isLoading: boolean = false
206
+ loadingRanges = observable.map<string, boolean>()
207
+ errors = observable.map<string, Error>()
208
+
209
+ // Virtualization State
210
+ viewportRange: { start: number; end: number } = { start: 0, end: 0 }
211
+ scrollPosition: number = 0
212
+ containerSize: { width: number; height: number } = { width: 0, height: 0 }
213
+
214
+ // Interaction State
215
+ draggedItems: ListItemData[] = []
216
+ dropTarget: ListItemData | null = null
217
+ contextMenuItem: ListItemData | null = null
218
+ isEditing: string | null = null
219
+
220
+ constructor(public provider: ListItemsProvider) {
221
+ makeAutoObservable(this, {});
222
+ }
223
+
224
+ // Computed properties for derived state
225
+ get selectedItemsArray(): ListItemData[] {
226
+ return Array.from(this.selectedItems.values());
227
+ }
228
+
229
+ get hasSelection(): boolean {
230
+ return this.selectedItems.size > 0;
231
+ }
232
+
233
+ get isItemSelected() {
234
+ return (itemId: string) => this.selectedItems.has(itemId);
235
+ }
236
+
237
+ get itemHeight(): number {
238
+ return this.provider.getItemHeight(this.currentViewType);
239
+ }
240
+
241
+ get gridItemsPerRow(): number {
242
+ if (this.currentViewType.id !== 'grid') return 1;
243
+ const itemWidth = this.provider.getItemWidth?.(this.currentViewType) ?? 200;
244
+ return Math.floor(this.containerSize.width / itemWidth);
245
+ }
246
+
247
+ // Async actions using flow
248
+ loadItems = flow(function* (this: ListItemsModel, options?: ListLoadOptions) {
249
+ this.isLoading = true;
250
+ this.errors.clear();
251
+
252
+ try {
253
+ const result = yield this.provider.loadItems(options);
254
+ this.items = result.items;
255
+ this.totalItemCount = result.totalCount ?? result.items.length;
256
+
257
+ // Update item map for fast lookups
258
+ this.itemMap.clear();
259
+ result.items.forEach(item => this.itemMap.set(item.id, item));
260
+
261
+ } catch (error) {
262
+ this.errors.set('loadItems', error);
263
+ } finally {
264
+ this.isLoading = false;
265
+ }
266
+ });
267
+
268
+ loadItemRange = flow(function* (this: ListItemsModel, start: number, end: number) {
269
+ const rangeKey = `${start}-${end}`;
270
+ this.loadingRanges.set(rangeKey, true);
271
+
272
+ try {
273
+ const result = yield this.provider.loadItemRange?.(start, end) ?? { items: [] };
274
+
275
+ // Merge items into existing array at correct positions
276
+ result.items.forEach((item, index) => {
277
+ const absoluteIndex = start + index;
278
+ this.items[absoluteIndex] = item;
279
+ this.itemMap.set(item.id, item);
280
+ });
281
+
282
+ } catch (error) {
283
+ this.errors.set(rangeKey, error);
284
+ } finally {
285
+ this.loadingRanges.delete(rangeKey);
286
+ }
287
+ });
288
+ }
289
+ ```
290
+
291
+ ### 3. ListItems Component (UI Layer)
292
+ **Location**: `/components/ListItems.tsx`
293
+
294
+ **Purpose**: Main React component that receives ListItemsProvider as prop and renders the virtualized list UI.
295
+
296
+ **Component Interface**:
297
+ ```typescript
298
+ interface ListItemsProps {
299
+ provider: ListItemsProvider;
300
+ className?: string;
301
+ height?: number;
302
+ width?: number;
303
+ // All behavior controlled by provider - no separate props
304
+ }
305
+
306
+ export const ListItems = observer(({ provider, className, height, width }: ListItemsProps) => {
307
+ const [model] = useState(() => new ListItemsModel(provider))
308
+
309
+ // All configuration comes from provider:
310
+ // - provider.supportedViewTypes
311
+ // - provider.isMultiSelectEnabled
312
+ // - provider.isDragDropEnabled
313
+ // - provider.isVirtualizationEnabled
314
+ // - provider.getVirtualizationConfig()
315
+
316
+ // Component delegates all actions to model,
317
+ // which calls provider callbacks
318
+ })
319
+ ```
320
+
321
+ ## View Types System
322
+
323
+ ### Built-in View Types
324
+ ```typescript
325
+ export const LIST_VIEW_TYPE: ListViewType = {
326
+ id: "list",
327
+ name: "List",
328
+ icon: "list",
329
+ itemsPerRow: 1,
330
+ showDetails: false
331
+ };
332
+
333
+ export const GRID_VIEW_TYPE: ListViewType = {
334
+ id: "grid",
335
+ name: "Grid",
336
+ icon: "grid",
337
+ itemsPerRow: 'auto', // Calculated based on container width
338
+ showDetails: false
339
+ };
340
+
341
+ export const DETAILS_VIEW_TYPE: ListViewType = {
342
+ id: "details",
343
+ name: "Details",
344
+ icon: "table",
345
+ itemsPerRow: 1,
346
+ showDetails: true,
347
+ columns: ['name', 'size', 'modified', 'type']
348
+ };
349
+
350
+ export const THUMBNAILS_VIEW_TYPE: ListViewType = {
351
+ id: "thumbnails",
352
+ name: "Thumbnails",
353
+ icon: "images",
354
+ itemsPerRow: 'auto',
355
+ showThumbnails: true,
356
+ thumbnailSizes: ['small', 'medium', 'large', 'extra-large']
357
+ };
358
+
359
+ export const MASONRY_HORIZONTAL_VIEW_TYPE: ListViewType = {
360
+ id: "masonry-horizontal",
361
+ name: "Masonry Horizontal",
362
+ icon: "masonry-horizontal",
363
+ itemsPerRow: 'auto',
364
+ showDetails: false,
365
+ masonry: true
366
+ };
367
+
368
+ export const MASONRY_VERTICAL_VIEW_TYPE: ListViewType = {
369
+ id: "masonry-vertical",
370
+ name: "Masonry Vertical",
371
+ icon: "masonry-vertical",
372
+ itemsPerRow: 'auto',
373
+ showDetails: false,
374
+ masonry: true
375
+ };
376
+ ```
377
+
378
+ ### Custom View Types
379
+ ```typescript
380
+ export const CUSTOM_VIEW_TYPE: ListViewType = {
381
+ id: "custom-cushion-tree-map",
382
+ name: "Cushion Tree Map",
383
+ icon: "custom",
384
+ itemsPerRow: 'custom',
385
+ customRenderer: CushionTreeMapRenderer
386
+ };
387
+ ```
388
+
389
+ ## File & Folder Structure
390
+
391
+ ```
392
+ fs-ui/src/ListItemsComponent/
393
+ ├── architecture.md
394
+ ├── providers/
395
+ │ └── ListItemsProvider.ts # Provider interface
396
+ ├── models/
397
+ │ ├── ListItemsModel.ts # Main MobX state model
398
+ │ ├── ListSelection.ts # Selection state management
399
+ │ ├── ViewTypeManager.ts # View type state management
400
+ │ ├── VirtualizationModel.ts # Virtualization state management
401
+ │ └── ListLoading.ts # Loading state management
402
+ ├── components/
403
+ │ ├── ListItems.tsx # Main list component
404
+ │ ├── ListItem.tsx # Individual item component
405
+ │ ├── VirtualizedList.tsx # Virtualization wrapper
406
+ │ ├── ViewTypeSelector.tsx # View type switcher
407
+ │ ├── ListContextMenu.tsx # Context menu component
408
+ │ ├── GridView.tsx # Grid layout component
409
+ │ ├── DetailsView.tsx # Details/table view component
410
+ │ ├── ThumbnailsView.tsx # Thumbnails view component
411
+ │ └── shared/
412
+ │ ├── ListIcon.tsx # Icon rendering
413
+ │ ├── ListLoader.tsx # Loading indicators
414
+ │ ├── ListThumbnail.tsx # Thumbnail rendering
415
+ │ └── ListVirtualization.tsx # Virtual scrolling utilities
416
+ ├── renderers/
417
+ │ ├── DefaultItemRenderer.ts # Default item rendering
418
+ │ ├── TextItemRenderer.ts # Text-only rendering
419
+ │ ├── ThumbnailItemRenderer.ts # Thumbnail rendering
420
+ │ └── CustomItemRenderer.tsx # Custom React rendering
421
+ ├── types/
422
+ │ ├── ListTypes.ts # Core type definitions
423
+ │ ├── ListEvents.ts # Event type definitions
424
+ │ ├── ListViewTypes.ts # View type definitions
425
+ │ └── ListOptions.ts # Configuration types
426
+ ├── utils/
427
+ │ ├── ListUtils.ts # List manipulation utilities
428
+ │ ├── ListKeyboard.ts # Keyboard navigation
429
+ │ ├── ListAccessibility.ts # ARIA utilities
430
+ │ ├── ListVirtualization.ts # Virtualization calculations
431
+ │ └── ListTextEllipsis.ts # Text truncation utilities
432
+ └── index.ts # Public exports
433
+ ```
434
+
435
+ ## Data Flow
436
+
437
+ ### 1. Initialization
438
+ ```
439
+ 1. ListItems component receives ListItemsProvider
440
+ 2. ListItemsModel created with provider
441
+ 3. ListItemsModel calls provider.initialize()
442
+ 4. ListItemsModel calls provider.loadItems()
443
+ 5. ListItems renders with initial data and view type
444
+ ```
445
+
446
+ ### 2. View Type Changes
447
+ ```
448
+ User clicks view type button
449
+
450
+ ViewTypeSelector component handles event
451
+
452
+ Calls ListItemsModel.setViewType()
453
+
454
+ ListItemsModel updates @observable currentViewType
455
+
456
+ ListItemsModel calls provider.onViewTypeChange()
457
+
458
+ UI re-renders with new layout via MobX observer
459
+ ```
460
+
461
+ ### 3. Virtualization Flow
462
+ ```
463
+ User scrolls list
464
+
465
+ VirtualizedList component updates viewport
466
+
467
+ Calls ListItemsModel.updateViewport()
468
+
469
+ ListItemsModel calculates visible range
470
+
471
+ If new items needed: calls loadItemRange()
472
+
473
+ UI renders only visible items
474
+ ```
475
+
476
+ ### 4. Selection Interactions
477
+ ```
478
+ User clicks item (with modifiers)
479
+
480
+ ListItem component handles event
481
+
482
+ Calls ListItemsModel.selectItem(modifiers)
483
+
484
+ ListItemsModel updates @observable selectedItems
485
+
486
+ ListItemsModel calls provider.onSelectionChange()
487
+
488
+ UI re-renders selection state via MobX observer
489
+ ```
490
+
491
+ ## Virtualization Strategy
492
+
493
+ ### Requirements
494
+ - **Mandatory**: Must handle 100k+ items without performance degradation
495
+ - **Library**: Use `react-window` or `react-virtualized-auto-sizer`
496
+ - **Height**: Fixed item heights per view type for optimal performance
497
+ - **Windowing**: Only render visible items + small overscan buffer
498
+ - **Dynamic Loading**: Load item ranges on-demand as user scrolls
499
+
500
+ ### Implementation
501
+ ```typescript
502
+ interface VirtualizationConfig {
503
+ /** Fixed item height for current view type */
504
+ itemHeight: number;
505
+ /** Items to render outside visible area */
506
+ overscan: number;
507
+ /** Minimum items before enabling virtualization */
508
+ threshold: number;
509
+ /** Dynamic loading range size */
510
+ rangeSize: number;
511
+ }
512
+
513
+ class VirtualizationModel {
514
+ viewportHeight: number = 0;
515
+ scrollTop: number = 0;
516
+ itemHeight: number = 40;
517
+
518
+ constructor(private owner: ListItemsModel) {
519
+ makeAutoObservable(this, {});
520
+ }
521
+
522
+ get visibleRange(): { start: number; end: number } {
523
+ const start = Math.floor(this.scrollTop / this.itemHeight);
524
+ const end = Math.min(
525
+ start + Math.ceil(this.viewportHeight / this.itemHeight),
526
+ this.owner.totalItemCount
527
+ );
528
+ return { start, end };
529
+ }
530
+
531
+ get visibleItems(): ListItemData[] {
532
+ const { start, end } = this.visibleRange;
533
+ return this.owner.items.slice(start, end + 1);
534
+ }
535
+ }
536
+ ```
537
+
538
+ ## Performance Optimizations
539
+
540
+ ### MobX Optimizations
541
+ - **Computed Properties**: Use for derived state calculations
542
+ - **Observable Maps**: For O(1) lookups instead of array.find()
543
+ - **Granular Observables**: Separate selection, loading, and UI state
544
+ - **Reaction Cleanup**: Dispose of unused reactions
545
+
546
+ ### Virtualization Optimizations
547
+ - **Fixed Heights**: Avoid dynamic height calculations
548
+ - **Overscan Buffer**: Prevent white space during fast scrolling
549
+ - **Range Loading**: Load items in batches, cache aggressively
550
+ - **Memory Management**: Unload items outside viewport bounds
551
+
552
+ ### Rendering Optimizations
553
+ - **Observer Components**: Extract list items to separate observer components
554
+ - **Memoization**: Use React.memo for expensive item renderers
555
+ - **CSS Containment**: Use CSS `contain` property for layout isolation
556
+ - **Image Lazy Loading**: Load thumbnails only when visible
557
+
558
+ ## Accessibility Features
559
+
560
+ ### Keyboard Navigation
561
+ - **Arrow Keys**: Navigate between items in all view types
562
+ - **Home/End**: Jump to first/last item
563
+ - **Page Up/Down**: Scroll by viewport height
564
+ - **Space**: Toggle selection (multi-select mode)
565
+ - **Enter**: Activate/open item
566
+ - **F2**: Start inline editing (if supported)
567
+
568
+ ### Screen Reader Support
569
+ - **Role Definitions**: `listbox`, `option`, `grid`, `gridcell`
570
+ - **ARIA Labels**: Descriptive labels for all interactive elements
571
+ - **Selection Announcements**: Announce selection changes
572
+ - **Position Information**: "Item 5 of 1000" for context
573
+ - **View Type Announcements**: Announce view changes
574
+
575
+ ### Focus Management
576
+ - **Visual Focus**: Clear focus indicators
577
+ - **Focus Trap**: Keep focus within component
578
+ - **Restore Focus**: Remember focus position on re-entry
579
+
580
+ ## Usage Examples
581
+
582
+ ### Basic File Explorer
583
+ ```typescript
584
+ const fileSystemProvider = new FileSystemListProvider(fileSystem, {
585
+ supportedViewTypes: [LIST_VIEW_TYPE, GRID_VIEW_TYPE, DETAILS_VIEW_TYPE],
586
+ multiSelectEnabled: true,
587
+ dragDropEnabled: true,
588
+ virtualizationEnabled: true,
589
+ defaultViewType: DETAILS_VIEW_TYPE
590
+ });
591
+
592
+ <ListItems provider={fileSystemProvider} height={600} />
593
+ ```
594
+
595
+ ### Media Gallery
596
+ ```typescript
597
+ const mediaProvider = new MediaGalleryProvider(mediaService, {
598
+ supportedViewTypes: [THUMBNAILS_VIEW_TYPE, GRID_VIEW_TYPE],
599
+ multiSelectEnabled: true,
600
+ virtualizationEnabled: true,
601
+ defaultThumbnailSize: 'large'
602
+ });
603
+
604
+ <ListItems provider={mediaProvider} />
605
+ ```
606
+
607
+ ### Custom Data Grid
608
+ ```typescript
609
+ class DataGridProvider implements ListItemsProvider {
610
+ constructor(private dataSource: DataSource) {}
611
+
612
+ async loadItems(options?: ListLoadOptions) {
613
+ return {
614
+ items: await this.dataSource.query(options),
615
+ totalCount: await this.dataSource.count()
616
+ };
617
+ }
618
+
619
+ getSupportedViewTypes() {
620
+ return [DETAILS_VIEW_TYPE, LIST_VIEW_TYPE];
621
+ }
622
+
623
+ getItemRenderer(item: ListItemData) {
624
+ return new CustomDataItemRenderer(item.type);
625
+ }
626
+
627
+ onSelectionChange(selectionInfo: ListSelectionInfo) {
628
+ // Handle selection for parent application
629
+ this.notifySelectionChanged(selectionInfo.selectedItems);
630
+ }
631
+ }
632
+ ```
633
+
634
+ ## Integration Points
635
+
636
+ ### With File System
637
+ ```typescript
638
+ const fileListProvider = new FileSystemListProvider(fileSystem, {
639
+ supportedViewTypes: [LIST_VIEW_TYPE, DETAILS_VIEW_TYPE, THUMBNAILS_VIEW_TYPE],
640
+ showHiddenFiles: false,
641
+ sortBy: 'name'
642
+ });
643
+
644
+ <ListItems provider={fileListProvider} />
645
+ ```
646
+
647
+ ### With Search Results
648
+ ```typescript
649
+ const searchProvider = new SearchResultsProvider(searchService, {
650
+ supportedViewTypes: [LIST_VIEW_TYPE, DETAILS_VIEW_TYPE],
651
+ highlightSearchTerms: true,
652
+ maxResults: 1000
653
+ });
654
+
655
+ <ListItems provider={searchProvider} />
656
+ ```
657
+
658
+ ### With Database Query
659
+ ```typescript
660
+ const dbProvider = new DatabaseListProvider(dbConnection, {
661
+ table: 'products',
662
+ supportedViewTypes: [DETAILS_VIEW_TYPE],
663
+ virtualizationEnabled: true,
664
+ pageSize: 100
665
+ });
666
+
667
+ <ListItems provider={dbProvider} />
668
+ ```
669
+
670
+ ## Error Handling & Loading States
671
+
672
+ ### Loading States
673
+ - **Initial Load**: Full component loading spinner
674
+ - **Range Loading**: Skeleton items in viewport
675
+ - **Background Refresh**: Subtle loading indicator
676
+ - **Search Loading**: Search spinner with debouncing
677
+
678
+ ### Error States
679
+ - **Load Errors**: Retry button with error message
680
+ - **Network Errors**: Offline indicator with retry
681
+ - **Permission Errors**: Clear access denied message
682
+ - **Partial Errors**: Show available items, note errors
683
+
684
+ ### Empty States
685
+ - **No Items**: Helpful empty state illustration
686
+ - **No Search Results**: Search suggestions and filters
687
+ - **Filter No Results**: Clear active filters button
688
+
689
+ ## Testing Strategy
690
+
691
+ ### Unit Tests
692
+ - **Models**: MobX state transitions and computed properties
693
+ - **Providers**: Data loading and callback functionality
694
+ - **Utils**: Virtualization calculations and utilities
695
+
696
+ ### Integration Tests
697
+ - **Provider + Model**: Data flow and state management
698
+ - **Component + Model**: UI interactions and updates
699
+ - **Virtualization**: Scroll behavior and range loading
700
+
701
+ ### E2E Tests
702
+ - **View Switching**: All view types render correctly
703
+ - **Large Datasets**: Performance with 10k+ items
704
+ - **Selection**: Multi-select with keyboard and mouse
705
+ - **Accessibility**: Screen reader and keyboard navigation
706
+
707
+ ## Migration Notes
708
+
709
+ ### From Legacy Components
710
+ 1. **Wrap existing data sources** in ListItemsProvider interface
711
+ 2. **Migrate selection logic** to provider callbacks
712
+ 3. **Update view switching** to use view type system
713
+ 4. **Add virtualization** for performance with large datasets
714
+ 5. **Enhance accessibility** with proper ARIA attributes
715
+
716
+ ### Breaking Changes
717
+ - **Selection API**: New selection event structure
718
+ - **View Types**: Standardized view type definitions
719
+ - **Rendering**: New renderer interface for customization
720
+ - **Performance**: Mandatory virtualization for large lists
721
+
722
+ This architecture provides a solid foundation for building high-performance, accessible list components that can handle massive datasets while maintaining a clean, extensible codebase following MobX best practices.
723
+
724
+ ## Size Controls
725
+
726
+ The `ViewSizeControls` component provides user interface for adjusting item sizes in grid and masonry views:
727
+
728
+ ### Features
729
+
730
+ - **Size Presets**: Quick buttons for small, medium, large, and extra-large sizes
731
+ - **Custom Sliders**: Fine-grained width and height adjustment sliders
732
+ - **Live Preview**: Real-time dimension display
733
+ - **View-Aware**: Only shows for views that support sizing (grid, masonry)
734
+
735
+ ### Usage
736
+
737
+ ```typescript
738
+ <ViewSizeControls
739
+ model={listModel}
740
+ showSizePresets={true}
741
+ showCustomSliders={false}
742
+ className="size-controls"
743
+ />
744
+ ```
745
+
746
+ ### Size Management in Model
747
+
748
+ The `ListItemsModel` provides size management through:
749
+
750
+ - `itemSize`: Current preset size ('small' | 'medium' | 'large' | 'extra-large')
751
+ - `customItemWidth`: Custom width in pixels (80-500px)
752
+ - `customItemHeight`: Custom height in pixels (60-400px)
753
+ - `itemsPerRow`: Number of items per row (1-8, or 'auto')
754
+ - `itemDimensions`: Computed property returning current dimensions
755
+ - `setItemSize()`: Set preset size with automatic dimension updates
756
+ - `setCustomItemWidth()` / `setCustomItemHeight()`: Fine-grained control
757
+ - `setItemsPerRow()`: Control column count in grid and masonry views
758
+
759
+ ## Variable Item Dimensions
760
+
761
+ Items can have custom dimensions for realistic masonry layouts:
762
+
763
+ ### Item Dimension Interface
764
+
765
+ ```typescript
766
+ interface ListItemData {
767
+ // ... other properties
768
+ getDimensions?(): { width: number; height: number };
769
+ imageUrl?: string;
770
+ aspectRatio?: number;
771
+ }
772
+ ```
773
+
774
+ ### Features
775
+
776
+ - **Dynamic Sizing**: Items can return custom dimensions via `getDimensions()`
777
+ - **Aspect Ratio Preservation**: Images maintain their aspect ratios in layouts
778
+ - **Fake Image Integration**: Uses picsum.photos for varied placeholder images
779
+ - **Performance Optimized**: Efficient rendering with large datasets (10,000+ items)
780
+
781
+ ### Image Service Integration
782
+
783
+ The component integrates with picsum.photos for realistic image placeholders:
784
+
785
+ ```typescript
786
+ // Generate varied image URLs
787
+ const imageUrl = `https://picsum.photos/${width}/${height}?random=${seed}`;
788
+ ```
789
+
790
+ ## Large Dataset Support
791
+
792
+ The component is optimized for large datasets:
793
+
794
+ ### Performance Features
795
+
796
+ - **Virtualization Ready**: Supports react-window for 10,000+ items
797
+ - **Efficient Rendering**: Memoized components and computed properties
798
+ - **Memory Management**: Proper cleanup and garbage collection
799
+ - **Smooth Scrolling**: Optimized for large lists without performance degradation
800
+
801
+ ### Test Dataset
802
+
803
+ The `TestListProvider` can generate large datasets with:
804
+ - 10,000 varied items
805
+ - Random dimensions and aspect ratios
806
+ - Fake images with different sizes
807
+ - Realistic file metadata