@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,105 @@
1
+ import { makeAutoObservable, observable } from 'mobx';
2
+ import type { TreeViewUIModel } from './ui/TreeViewUIModel';
3
+
4
+ export interface LeftPanelMode {
5
+ id: string;
6
+ name: string;
7
+ icon?: string;
8
+ component: React.ComponentType<any>;
9
+ isAvailable?: () => boolean;
10
+ }
11
+
12
+ export class LeftPanelManagerModel {
13
+ // Available left panel modes (provided by provider)
14
+ availableModes = observable.map<string, LeftPanelMode>();
15
+ currentMode = 'tree'; // default: tree navigation
16
+
17
+ // Tree view state (default mode)
18
+ treeViewUI: TreeViewUIModel;
19
+
20
+ // Other panel modes added by providers
21
+ customModes = observable.map<string, any>();
22
+
23
+ constructor(
24
+ private owner: { logger?: any },
25
+ treeViewUI: TreeViewUIModel
26
+ ) {
27
+ this.treeViewUI = treeViewUI;
28
+
29
+ // Add default tree mode
30
+ this.availableModes.set('tree', {
31
+ id: 'tree',
32
+ name: 'Tree',
33
+ icon: 'folder-tree',
34
+ component: {} as any, // Will be set by consumer
35
+ isAvailable: () => true
36
+ });
37
+
38
+ makeAutoObservable(this);
39
+ this.owner.logger?.info('LeftPanelManagerModel initialized');
40
+ }
41
+
42
+ // Actions
43
+ setCurrentMode = (modeId: string) => {
44
+ if (this.availableModes.has(modeId)) {
45
+ this.currentMode = modeId;
46
+ this.owner.logger?.info(`Left panel mode changed to: ${modeId}`);
47
+ } else {
48
+ this.owner.logger?.warn(`Unknown left panel mode: ${modeId}`);
49
+ }
50
+ };
51
+
52
+ addMode = (mode: LeftPanelMode) => {
53
+ this.availableModes.set(mode.id, mode);
54
+ this.owner.logger?.info(`Added left panel mode: ${mode.id}`);
55
+ };
56
+
57
+ removeMode = (modeId: string) => {
58
+ if (modeId === 'tree') {
59
+ this.owner.logger?.warn('Cannot remove default tree mode');
60
+ return;
61
+ }
62
+
63
+ this.availableModes.delete(modeId);
64
+ this.customModes.delete(modeId);
65
+
66
+ // Switch to tree if current mode was removed
67
+ if (this.currentMode === modeId) {
68
+ this.currentMode = 'tree';
69
+ }
70
+
71
+ this.owner.logger?.info(`Removed left panel mode: ${modeId}`);
72
+ };
73
+
74
+ addCustomModeState = (modeId: string, state: any) => {
75
+ this.customModes.set(modeId, state);
76
+ };
77
+
78
+ // Computed
79
+ get availableModesList() {
80
+ return Array.from(this.availableModes.values()).filter(mode =>
81
+ mode.isAvailable ? mode.isAvailable() : true
82
+ );
83
+ }
84
+
85
+ get fileBrowserModel() {
86
+ return this.owner as any; // Cast to access FileBrowserModel properties
87
+ }
88
+
89
+ get currentModeData() {
90
+ return this.availableModes.get(this.currentMode);
91
+ }
92
+
93
+ get hasMultipleModes() {
94
+ return this.availableModesList.length > 1;
95
+ }
96
+
97
+ get currentUIModel() {
98
+ switch (this.currentMode) {
99
+ case 'tree':
100
+ return this.treeViewUI;
101
+ default:
102
+ return this.customModes.get(this.currentMode) || null;
103
+ }
104
+ }
105
+ }
@@ -0,0 +1,312 @@
1
+ import { makeAutoObservable, reaction } from 'mobx';
2
+
3
+ interface NavigationOwner {
4
+ logger?: { info: (message: string) => void } | null;
5
+ leftPanel?: any; // LeftPanelManagerModel
6
+ rightPanel?: any; // RightPanelManagerModel
7
+ selectionManager?: any; // SelectionManagerModel
8
+ }
9
+
10
+ export class NavigationManagerModel {
11
+ // Observable state
12
+ history: string[] = [];
13
+ historyIndex = -1;
14
+
15
+ // Coordination state
16
+ isUpdatingFromPanels = false; // Prevent infinite loops
17
+
18
+ private owner: NavigationOwner;
19
+ private disposers: (() => void)[] = [];
20
+
21
+ constructor(owner: NavigationOwner) {
22
+ makeAutoObservable(this);
23
+
24
+ this.owner = owner;
25
+
26
+ // Set up coordination reactions
27
+ this.setupCoordinationReactions();
28
+ }
29
+
30
+ // Computed values
31
+ get canGoBack() {
32
+ return this.historyIndex > 0;
33
+ }
34
+
35
+ get canGoForward() {
36
+ return this.historyIndex < this.history.length - 1;
37
+ }
38
+
39
+ get currentPath() {
40
+ return this.historyIndex >= 0 ? (this.history[this.historyIndex] ?? '/') : '/';
41
+ }
42
+
43
+ get previousPath(): string | null {
44
+ if (!this.canGoBack) return null;
45
+ return this.history[this.historyIndex - 1] ?? null;
46
+ }
47
+
48
+ get nextPath(): string | null {
49
+ if (!this.canGoForward) return null;
50
+ return this.history[this.historyIndex + 1] ?? null;
51
+ }
52
+
53
+ // Actions
54
+ addToHistory = (path: string) => {
55
+ const normalizedPath = this.normalizePath(path);
56
+ this.owner.logger?.info(`addToHistory: ${normalizedPath}`);
57
+
58
+ // Don't add if it's the same as current path
59
+ if (normalizedPath === this.currentPath) {
60
+ return;
61
+ }
62
+
63
+ // Remove any forward history when adding new path
64
+ if (this.canGoForward) {
65
+ this.history = this.history.slice(0, this.historyIndex + 1);
66
+ }
67
+
68
+ // Add new path
69
+ this.history.push(normalizedPath);
70
+ this.historyIndex = this.history.length - 1;
71
+
72
+ // Limit history size to prevent memory issues
73
+ const maxHistorySize = 100;
74
+ if (this.history.length > maxHistorySize) {
75
+ this.history = this.history.slice(-maxHistorySize);
76
+ this.historyIndex = this.history.length - 1;
77
+ }
78
+ };
79
+
80
+ goBack = (): string | null => {
81
+ if (!this.canGoBack) {
82
+ this.owner.logger?.info('goBack: cannot go back');
83
+ return null;
84
+ }
85
+
86
+ this.historyIndex--;
87
+ const path = this.currentPath;
88
+ this.owner.logger?.info(`goBack: navigating to ${path}`);
89
+ return path;
90
+ };
91
+
92
+ goForward = (): string | null => {
93
+ if (!this.canGoForward) {
94
+ this.owner.logger?.info('goForward: cannot go forward');
95
+ return null;
96
+ }
97
+
98
+ this.historyIndex++;
99
+ const path = this.currentPath;
100
+ this.owner.logger?.info(`goForward: navigating to ${path}`);
101
+ return path;
102
+ };
103
+
104
+ goToParent = (currentPath: string): string | null => {
105
+ const normalizedPath = this.normalizePath(currentPath);
106
+ const parentPath = this.getParentPath(normalizedPath);
107
+
108
+ if (parentPath && parentPath !== normalizedPath) {
109
+ this.owner.logger?.info(`goToParent: ${normalizedPath} -> ${parentPath}`);
110
+ return parentPath;
111
+ }
112
+
113
+ this.owner.logger?.info(`goToParent: already at root for ${normalizedPath}`);
114
+ return null;
115
+ };
116
+
117
+ clearHistory = () => {
118
+ this.owner.logger?.info('clearHistory');
119
+ this.history = [];
120
+ this.historyIndex = -1;
121
+ };
122
+
123
+ setCurrentPath = (path: string) => {
124
+ this.addToHistory(path);
125
+ };
126
+
127
+ navigateTo = (path: string) => {
128
+ this.addToHistory(path);
129
+ };
130
+
131
+ // Path utilities
132
+ normalizePath = (path: string): string => {
133
+ if (!path || path === '') return '/';
134
+
135
+ // Ensure path starts with /
136
+ let normalized = path.startsWith('/') ? path : '/' + path;
137
+
138
+ // Remove trailing slash unless it's root
139
+ if (normalized.length > 1 && normalized.endsWith('/')) {
140
+ normalized = normalized.slice(0, -1);
141
+ }
142
+
143
+ // Resolve .. and . segments
144
+ const segments = normalized.split('/').filter(segment => segment !== '');
145
+ const resolvedSegments: string[] = [];
146
+
147
+ for (const segment of segments) {
148
+ if (segment === '..') {
149
+ if (resolvedSegments.length > 0) {
150
+ resolvedSegments.pop();
151
+ }
152
+ } else if (segment !== '.') {
153
+ resolvedSegments.push(segment);
154
+ }
155
+ }
156
+
157
+ return resolvedSegments.length === 0 ? '/' : '/' + resolvedSegments.join('/');
158
+ };
159
+
160
+ getParentPath = (path: string): string | null => {
161
+ const normalized = this.normalizePath(path);
162
+
163
+ if (normalized === '/') {
164
+ return null; // Root has no parent
165
+ }
166
+
167
+ const lastSlashIndex = normalized.lastIndexOf('/');
168
+ if (lastSlashIndex === 0) {
169
+ return '/'; // Parent is root
170
+ }
171
+
172
+ return normalized.substring(0, lastSlashIndex);
173
+ };
174
+
175
+ getPathSegments = (path: string): string[] => {
176
+ const normalized = this.normalizePath(path);
177
+ if (normalized === '/') return [];
178
+
179
+ return normalized.split('/').filter(segment => segment !== '');
180
+ };
181
+
182
+ joinPaths = (...paths: string[]): string => {
183
+ const joined = paths.join('/');
184
+ return this.normalizePath(joined);
185
+ };
186
+
187
+ // Coordination methods
188
+ private setupCoordinationReactions = () => {
189
+ // React to navigation changes for panel coordination
190
+ const navigationReaction = reaction(
191
+ () => this.currentPath,
192
+ (currentPath) => {
193
+ if (this.isUpdatingFromPanels || !currentPath) return;
194
+
195
+ this.owner.logger?.info(`Navigation reaction: path changed to ${currentPath}`);
196
+
197
+ // Update panels based on navigation
198
+ this.coordinateNavigation(currentPath);
199
+ },
200
+ { name: 'NavigationCoordination' }
201
+ );
202
+
203
+ this.disposers.push(navigationReaction);
204
+ };
205
+
206
+ private coordinateNavigation = (path: string) => {
207
+ if (this.isUpdatingFromPanels) return;
208
+
209
+ this.isUpdatingFromPanels = true;
210
+
211
+ try {
212
+ // Update right panel to show the new path content
213
+ if (this.owner.rightPanel) {
214
+ // If navigating to a directory, clear selection and show folder content
215
+ this.owner.rightPanel.setSelectedItem(null);
216
+ }
217
+
218
+ // Update selection manager to reflect navigation
219
+ if (this.owner.selectionManager) {
220
+ // Find the item for this path and set it as focused
221
+ // This will be implemented when we have access to the items
222
+ this.owner.logger?.info(`Navigation coordination: ${path}`);
223
+ }
224
+
225
+ } finally {
226
+ this.isUpdatingFromPanels = false;
227
+ }
228
+ };
229
+
230
+ // Panel-specific navigation methods
231
+ navigateFromTreePanel = (path: string) => {
232
+ this.isUpdatingFromPanels = true;
233
+
234
+ try {
235
+ this.navigateTo(path);
236
+
237
+ // Update right panel to show folder content
238
+ if (this.owner.rightPanel) {
239
+ this.owner.rightPanel.setSelectedItem(null);
240
+ }
241
+
242
+ this.owner.logger?.info(`Tree panel navigation: ${path}`);
243
+
244
+ } finally {
245
+ this.isUpdatingFromPanels = false;
246
+ }
247
+ };
248
+
249
+ navigateFromRightPanel = (path: string) => {
250
+ this.isUpdatingFromPanels = true;
251
+
252
+ try {
253
+ this.navigateTo(path);
254
+
255
+ // TODO: Update tree panel expansion when TreeNavigationView supports it
256
+ this.owner.logger?.info(`Right panel navigation: ${path}`);
257
+
258
+ } finally {
259
+ this.isUpdatingFromPanels = false;
260
+ }
261
+ };
262
+
263
+ // Breadcrumb navigation
264
+ navigateFromBreadcrumb = (path: string) => {
265
+ this.isUpdatingFromPanels = true;
266
+
267
+ try {
268
+ this.navigateTo(path);
269
+
270
+ // Update both panels
271
+ if (this.owner.rightPanel) {
272
+ this.owner.rightPanel.setSelectedItem(null);
273
+ }
274
+
275
+ this.owner.logger?.info(`Breadcrumb navigation: ${path}`);
276
+
277
+ } finally {
278
+ this.isUpdatingFromPanels = false;
279
+ }
280
+ };
281
+
282
+ // Enhanced navigation with coordination
283
+ navigateToWithCoordination = (path: string, source: 'tree' | 'right' | 'breadcrumb' | 'history' = 'history') => {
284
+ switch (source) {
285
+ case 'tree':
286
+ this.navigateFromTreePanel(path);
287
+ break;
288
+ case 'right':
289
+ this.navigateFromRightPanel(path);
290
+ break;
291
+ case 'breadcrumb':
292
+ this.navigateFromBreadcrumb(path);
293
+ break;
294
+ default:
295
+ this.navigateTo(path);
296
+ break;
297
+ }
298
+ };
299
+
300
+ // Set selection manager reference after both managers are created
301
+ setSelectionManager = (selectionManager: any) => {
302
+ (this.owner as any).selectionManager = selectionManager;
303
+ };
304
+
305
+ // Cleanup
306
+ dispose = () => {
307
+ this.disposers.forEach(disposer => disposer());
308
+ this.disposers = [];
309
+ this.clearHistory();
310
+ this.owner.logger?.info('NavigationManagerModel disposed');
311
+ };
312
+ }