@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,530 @@
1
+ # TreeComponent Architecture
2
+
3
+ ## Overview
4
+
5
+ The TreeComponent is a reusable, high-performance tree component built with React, MobX, and TypeScript. It provides a flexible, accessible, and extensible tree interface that can work with any data source through the Provider pattern. The provider can work with or without React, supporting both web and non-web environments.
6
+
7
+ **🔄 Migration Status**: This TreeComponent is designed to replace the existing FileBrowser TreeView components. Once fully implemented and tested, it will replace the legacy tree components in the FileBrowser system, providing better performance, accessibility, and maintainability.
8
+
9
+ ## Design Principles
10
+
11
+ - **Provider-Driven Architecture**: TreeProvider model drives ALL behavior (selection, drag-drop, virtualization)
12
+ - **Direct Provider Injection**: No registry pattern - provider passed directly to Tree 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 configured in provider
19
+ - **Callback-Based**: Tree component calls provider callbacks for all interactions
20
+ - **Node-Level Customization**: Per-node 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**: Virtualization support for large trees
25
+ - **Type Safety**: Comprehensive TypeScript coverage
26
+
27
+ ## MobX Best Practices (CRITICAL)
28
+
29
+ **⚠️ STRICT REQUIREMENTS - These patterns must be followed exactly:**
30
+
31
+ ### 1. No Decorators - Use makeAutoObservable
32
+ ```typescript
33
+ // ❌ NEVER use decorators
34
+ class TreeModel {
35
+ @observable nodes = []
36
+ @action selectNode() {}
37
+ }
38
+
39
+ // ✅ ALWAYS use makeAutoObservable
40
+ class TreeModel {
41
+ nodes = []
42
+
43
+ constructor() {
44
+ makeAutoObservable(this, {}); // Empty overrides object
45
+ }
46
+
47
+ selectNode() {} // Automatically becomes action
48
+ }
49
+ ```
50
+
51
+ ### 2. Observable Collections - Use observable.map()
52
+ ```typescript
53
+ // ❌ NEVER use plain Map/Set
54
+ selectedNodes = new Map<string, TreeNodeData>()
55
+ expandedNodes = new Set<string>()
56
+
57
+ // ✅ ALWAYS use observable.map()
58
+ selectedNodes = observable.map<string, TreeNodeData>()
59
+ expandedNodes = observable.map<string, boolean>()
60
+ ```
61
+
62
+ ### 3. Async Actions - Use flow
63
+ ```typescript
64
+ // ❌ NEVER use async/await directly in actions
65
+ async loadNodes() {
66
+ this.isLoading = true;
67
+ const result = await api.loadNodes();
68
+ this.nodes = result; // ⚠️ Not in action!
69
+ }
70
+
71
+ // ✅ ALWAYS use flow for async operations
72
+ loadNodes = flow(function* (this: TreeModel) {
73
+ this.isLoading = true;
74
+ const result = yield api.loadNodes();
75
+ this.nodes = result; // ✅ Automatically in action
76
+ });
77
+ ```
78
+
79
+ ### 4. Composition Over Inheritance
80
+ ```typescript
81
+ // ❌ NEVER use inheritance (MobX issues)
82
+ class BaseModel {}
83
+ class TreeModel extends BaseModel {}
84
+
85
+ // ✅ ALWAYS use composition
86
+ class TreeModel {
87
+ selectionManager: TreeSelectionModel;
88
+ expansionManager: TreeExpansionModel;
89
+
90
+ constructor() {
91
+ makeAutoObservable(this, {});
92
+ this.selectionManager = new TreeSelectionModel(this);
93
+ this.expansionManager = new TreeExpansionModel(this);
94
+ }
95
+ }
96
+ ```
97
+
98
+ ### 5. Computed Properties for Performance
99
+ ```typescript
100
+ class TreeModel {
101
+ selectedNodes = observable.map<string, TreeNodeData>()
102
+
103
+ constructor() {
104
+ makeAutoObservable(this, {});
105
+ }
106
+
107
+ // ✅ Computed properties are automatically optimized
108
+ get selectedNodesArray() {
109
+ return Array.from(this.selectedNodes.values());
110
+ }
111
+
112
+ get hasSelection() {
113
+ return this.selectedNodes.size > 0;
114
+ }
115
+ }
116
+ ```
117
+
118
+ ### 6. Observer Components for Lists
119
+ ```typescript
120
+ // ❌ NEVER render observables directly in map
121
+ const NodeList = observer(() => (
122
+ <div>
123
+ {nodes.map(node => <div key={node.id}>{node.name}</div>)} {/* Won't react! */}
124
+ </div>
125
+ ))
126
+
127
+ // ✅ ALWAYS extract to separate observer components
128
+ const NodeItem = observer(({ node }) => <div>{node.name}</div>)
129
+
130
+ const NodeList = observer(() => (
131
+ <div>
132
+ {nodes.map(node => <NodeItem key={node.id} node={node} />)}
133
+ </div>
134
+ ))
135
+ ```
136
+
137
+ ## Architecture Overview
138
+
139
+ ```
140
+ TreeComponent
141
+ ↓ receives
142
+ TreeProvider (MobX Model)
143
+ ↓ provides data & callbacks
144
+ TreeModel (MobX State)
145
+ ↓ manages
146
+ Tree Components (React UI)
147
+ ```
148
+
149
+ ## Core Components
150
+
151
+ ### 1. TreeProvider (Model Layer)
152
+ **Location**: `/providers/TreeProvider.ts`
153
+
154
+ **Purpose**: Defines the contract for data loading, node rendering, and interaction callbacks. Works independently of React.
155
+
156
+ **Key Features**:
157
+ - Data loading methods (`loadNodes`, `loadChildren`, `refresh`, `search`)
158
+ - Per-node context menus (`getNodeContextMenu`, `getMultiNodeContextMenu`)
159
+ - Node rendering overrides (`getNodeRenderer`, `getDefaultRenderer`)
160
+ - Capability checks (`canExpand`, `canSelect`, `canDrag`, `canDrop`)
161
+ - Event callbacks (`onSelectionChange`, `onDragDrop`, `onContextMenuAction`)
162
+ - Non-React node rendering (`TreeNodeRenderer.renderText`, `renderIcon`)
163
+
164
+ ### 2. TreeModel (State Layer)
165
+ **Location**: `/models/TreeModel.ts`
166
+
167
+ **Purpose**: MobX observable state container that manages tree data, selection, expansion, and UI state.
168
+
169
+ **State Management**:
170
+ ```typescript
171
+ class TreeModel {
172
+ // Core Data - using observable.map for reactive collections
173
+ nodes: TreeNodeData[] = []
174
+ nodeMap = observable.map<string, TreeNodeData>()
175
+
176
+ // UI State - using observable.map instead of Set/Map
177
+ selectedNodes = observable.map<string, TreeNodeData>()
178
+ expandedNodes = observable.map<string, boolean>()
179
+ focusedNode: string | null = null
180
+
181
+ // Loading State
182
+ isLoading: boolean = false
183
+ loadingNodes = observable.map<string, boolean>()
184
+ errors = observable.map<string, Error>()
185
+
186
+ // Interaction State
187
+ draggedNodes: TreeNodeData[] = []
188
+ dropTarget: TreeNodeData | null = null
189
+ contextMenuNode: TreeNodeData | null = null
190
+
191
+ constructor(public provider: TreeProvider) {
192
+ makeAutoObservable(this, {
193
+ // Most defaults are correct, empty overrides object
194
+ });
195
+ }
196
+
197
+ // Computed properties for derived state
198
+ get selectedNodesArray(): TreeNodeData[] {
199
+ return Array.from(this.selectedNodes.values());
200
+ }
201
+
202
+ get hasSelection(): boolean {
203
+ return this.selectedNodes.size > 0;
204
+ }
205
+
206
+ get isNodeSelected() {
207
+ return (nodeId: string) => this.selectedNodes.has(nodeId);
208
+ }
209
+
210
+ // Async actions using flow
211
+ loadNodes = flow(function* (this: TreeModel, options?: TreeLoadOptions) {
212
+ this.isLoading = true;
213
+ this.errors.clear();
214
+
215
+ try {
216
+ const result = yield this.provider.loadNodes(options);
217
+ this.nodes = result.nodes;
218
+
219
+ // Update node map for fast lookups
220
+ this.nodeMap.clear();
221
+ result.nodes.forEach(node => this.nodeMap.set(node.id, node));
222
+
223
+ } catch (error) {
224
+ this.errors.set('loadNodes', error);
225
+ } finally {
226
+ this.isLoading = false;
227
+ }
228
+ });
229
+ }
230
+ ```
231
+
232
+ ### 3. Tree Component (UI Layer)
233
+ **Location**: `/components/Tree.tsx`
234
+
235
+ **Purpose**: Main React component that receives TreeProvider as prop and renders the tree UI.
236
+
237
+ **Component Interface**:
238
+ ```typescript
239
+ interface TreeProps {
240
+ provider: TreeProvider;
241
+ className?: string;
242
+ height?: number;
243
+ // All behavior controlled by provider - no separate props
244
+ }
245
+
246
+ export const Tree = observer(({ provider, className, height }: TreeProps) => {
247
+ const [model] = useState(() => new TreeModel(provider))
248
+
249
+ // All configuration comes from provider:
250
+ // - provider.isMultiSelectEnabled
251
+ // - provider.isDragDropEnabled
252
+ // - provider.isVirtualizationEnabled
253
+ // - provider.getVirtualizationConfig()
254
+
255
+ // Component delegates all actions to model,
256
+ // which calls provider callbacks
257
+ })
258
+ ```
259
+
260
+ ## File & Folder Structure
261
+
262
+ ```
263
+ fs-ui/src/TreeComponent/
264
+ ├── architecture.md
265
+ ├── providers/
266
+ │ └── TreeProvider.ts # Provider interface
267
+ ├── models/
268
+ │ ├── TreeModel.ts # Main MobX state model
269
+ │ ├── TreeNode.ts # Individual node state
270
+ │ ├── TreeSelection.ts # Selection state management
271
+ │ ├── TreeExpansion.ts # Expansion state management
272
+ │ └── TreeLoading.ts # Loading state management
273
+ ├── components/
274
+ │ ├── Tree.tsx # Main tree component
275
+ │ ├── TreeNode.tsx # Individual node component
276
+ │ ├── TreeNodeList.tsx # Node list container
277
+ │ ├── TreeContextMenu.tsx # Context menu component
278
+ │ └── shared/
279
+ │ ├── TreeIcon.tsx # Icon rendering
280
+ │ ├── TreeLoader.tsx # Loading indicators
281
+ │ └── TreeVirtualization.tsx # Virtual scrolling
282
+ ├── renderers/
283
+ │ ├── DefaultNodeRenderer.ts # Default node rendering
284
+ │ ├── TextNodeRenderer.ts # Text-only rendering
285
+ │ └── CustomNodeRenderer.tsx # Custom React rendering
286
+ ├── types/
287
+ │ ├── TreeTypes.ts # Core type definitions
288
+ │ ├── TreeEvents.ts # Event type definitions
289
+ │ └── TreeOptions.ts # Configuration types
290
+ ├── utils/
291
+ │ ├── TreeUtils.ts # Tree manipulation utilities
292
+ │ ├── TreeKeyboard.ts # Keyboard navigation
293
+ │ └── TreeAccessibility.ts # ARIA utilities
294
+ └── index.ts # Public exports
295
+ ```
296
+
297
+ ## Data Flow
298
+
299
+ ### 1. Initialization
300
+ ```
301
+ 1. Tree component receives TreeProvider
302
+ 2. TreeModel created with provider
303
+ 3. TreeModel calls provider.initialize()
304
+ 4. TreeModel calls provider.loadNodes()
305
+ 5. Tree renders with initial data
306
+ ```
307
+
308
+ ### 2. User Interactions
309
+ ```
310
+ User clicks node
311
+
312
+ TreeNode component handles event
313
+
314
+ Calls TreeModel.selectNode()
315
+
316
+ TreeModel updates @observable selectedNodes
317
+
318
+ TreeModel calls provider.onSelectionChange()
319
+
320
+ UI re-renders via MobX observer
321
+ ```
322
+
323
+ ### 3. Context Menus
324
+ ```
325
+ User right-clicks node
326
+
327
+ TreeNode calls provider.getNodeContextMenu(node)
328
+
329
+ TreeContextMenu renders menu items
330
+
331
+ User clicks menu item
332
+
333
+ TreeContextMenu calls provider.onContextMenuAction()
334
+ ```
335
+
336
+ ### 4. Custom Rendering
337
+ ```
338
+ TreeNode needs to render
339
+
340
+ Calls provider.getNodeRenderer(node)
341
+
342
+ If custom renderer exists:
343
+ - Use renderer.renderComponent (React)
344
+ - Or renderer.renderText (non-React)
345
+
346
+ Otherwise use default rendering
347
+ ```
348
+
349
+ ## State Management Details
350
+
351
+ ### TreeModel State Structure (MobX Best Practices)
352
+ ```typescript
353
+ class TreeModel {
354
+ // Core Data - using observable.map for reactive collections
355
+ nodes: TreeNodeData[] = []
356
+ nodeMap = observable.map<string, TreeNodeData>()
357
+
358
+ // UI State - using observable.map instead of Set/Map
359
+ selectedNodes = observable.map<string, TreeNodeData>()
360
+ expandedNodes = observable.map<string, boolean>()
361
+ focusedNode: string | null = null
362
+
363
+ // Loading State
364
+ isLoading: boolean = false
365
+ loadingNodes = observable.map<string, boolean>()
366
+ errors = observable.map<string, Error>()
367
+
368
+ // Interaction State
369
+ draggedNodes: TreeNodeData[] = []
370
+ dropTarget: TreeNodeData | null = null
371
+ contextMenuNode: TreeNodeData | null = null
372
+
373
+ constructor(public provider: TreeProvider) {
374
+ makeAutoObservable(this, {
375
+ // Most defaults are correct, empty overrides object
376
+ });
377
+ }
378
+
379
+ // Computed properties for derived state
380
+ get selectedNodesArray(): TreeNodeData[] {
381
+ return Array.from(this.selectedNodes.values());
382
+ }
383
+
384
+ get hasSelection(): boolean {
385
+ return this.selectedNodes.size > 0;
386
+ }
387
+
388
+ get isNodeSelected() {
389
+ return (nodeId: string) => this.selectedNodes.has(nodeId);
390
+ }
391
+
392
+ // Async actions using flow
393
+ loadNodes = flow(function* (this: TreeModel, options?: TreeLoadOptions) {
394
+ this.isLoading = true;
395
+ this.errors.clear();
396
+
397
+ try {
398
+ const result = yield this.provider.loadNodes(options);
399
+ this.nodes = result.nodes;
400
+
401
+ // Update node map for fast lookups
402
+ this.nodeMap.clear();
403
+ result.nodes.forEach(node => this.nodeMap.set(node.id, node));
404
+
405
+ } catch (error) {
406
+ this.errors.set('loadNodes', error);
407
+ } finally {
408
+ this.isLoading = false;
409
+ }
410
+ });
411
+ }
412
+ ```
413
+
414
+ ### Provider Callback Integration
415
+ All user interactions flow through the provider:
416
+
417
+ - **Selection**: `provider.onSelectionChange(selectionInfo)`
418
+ - **Expansion**: `provider.onNodeExpansion(node, expanded)`
419
+ - **Double-click**: `provider.onNodeDoubleClick(node)`
420
+ - **Drag & Drop**: `provider.onDragDrop(dragInfo)`
421
+ - **Context Menu**: `provider.onContextMenuAction(menuId, nodes)`
422
+ - **Focus**: `provider.onNodeFocus(node)`
423
+
424
+ ## Node Rendering System
425
+
426
+ ### Multi-Environment Support
427
+ The TreeProvider supports rendering in multiple environments:
428
+
429
+ ```typescript
430
+ interface TreeNodeRenderer {
431
+ // Non-React environments (Node.js, CLI tools)
432
+ renderText?(node: TreeNodeData): string
433
+ renderIcon?(node: TreeNodeData): string
434
+ getDisplayProps?(node: TreeNodeData): DisplayProps
435
+
436
+ // React environments
437
+ renderComponent?: React.ComponentType<{node: TreeNodeData}>
438
+ }
439
+ ```
440
+
441
+ ### Per-Node Customization
442
+ Each node can have its own renderer:
443
+
444
+ ```typescript
445
+ // Provider can customize per node
446
+ provider.getNodeRenderer(fileNode) // Returns FileRenderer
447
+ provider.getNodeRenderer(dirNode) // Returns DirectoryRenderer
448
+ provider.getDefaultRenderer() // Returns fallback renderer
449
+ ```
450
+
451
+ ### Context Menu Customization
452
+ Each node can have different context menus:
453
+
454
+ ```typescript
455
+ // Different menus per node type
456
+ provider.getNodeContextMenu(fileNode) // [Edit, Delete, Rename]
457
+ provider.getNodeContextMenu(dirNode) // [New File, New Folder, Delete]
458
+ provider.getMultiNodeContextMenu(nodes) // [Delete Selected, Move]
459
+ provider.getEmptySpaceContextMenu() // [New File, New Folder, Paste]
460
+ ```
461
+
462
+ ## Usage Examples
463
+
464
+ ### Basic Usage
465
+ ```typescript
466
+ // Create provider with configuration
467
+ const fileSystemProvider = new FileSystemTreeProvider(fileSystem, {
468
+ multiSelectEnabled: true,
469
+ dragDropEnabled: true,
470
+ virtualizationEnabled: true
471
+ })
472
+
473
+ // Use in React - all behavior comes from provider
474
+ <Tree provider={fileSystemProvider} />
475
+ ```
476
+
477
+ ### Custom Provider Implementation
478
+ ```typescript
479
+ class GitTreeProvider implements TreeProvider {
480
+ constructor(private gitRepo: GitRepository) {}
481
+
482
+ async loadNodes() {
483
+ return { nodes: await this.gitRepo.getFiles() }
484
+ }
485
+
486
+ getNodeContextMenu(node: TreeNodeData) {
487
+ if (node.type === 'file') {
488
+ return [
489
+ { id: 'edit', label: 'Edit File', icon: 'edit' },
490
+ { id: 'delete', label: 'Delete', icon: 'trash' },
491
+ { type: 'separator' },
492
+ { id: 'commit', label: 'Commit Changes', icon: 'git-commit' }
493
+ ]
494
+ }
495
+ return []
496
+ }
497
+
498
+ onContextMenuAction(menuId: string, nodes: TreeNodeData[]) {
499
+ switch (menuId) {
500
+ case 'edit': this.editFile(nodes[0]); break
501
+ case 'delete': this.deleteFiles(nodes); break
502
+ case 'commit': this.commitChanges(nodes); break
503
+ }
504
+ }
505
+ }
506
+ ```
507
+
508
+ ## Performance Considerations
509
+
510
+ - **MobX Reactivity**: Only affected components re-render on state changes
511
+ - **Virtualization**: Built-in support for large trees
512
+ - **Lazy Loading**: Provider-driven on-demand loading
513
+ - **Memory Management**: Automatic cleanup of unused nodes
514
+ - **Debounced Actions**: Built-in debouncing for frequent operations
515
+
516
+ ## Accessibility Features
517
+
518
+ - **ARIA Support**: Full screen reader compatibility
519
+ - **Keyboard Navigation**: Arrow keys, space, enter
520
+ - **Focus Management**: Proper focus handling and visibility
521
+ - **High Contrast**: Respects system accessibility preferences
522
+ - **Voice Control**: Semantic markup for voice navigation
523
+
524
+ ## Integration Points
525
+
526
+ ### With FileBrowser
527
+ ```typescript
528
+ const fileBrowserProvider = new FileBrowserTreeProvider(fileSystem)
529
+ <Tree provider={fileBrowserProvider} />
530
+ ```