@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,563 @@
1
+ // Simple debounce implementation
2
+ const debounce = <T extends (...args: any[]) => void>(
3
+ func: T,
4
+ wait: number
5
+ ): ((...args: Parameters<T>) => void) => {
6
+ let timeout: NodeJS.Timeout;
7
+ return (...args: Parameters<T>) => {
8
+ clearTimeout(timeout);
9
+ timeout = setTimeout(() => func(...args), wait);
10
+ };
11
+ };
12
+
13
+ // Simple throttle implementation
14
+ const throttle = <T extends (...args: any[]) => void>(
15
+ func: T,
16
+ wait: number
17
+ ): ((...args: Parameters<T>) => void) => {
18
+ let lastRun = 0;
19
+ return (...args: Parameters<T>) => {
20
+ if (Date.now() - lastRun >= wait) {
21
+ func(...args);
22
+ lastRun = Date.now();
23
+ }
24
+ };
25
+ };
26
+
27
+ /**
28
+ * Performance optimization utilities for FileBrowser responsive design
29
+ */
30
+
31
+ export interface PerformanceMetrics {
32
+ renderTime: number;
33
+ interactionLatency: number;
34
+ memoryUsage: number;
35
+ bundleSize: number;
36
+ frameRate: number;
37
+ touchLatency: number;
38
+ }
39
+
40
+ export interface PerformanceThresholds {
41
+ maxRenderTime: number;
42
+ maxInteractionLatency: number;
43
+ maxMemoryUsage: number;
44
+ minFrameRate: number;
45
+ maxTouchLatency: number;
46
+ }
47
+
48
+ export class PerformanceMonitor {
49
+ private metrics: Partial<PerformanceMetrics> = {};
50
+ private thresholds: PerformanceThresholds;
51
+ private warnings: string[] = [];
52
+ private observers: PerformanceObserver[] = [];
53
+
54
+ constructor(thresholds: Partial<PerformanceThresholds> = {}) {
55
+ this.thresholds = {
56
+ maxRenderTime: 100, // 100ms
57
+ maxInteractionLatency: 50, // 50ms
58
+ maxMemoryUsage: 100 * 1024 * 1024, // 100MB
59
+ minFrameRate: 30, // 30fps
60
+ maxTouchLatency: 16, // 16ms for 60fps
61
+ ...thresholds
62
+ };
63
+
64
+ this.setupPerformanceObservers();
65
+ }
66
+
67
+ private setupPerformanceObservers() {
68
+ if (typeof PerformanceObserver !== 'undefined') {
69
+ // Monitor paint metrics
70
+ const paintObserver = new PerformanceObserver((list) => {
71
+ for (const entry of list.getEntries()) {
72
+ if (entry.name === 'first-contentful-paint') {
73
+ this.metrics.renderTime = entry.startTime;
74
+ this.checkThreshold('renderTime', entry.startTime, this.thresholds.maxRenderTime);
75
+ }
76
+ }
77
+ });
78
+
79
+ paintObserver.observe({ entryTypes: ['paint'] });
80
+ this.observers.push(paintObserver);
81
+
82
+ // Monitor user interactions
83
+ const eventObserver = new PerformanceObserver((list) => {
84
+ for (const entry of list.getEntries()) {
85
+ const latency = entry.processingEnd - entry.startTime;
86
+ this.metrics.interactionLatency = latency;
87
+ this.checkThreshold('interactionLatency', latency, this.thresholds.maxInteractionLatency);
88
+ }
89
+ });
90
+
91
+ try {
92
+ eventObserver.observe({ entryTypes: ['event'] });
93
+ this.observers.push(eventObserver);
94
+ } catch (e) {
95
+ // Event timing API not supported
96
+ }
97
+ }
98
+ }
99
+
100
+ private checkThreshold(metric: keyof PerformanceMetrics, value: number, threshold: number) {
101
+ if (value > threshold) {
102
+ const warning = `Performance warning: ${metric} (${value.toFixed(2)}) exceeds threshold (${threshold})`;
103
+ this.warnings.push(warning);
104
+ console.warn(warning);
105
+ }
106
+ }
107
+
108
+ recordMetric(name: keyof PerformanceMetrics, value: number) {
109
+ this.metrics[name] = value;
110
+
111
+ const threshold = this.getThresholdForMetric(name);
112
+ if (threshold !== undefined) {
113
+ this.checkThreshold(name, value, threshold);
114
+ }
115
+ }
116
+
117
+ private getThresholdForMetric(name: keyof PerformanceMetrics): number | undefined {
118
+ switch (name) {
119
+ case 'renderTime': return this.thresholds.maxRenderTime;
120
+ case 'interactionLatency': return this.thresholds.maxInteractionLatency;
121
+ case 'memoryUsage': return this.thresholds.maxMemoryUsage;
122
+ case 'touchLatency': return this.thresholds.maxTouchLatency;
123
+ case 'frameRate': return this.thresholds.minFrameRate;
124
+ default: return undefined;
125
+ }
126
+ }
127
+
128
+ getMetrics(): Partial<PerformanceMetrics> {
129
+ return { ...this.metrics };
130
+ }
131
+
132
+ getWarnings(): string[] {
133
+ return [...this.warnings];
134
+ }
135
+
136
+ getRecommendations(): string[] {
137
+ const recommendations: string[] = [];
138
+
139
+ if (this.metrics.renderTime && this.metrics.renderTime > this.thresholds.maxRenderTime) {
140
+ recommendations.push('Enable virtualization for large lists');
141
+ recommendations.push('Implement React.memo for expensive components');
142
+ recommendations.push('Use code splitting for heavy components');
143
+ }
144
+
145
+ if (this.metrics.interactionLatency && this.metrics.interactionLatency > this.thresholds.maxInteractionLatency) {
146
+ recommendations.push('Debounce rapid user interactions');
147
+ recommendations.push('Use requestAnimationFrame for smooth animations');
148
+ recommendations.push('Optimize event handlers');
149
+ }
150
+
151
+ if (this.metrics.memoryUsage && this.metrics.memoryUsage > this.thresholds.maxMemoryUsage) {
152
+ recommendations.push('Implement LRU cache with size limits');
153
+ recommendations.push('Clean up event listeners on unmount');
154
+ recommendations.push('Use weak references for large objects');
155
+ }
156
+
157
+ if (this.metrics.touchLatency && this.metrics.touchLatency > this.thresholds.maxTouchLatency) {
158
+ recommendations.push('Optimize touch event handlers');
159
+ recommendations.push('Use passive event listeners');
160
+ recommendations.push('Reduce touch target processing time');
161
+ }
162
+
163
+ return recommendations;
164
+ }
165
+
166
+ dispose() {
167
+ this.observers.forEach(observer => observer.disconnect());
168
+ this.observers = [];
169
+ this.warnings = [];
170
+ this.metrics = {};
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Debounced resize handler for responsive layouts
176
+ */
177
+ export const createDebouncedResizeHandler = (
178
+ handler: (width: number, height: number) => void,
179
+ delay = 250
180
+ ) => {
181
+ return debounce((event: Event) => {
182
+ const width = window.innerWidth;
183
+ const height = window.innerHeight;
184
+ handler(width, height);
185
+ }, delay);
186
+ };
187
+
188
+ /**
189
+ * Throttled scroll handler for efficient scrolling
190
+ */
191
+ export const createThrottledScrollHandler = (
192
+ handler: (scrollTop: number, scrollLeft: number) => void,
193
+ delay = 16 // 60fps
194
+ ) => {
195
+ return throttle((event: Event) => {
196
+ const target = event.target as HTMLElement;
197
+ handler(target.scrollTop, target.scrollLeft);
198
+ }, delay);
199
+ };
200
+
201
+ /**
202
+ * Intersection Observer for lazy loading
203
+ */
204
+ export class LazyLoadManager {
205
+ private observer: IntersectionObserver;
206
+ private loadedItems = new Set<string>();
207
+
208
+ constructor(
209
+ private loadCallback: (element: Element) => void,
210
+ options: IntersectionObserverInit = {}
211
+ ) {
212
+ const defaultOptions: IntersectionObserverInit = {
213
+ root: null,
214
+ rootMargin: '50px',
215
+ threshold: 0.1,
216
+ ...options
217
+ };
218
+
219
+ this.observer = new IntersectionObserver((entries) => {
220
+ entries.forEach(entry => {
221
+ if (entry.isIntersecting && !this.loadedItems.has(entry.target.id)) {
222
+ this.loadedItems.add(entry.target.id);
223
+ this.loadCallback(entry.target);
224
+ this.observer.unobserve(entry.target);
225
+ }
226
+ });
227
+ }, defaultOptions);
228
+ }
229
+
230
+ observe(element: Element) {
231
+ if (!this.loadedItems.has(element.id)) {
232
+ this.observer.observe(element);
233
+ }
234
+ }
235
+
236
+ unobserve(element: Element) {
237
+ this.observer.unobserve(element);
238
+ this.loadedItems.delete(element.id);
239
+ }
240
+
241
+ disconnect() {
242
+ this.observer.disconnect();
243
+ this.loadedItems.clear();
244
+ }
245
+ }
246
+
247
+ /**
248
+ * Memory management utilities
249
+ */
250
+ export class MemoryManager {
251
+ private caches = new Map<string, Map<string, any>>();
252
+ private maxCacheSize = 100;
253
+
254
+ createLRUCache<T>(name: string, maxSize = this.maxCacheSize): LRUCache<T> {
255
+ const cache = new LRUCache<T>(maxSize);
256
+ this.caches.set(name, cache.storage);
257
+ return cache;
258
+ }
259
+
260
+ clearCaches() {
261
+ this.caches.forEach(cache => cache.clear());
262
+ }
263
+
264
+ getCacheStats() {
265
+ const stats: Record<string, { size: number; maxSize: number }> = {};
266
+
267
+ this.caches.forEach((cache, name) => {
268
+ stats[name] = {
269
+ size: cache.size,
270
+ maxSize: this.maxCacheSize
271
+ };
272
+ });
273
+
274
+ return stats;
275
+ }
276
+
277
+ getMemoryUsage(): number {
278
+ if ('memory' in performance) {
279
+ return (performance as any).memory.usedJSHeapSize;
280
+ }
281
+ return 0;
282
+ }
283
+
284
+ onMemoryPressure(callback: () => void) {
285
+ if ('memory' in performance) {
286
+ // Monitor memory usage and trigger callback when high
287
+ const checkMemory = () => {
288
+ const usage = this.getMemoryUsage();
289
+ const limit = 50 * 1024 * 1024; // 50MB threshold
290
+
291
+ if (usage > limit) {
292
+ callback();
293
+ }
294
+ };
295
+
296
+ setInterval(checkMemory, 5000); // Check every 5 seconds
297
+ }
298
+ }
299
+ }
300
+
301
+ /**
302
+ * LRU Cache implementation
303
+ */
304
+ export class LRUCache<T> {
305
+ public storage = new Map<string, T>();
306
+ private accessOrder = new Map<string, number>();
307
+ private accessCounter = 0;
308
+
309
+ constructor(private maxSize: number) {}
310
+
311
+ get(key: string): T | undefined {
312
+ const value = this.storage.get(key);
313
+ if (value !== undefined) {
314
+ this.accessOrder.set(key, ++this.accessCounter);
315
+ }
316
+ return value;
317
+ }
318
+
319
+ set(key: string, value: T): void {
320
+ if (this.storage.size >= this.maxSize && !this.storage.has(key)) {
321
+ this.evictLeastRecentlyUsed();
322
+ }
323
+
324
+ this.storage.set(key, value);
325
+ this.accessOrder.set(key, ++this.accessCounter);
326
+ }
327
+
328
+ has(key: string): boolean {
329
+ return this.storage.has(key);
330
+ }
331
+
332
+ delete(key: string): boolean {
333
+ this.accessOrder.delete(key);
334
+ return this.storage.delete(key);
335
+ }
336
+
337
+ clear(): void {
338
+ this.storage.clear();
339
+ this.accessOrder.clear();
340
+ this.accessCounter = 0;
341
+ }
342
+
343
+ private evictLeastRecentlyUsed(): void {
344
+ let oldestKey = '';
345
+ let oldestAccess = Infinity;
346
+
347
+ for (const [key, access] of this.accessOrder) {
348
+ if (access < oldestAccess) {
349
+ oldestAccess = access;
350
+ oldestKey = key;
351
+ }
352
+ }
353
+
354
+ if (oldestKey) {
355
+ this.delete(oldestKey);
356
+ }
357
+ }
358
+
359
+ get size(): number {
360
+ return this.storage.size;
361
+ }
362
+ }
363
+
364
+ /**
365
+ * Bundle size optimization utilities
366
+ */
367
+ export class BundleOptimizer {
368
+ private loadedModules = new Set<string>();
369
+ private modulePromises = new Map<string, Promise<any>>();
370
+
371
+ async loadModule<T>(
372
+ moduleName: string,
373
+ importFunction: () => Promise<{ default: T }>
374
+ ): Promise<T> {
375
+ if (this.loadedModules.has(moduleName)) {
376
+ return (await this.modulePromises.get(moduleName)!).default;
377
+ }
378
+
379
+ if (!this.modulePromises.has(moduleName)) {
380
+ const promise = importFunction();
381
+ this.modulePromises.set(moduleName, promise);
382
+
383
+ promise.then(() => {
384
+ this.loadedModules.add(moduleName);
385
+ });
386
+ }
387
+
388
+ const module = await this.modulePromises.get(moduleName)!;
389
+ return module.default;
390
+ }
391
+
392
+ getLoadedModules(): string[] {
393
+ return Array.from(this.loadedModules);
394
+ }
395
+
396
+ preloadModule(moduleName: string, importFunction: () => Promise<any>): void {
397
+ if (!this.loadedModules.has(moduleName) && !this.modulePromises.has(moduleName)) {
398
+ this.loadModule(moduleName, importFunction);
399
+ }
400
+ }
401
+ }
402
+
403
+ /**
404
+ * Touch performance optimization
405
+ */
406
+ export class TouchOptimizer {
407
+ private lastTouchTime = 0;
408
+ private touchLatencies: number[] = [];
409
+
410
+ createOptimizedTouchHandler<T extends Event>(
411
+ handler: (event: T) => void,
412
+ options: { passive?: boolean; capture?: boolean } = {}
413
+ ) {
414
+ const optimizedHandler = (event: T) => {
415
+ const startTime = performance.now();
416
+
417
+ // Throttle rapid touch events
418
+ if (startTime - this.lastTouchTime < 16) {
419
+ return;
420
+ }
421
+
422
+ this.lastTouchTime = startTime;
423
+
424
+ // Execute handler
425
+ handler(event);
426
+
427
+ // Track latency
428
+ const latency = performance.now() - startTime;
429
+ this.touchLatencies.push(latency);
430
+
431
+ // Keep only recent latencies
432
+ if (this.touchLatencies.length > 100) {
433
+ this.touchLatencies.shift();
434
+ }
435
+ };
436
+
437
+ return {
438
+ handler: optimizedHandler,
439
+ options: {
440
+ passive: true,
441
+ capture: false,
442
+ ...options
443
+ }
444
+ };
445
+ }
446
+
447
+ getAverageTouchLatency(): number {
448
+ if (this.touchLatencies.length === 0) return 0;
449
+
450
+ const sum = this.touchLatencies.reduce((a, b) => a + b, 0);
451
+ return sum / this.touchLatencies.length;
452
+ }
453
+
454
+ clearLatencyData(): void {
455
+ this.touchLatencies = [];
456
+ }
457
+ }
458
+
459
+ /**
460
+ * Device-specific optimizations
461
+ */
462
+ export class DeviceOptimizer {
463
+ private deviceInfo = this.getDeviceInfo();
464
+
465
+ private getDeviceInfo() {
466
+ const userAgent = navigator.userAgent;
467
+ const isMobile = /Mobile|Android|iPhone|iPad/.test(userAgent);
468
+ const isTablet = /iPad|Tablet/.test(userAgent);
469
+ const isLowEnd = this.isLowEndDevice();
470
+
471
+ return {
472
+ isMobile,
473
+ isTablet,
474
+ isDesktop: !isMobile && !isTablet,
475
+ isLowEnd,
476
+ pixelRatio: window.devicePixelRatio || 1,
477
+ connectionType: this.getConnectionType()
478
+ };
479
+ }
480
+
481
+ private isLowEndDevice(): boolean {
482
+ // Detect low-end devices based on available metrics
483
+ if ('memory' in navigator) {
484
+ return (navigator as any).memory.deviceMemory < 4; // Less than 4GB RAM
485
+ }
486
+
487
+ if ('hardwareConcurrency' in navigator) {
488
+ return navigator.hardwareConcurrency < 4; // Less than 4 CPU cores
489
+ }
490
+
491
+ return false;
492
+ }
493
+
494
+ private getConnectionType(): string {
495
+ if ('connection' in navigator) {
496
+ return (navigator as any).connection.effectiveType || 'unknown';
497
+ }
498
+ return 'unknown';
499
+ }
500
+
501
+ getOptimizationStrategy() {
502
+ const { isMobile, isTablet, isLowEnd, connectionType } = this.deviceInfo;
503
+
504
+ return {
505
+ // Rendering optimizations
506
+ enableVirtualization: isLowEnd || isMobile,
507
+ reduceAnimations: isLowEnd || connectionType === 'slow-2g',
508
+ lazyLoadImages: isMobile || connectionType === 'slow-2g',
509
+
510
+ // Interaction optimizations
511
+ debounceDelay: isLowEnd ? 500 : 250,
512
+ throttleDelay: isLowEnd ? 32 : 16,
513
+
514
+ // Memory optimizations
515
+ maxCacheSize: isLowEnd ? 20 : 100,
516
+ enableImageCompression: isMobile || connectionType === 'slow-2g',
517
+
518
+ // Bundle optimizations
519
+ enableCodeSplitting: true,
520
+ preloadCriticalModules: !isLowEnd,
521
+
522
+ // Touch optimizations
523
+ enablePassiveListeners: isMobile,
524
+ optimizeTouchTargets: isMobile || isTablet
525
+ };
526
+ }
527
+
528
+ getDeviceInfo() {
529
+ return { ...this.deviceInfo };
530
+ }
531
+ }
532
+
533
+ /**
534
+ * Performance optimization hook factory
535
+ */
536
+ export const createPerformanceOptimizations = () => {
537
+ const monitor = new PerformanceMonitor();
538
+ const memoryManager = new MemoryManager();
539
+ const bundleOptimizer = new BundleOptimizer();
540
+ const touchOptimizer = new TouchOptimizer();
541
+ const deviceOptimizer = new DeviceOptimizer();
542
+
543
+ const strategy = deviceOptimizer.getOptimizationStrategy();
544
+
545
+ return {
546
+ monitor,
547
+ memoryManager,
548
+ bundleOptimizer,
549
+ touchOptimizer,
550
+ deviceOptimizer,
551
+ strategy,
552
+
553
+ // Utility functions
554
+ debouncedResize: createDebouncedResizeHandler,
555
+ throttledScroll: createThrottledScrollHandler,
556
+
557
+ // Cleanup function
558
+ dispose: () => {
559
+ monitor.dispose();
560
+ memoryManager.clearCaches();
561
+ }
562
+ };
563
+ };