@moontra/moonui-pro 2.20.2 → 2.20.4

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 (153) hide show
  1. package/package.json +8 -3
  2. package/plugin/index.d.ts +86 -0
  3. package/plugin/index.js +308 -0
  4. package/scripts/postinstall.js +191 -23
  5. package/src/components/advanced-chart/index.tsx +0 -1246
  6. package/src/components/advanced-forms/index.tsx +0 -585
  7. package/src/components/animated-button/index.tsx +0 -385
  8. package/src/components/calendar/event-dialog.tsx +0 -377
  9. package/src/components/calendar/index.tsx +0 -1220
  10. package/src/components/calendar-pro/index.tsx +0 -1697
  11. package/src/components/color-picker/index.tsx +0 -432
  12. package/src/components/credit-card-input/index.tsx +0 -406
  13. package/src/components/dashboard/dashboard-grid.tsx +0 -480
  14. package/src/components/dashboard/demo.tsx +0 -425
  15. package/src/components/dashboard/index.tsx +0 -1046
  16. package/src/components/dashboard/time-range-picker.tsx +0 -336
  17. package/src/components/dashboard/types.ts +0 -225
  18. package/src/components/dashboard/widgets/activity-feed.tsx +0 -349
  19. package/src/components/dashboard/widgets/chart-widget.tsx +0 -418
  20. package/src/components/dashboard/widgets/comparison-widget.tsx +0 -177
  21. package/src/components/dashboard/widgets/index.ts +0 -5
  22. package/src/components/dashboard/widgets/metric-card.tsx +0 -363
  23. package/src/components/dashboard/widgets/progress-widget.tsx +0 -113
  24. package/src/components/data-table/data-table-bulk-actions.tsx +0 -204
  25. package/src/components/data-table/data-table-column-toggle.tsx +0 -169
  26. package/src/components/data-table/data-table-export.ts +0 -156
  27. package/src/components/data-table/data-table-filter-drawer.tsx +0 -448
  28. package/src/components/data-table/index.tsx +0 -845
  29. package/src/components/draggable-list/index.tsx +0 -100
  30. package/src/components/error-boundary/index.tsx +0 -232
  31. package/src/components/file-upload/index.tsx +0 -1660
  32. package/src/components/floating-action-button/index.tsx +0 -206
  33. package/src/components/form-wizard/form-wizard-context.tsx +0 -335
  34. package/src/components/form-wizard/form-wizard-navigation.tsx +0 -118
  35. package/src/components/form-wizard/form-wizard-progress.tsx +0 -329
  36. package/src/components/form-wizard/form-wizard-step.tsx +0 -111
  37. package/src/components/form-wizard/index.tsx +0 -102
  38. package/src/components/form-wizard/types.ts +0 -77
  39. package/src/components/gesture-drawer/index.tsx +0 -551
  40. package/src/components/github-stars/github-api.ts +0 -426
  41. package/src/components/github-stars/hooks.ts +0 -517
  42. package/src/components/github-stars/index.tsx +0 -375
  43. package/src/components/github-stars/types.ts +0 -148
  44. package/src/components/github-stars/variants.tsx +0 -515
  45. package/src/components/health-check/index.tsx +0 -439
  46. package/src/components/hover-card-3d/index.tsx +0 -529
  47. package/src/components/index.ts +0 -130
  48. package/src/components/internal/index.ts +0 -78
  49. package/src/components/kanban/add-card-modal.tsx +0 -502
  50. package/src/components/kanban/card-detail-modal.tsx +0 -761
  51. package/src/components/kanban/index.ts +0 -13
  52. package/src/components/kanban/kanban.tsx +0 -1689
  53. package/src/components/kanban/types.ts +0 -168
  54. package/src/components/lazy-component/index.tsx +0 -823
  55. package/src/components/license-error/index.tsx +0 -31
  56. package/src/components/magnetic-button/index.tsx +0 -216
  57. package/src/components/memory-efficient-data/index.tsx +0 -1018
  58. package/src/components/moonui-quiz-form/index.tsx +0 -817
  59. package/src/components/navbar/index.tsx +0 -781
  60. package/src/components/optimized-image/index.tsx +0 -425
  61. package/src/components/performance-debugger/index.tsx +0 -613
  62. package/src/components/performance-monitor/index.tsx +0 -808
  63. package/src/components/phone-number-input/index.tsx +0 -343
  64. package/src/components/phone-number-input/phone-number-input-simple.tsx +0 -167
  65. package/src/components/pinch-zoom/index.tsx +0 -566
  66. package/src/components/quiz-form/index.tsx +0 -479
  67. package/src/components/rich-text-editor/index.tsx +0 -2322
  68. package/src/components/rich-text-editor/slash-commands-extension.ts +0 -230
  69. package/src/components/rich-text-editor/slash-commands.css +0 -35
  70. package/src/components/rich-text-editor/table-styles.css +0 -65
  71. package/src/components/sidebar/index.tsx +0 -884
  72. package/src/components/spotlight-card/index.tsx +0 -191
  73. package/src/components/swipeable-card/index.tsx +0 -100
  74. package/src/components/timeline/index.tsx +0 -1183
  75. package/src/components/ui/accordion.tsx +0 -581
  76. package/src/components/ui/alert-dialog.tsx +0 -141
  77. package/src/components/ui/alert.tsx +0 -141
  78. package/src/components/ui/aspect-ratio.tsx +0 -245
  79. package/src/components/ui/avatar.tsx +0 -155
  80. package/src/components/ui/badge.tsx +0 -230
  81. package/src/components/ui/breadcrumb.tsx +0 -216
  82. package/src/components/ui/button.tsx +0 -228
  83. package/src/components/ui/calendar.tsx +0 -387
  84. package/src/components/ui/card.tsx +0 -216
  85. package/src/components/ui/checkbox.tsx +0 -259
  86. package/src/components/ui/collapsible.tsx +0 -631
  87. package/src/components/ui/color-picker.tsx +0 -97
  88. package/src/components/ui/command.tsx +0 -948
  89. package/src/components/ui/dialog.tsx +0 -752
  90. package/src/components/ui/dropdown-menu.tsx +0 -706
  91. package/src/components/ui/gesture-drawer.tsx +0 -11
  92. package/src/components/ui/hover-card.tsx +0 -29
  93. package/src/components/ui/index.ts +0 -222
  94. package/src/components/ui/input.tsx +0 -224
  95. package/src/components/ui/label.tsx +0 -29
  96. package/src/components/ui/lightbox.tsx +0 -606
  97. package/src/components/ui/magnetic-button.tsx +0 -129
  98. package/src/components/ui/media-gallery.tsx +0 -611
  99. package/src/components/ui/navigation-menu.tsx +0 -130
  100. package/src/components/ui/pagination.tsx +0 -125
  101. package/src/components/ui/popover.tsx +0 -185
  102. package/src/components/ui/progress.tsx +0 -30
  103. package/src/components/ui/radio-group.tsx +0 -257
  104. package/src/components/ui/scroll-area.tsx +0 -47
  105. package/src/components/ui/select.tsx +0 -378
  106. package/src/components/ui/separator.tsx +0 -145
  107. package/src/components/ui/sheet.tsx +0 -139
  108. package/src/components/ui/skeleton.tsx +0 -20
  109. package/src/components/ui/slider.tsx +0 -354
  110. package/src/components/ui/spotlight-card.tsx +0 -119
  111. package/src/components/ui/switch.tsx +0 -86
  112. package/src/components/ui/table.tsx +0 -331
  113. package/src/components/ui/tabs-pro.tsx +0 -542
  114. package/src/components/ui/tabs.tsx +0 -54
  115. package/src/components/ui/textarea.tsx +0 -28
  116. package/src/components/ui/toast.tsx +0 -317
  117. package/src/components/ui/toggle.tsx +0 -119
  118. package/src/components/ui/tooltip.tsx +0 -151
  119. package/src/components/virtual-list/index.tsx +0 -668
  120. package/src/hooks/use-chart.ts +0 -205
  121. package/src/hooks/use-data-table.ts +0 -182
  122. package/src/hooks/use-docs-pro-access.ts +0 -13
  123. package/src/hooks/use-license-check.ts +0 -65
  124. package/src/hooks/use-subscription.ts +0 -19
  125. package/src/hooks/use-toast.ts +0 -15
  126. package/src/index.ts +0 -22
  127. package/src/lib/ai-providers.ts +0 -377
  128. package/src/lib/component-metadata.ts +0 -18
  129. package/src/lib/micro-interactions.ts +0 -255
  130. package/src/lib/paddle.ts +0 -17
  131. package/src/lib/utils.ts +0 -6
  132. package/src/patterns/login-form/index.tsx +0 -276
  133. package/src/patterns/login-form/types.ts +0 -67
  134. package/src/setupTests.ts +0 -41
  135. package/src/styles/advanced-chart.css +0 -239
  136. package/src/styles/calendar.css +0 -35
  137. package/src/styles/design-system.css +0 -363
  138. package/src/styles/index.css +0 -681
  139. package/src/styles/tailwind.css +0 -7
  140. package/src/styles/tokens.css +0 -455
  141. package/src/types/next-auth.d.ts +0 -21
  142. package/src/use-intersection-observer.tsx +0 -154
  143. package/src/use-local-storage.tsx +0 -71
  144. package/src/use-paddle.ts +0 -138
  145. package/src/use-performance-optimizer.ts +0 -389
  146. package/src/use-pro-access.ts +0 -141
  147. package/src/use-scroll-animation.ts +0 -219
  148. package/src/use-subscription.ts +0 -37
  149. package/src/use-toast.ts +0 -32
  150. package/src/utils/chart-helpers.ts +0 -357
  151. package/src/utils/cn.ts +0 -6
  152. package/src/utils/data-processing.ts +0 -151
  153. package/src/utils/license-validator.tsx +0 -183
@@ -1,1018 +0,0 @@
1
- "use client"
2
-
3
- import React, { useMemo, useCallback, useState, useEffect, useRef } from 'react'
4
- import { motion, AnimatePresence } from 'framer-motion'
5
- import { cn } from '../../lib/utils'
6
- import { Search, Filter, Download, SortAsc, SortDesc, BarChart3, Cpu, Clock, Zap } from 'lucide-react'
7
-
8
- // Type definitions for memory configuration
9
- interface MemoryConfig {
10
- chunkSize?: number
11
- maxMemoryItems?: number
12
- cacheStrategy?: 'lru' | 'fifo' | 'lfu'
13
- compression?: boolean
14
- autoCleanup?: boolean
15
- cleanupThreshold?: number
16
- streamingMode?: boolean
17
- enableAnalytics?: boolean
18
- analyticsCallback?: (stats: MemoryStats) => void
19
- // New features
20
- variableHeight?: boolean
21
- preloadStrategy?: 'none' | 'aggressive' | 'smart'
22
- performanceTracking?: boolean
23
- enableSearch?: boolean
24
- enableSort?: boolean
25
- enableFilter?: boolean
26
- enableExport?: boolean
27
- animations?: boolean
28
- }
29
-
30
- // Type definition for performance metrics
31
- interface MemoryPerformanceMetrics {
32
- fps: number
33
- renderTime: number
34
- memoryLeaks: number
35
- scrollPerformance: number
36
- lastUpdate: number
37
- }
38
-
39
- // Type definitions for Search/Sort/Filter
40
- interface TableFeatures<T> {
41
- searchTerm?: string
42
- sortConfig?: {
43
- key: keyof T
44
- direction: 'asc' | 'desc'
45
- }
46
- filters?: Array<{
47
- key: keyof T
48
- value: any
49
- operator: 'equals' | 'contains' | 'greaterThan' | 'lessThan'
50
- }>
51
- }
52
-
53
- // Type definition for height measurement
54
- interface ItemHeightInfo {
55
- index: number
56
- height: number
57
- offset: number
58
- }
59
-
60
- // Type definition for memory statistics
61
- interface MemoryStats {
62
- memoryUsage: number
63
- itemCount: number
64
- cacheHitRate: number
65
- compressionRatio?: number
66
- lastCleanup?: number
67
- performance?: MemoryPerformanceMetrics
68
- }
69
-
70
- // Main component props
71
- export interface MemoryEfficientDataProps<T = any> {
72
- data: T[]
73
- config?: MemoryConfig
74
- renderItem: (item: T, index: number) => React.ReactNode
75
- height?: number
76
- onMemoryUpdate?: (stats: MemoryStats) => void
77
- className?: string
78
- // New features
79
- itemHeight?: number | ((item: T, index: number) => number)
80
- onSearch?: (searchTerm: string) => T[]
81
- onSort?: (data: T[], key: keyof T, direction: 'asc' | 'desc') => T[]
82
- onFilter?: (data: T[], filters: TableFeatures<T>['filters']) => T[]
83
- onExport?: (data: T[], format: 'csv' | 'json' | 'xlsx') => void
84
- searchPlaceholder?: string
85
- emptyStateMessage?: string
86
- loadingComponent?: React.ReactNode
87
- errorComponent?: React.ReactNode
88
- }
89
-
90
- // Cache node yapısı
91
- interface CacheNode<T> {
92
- data: T[]
93
- timestamp: number
94
- accessCount: number
95
- compressed?: boolean
96
- }
97
-
98
- // Memory cache sınıfı
99
- class MemoryCache<T> {
100
- private cache = new Map<string, CacheNode<T>>()
101
- private maxSize: number
102
- private strategy: 'lru' | 'fifo' | 'lfu'
103
-
104
- constructor(maxSize: number, strategy: 'lru' | 'fifo' | 'lfu' = 'lru') {
105
- this.maxSize = maxSize
106
- this.strategy = strategy
107
- }
108
-
109
- set(key: string, data: T[], compressed = false): void {
110
- if (this.cache.size >= this.maxSize) {
111
- this.evict()
112
- }
113
-
114
- this.cache.set(key, {
115
- data,
116
- timestamp: Date.now(),
117
- accessCount: 0,
118
- compressed
119
- })
120
- }
121
-
122
-
123
- private evict(): void {
124
- if (this.cache.size === 0) return
125
-
126
- let keyToDelete: string | null = null
127
-
128
- switch (this.strategy) {
129
- case 'lru':
130
- // Delete least recently used
131
- let oldestTime = Infinity
132
- for (const [key, node] of this.cache) {
133
- if (node.timestamp < oldestTime) {
134
- oldestTime = node.timestamp
135
- keyToDelete = key
136
- }
137
- }
138
- break
139
-
140
- case 'lfu':
141
- // Delete least frequently used
142
- let minAccess = Infinity
143
- for (const [key, node] of this.cache) {
144
- if (node.accessCount < minAccess) {
145
- minAccess = node.accessCount
146
- keyToDelete = key
147
- }
148
- }
149
- break
150
-
151
- case 'fifo':
152
- // Delete first in
153
- keyToDelete = this.cache.keys().next().value || null
154
- break
155
- }
156
-
157
- if (keyToDelete) {
158
- this.cache.delete(keyToDelete)
159
- }
160
- }
161
-
162
- clear(): void {
163
- this.cache.clear()
164
- }
165
-
166
- getStats(): { size: number; hitRate: number; memoryUsage: number } {
167
- let totalMemory = 0
168
- for (const [, node] of this.cache) {
169
- totalMemory += JSON.stringify(node.data).length * 2 // Rough memory calculation
170
- }
171
-
172
- return {
173
- size: this.cache.size,
174
- hitRate: this.calculateHitRate(),
175
- memoryUsage: totalMemory
176
- }
177
- }
178
-
179
- private hitCount = 0
180
- private missCount = 0
181
-
182
- private calculateHitRate(): number {
183
- const total = this.hitCount + this.missCount
184
- return total === 0 ? 0 : this.hitCount / total
185
- }
186
-
187
- // Update for hit/miss tracking
188
- get(key: string): T[] | null {
189
- const node = this.cache.get(key)
190
- if (!node) {
191
- this.missCount++
192
- return null
193
- }
194
-
195
- this.hitCount++
196
- node.accessCount++
197
- node.timestamp = Date.now()
198
- return node.data
199
- }
200
- }
201
-
202
- // Performance Tracker sınıfı
203
- class PerformanceTracker {
204
- private frames: number[] = []
205
- private renderTimes: number[] = []
206
- private startTime = 0
207
- private lastFrameTime = 0
208
-
209
- startRender(): void {
210
- this.startTime = performance.now()
211
- }
212
-
213
- endRender(): void {
214
- const renderTime = performance.now() - this.startTime
215
- this.renderTimes.push(renderTime)
216
-
217
- // Keep last 60 render times
218
- if (this.renderTimes.length > 60) {
219
- this.renderTimes.shift()
220
- }
221
- }
222
-
223
- recordFrame(): void {
224
- const now = performance.now()
225
- if (this.lastFrameTime > 0) {
226
- const fps = 1000 / (now - this.lastFrameTime)
227
- this.frames.push(fps)
228
-
229
- // Keep last 60 frames
230
- if (this.frames.length > 60) {
231
- this.frames.shift()
232
- }
233
- }
234
- this.lastFrameTime = now
235
- }
236
-
237
- getMetrics(): MemoryPerformanceMetrics {
238
- const avgFPS = this.frames.length > 0
239
- ? this.frames.reduce((a, b) => a + b, 0) / this.frames.length
240
- : 0
241
-
242
- const avgRenderTime = this.renderTimes.length > 0
243
- ? this.renderTimes.reduce((a, b) => a + b, 0) / this.renderTimes.length
244
- : 0
245
-
246
- return {
247
- fps: Math.round(avgFPS),
248
- renderTime: Math.round(avgRenderTime * 100) / 100,
249
- memoryLeaks: this.detectMemoryLeaks(),
250
- scrollPerformance: this.calculateScrollPerformance(),
251
- lastUpdate: Date.now()
252
- }
253
- }
254
-
255
- private detectMemoryLeaks(): number {
256
- // Simple memory leak detection
257
- return this.renderTimes.filter(time => time > 16).length // 16ms = 60fps threshold
258
- }
259
-
260
- private calculateScrollPerformance(): number {
261
- // Calculate scroll performance (0-100 score)
262
- const avgFPS = this.frames.length > 0
263
- ? this.frames.reduce((a, b) => a + b, 0) / this.frames.length
264
- : 60
265
-
266
- return Math.min(100, Math.max(0, (avgFPS / 60) * 100))
267
- }
268
- }
269
-
270
- // Variable Height Manager sınıfı
271
- class VariableHeightManager {
272
- private heights = new Map<number, number>()
273
- private defaultHeight: number
274
- private totalHeight = 0
275
- private measuredCount = 0
276
-
277
- constructor(defaultHeight = 60) {
278
- this.defaultHeight = defaultHeight
279
- }
280
-
281
- setItemHeight(index: number, height: number): void {
282
- const oldHeight = this.heights.get(index) || this.defaultHeight
283
- this.heights.set(index, height)
284
-
285
- if (!this.heights.has(index)) {
286
- this.measuredCount++
287
- }
288
-
289
- this.totalHeight += height - oldHeight
290
- }
291
-
292
- getItemHeight(index: number): number {
293
- return this.heights.get(index) || this.defaultHeight
294
- }
295
-
296
- getOffsetForIndex(index: number): number {
297
- let offset = 0
298
- for (let i = 0; i < index; i++) {
299
- offset += this.getItemHeight(i)
300
- }
301
- return offset
302
- }
303
-
304
- getTotalHeight(itemCount: number): number {
305
- if (this.measuredCount === 0) {
306
- return itemCount * this.defaultHeight
307
- }
308
-
309
- const measuredHeight = Array.from(this.heights.values())
310
- .reduce((sum, height) => sum + height, 0)
311
- const averageHeight = measuredHeight / this.measuredCount
312
- const unmeasuredCount = itemCount - this.measuredCount
313
-
314
- return measuredHeight + (unmeasuredCount * averageHeight)
315
- }
316
-
317
- getVisibleRange(scrollTop: number, containerHeight: number, itemCount: number): { start: number; end: number } {
318
- let start = 0
319
- let currentOffset = 0
320
-
321
- // Count items up to scroll position
322
- while (start < itemCount && currentOffset < scrollTop) {
323
- currentOffset += this.getItemHeight(start)
324
- start++
325
- }
326
-
327
- start = Math.max(0, start - 1)
328
-
329
- // Continue through visible area
330
- let end = start
331
- const targetOffset = scrollTop + containerHeight
332
- currentOffset = this.getOffsetForIndex(start)
333
-
334
- while (end < itemCount && currentOffset < targetOffset) {
335
- currentOffset += this.getItemHeight(end)
336
- end++
337
- }
338
-
339
- return { start, end: Math.min(itemCount, end + 1) }
340
- }
341
- }
342
-
343
- // Main Memory Efficient Data Component
344
- function MemoryEfficientData<T = any>({
345
- data,
346
- config = {},
347
- renderItem,
348
- height = 400,
349
- onMemoryUpdate,
350
- className,
351
- // New props
352
- itemHeight = 60,
353
- onSearch,
354
- onSort,
355
- onFilter,
356
- onExport,
357
- searchPlaceholder = "Search...",
358
- emptyStateMessage = "No data found",
359
- loadingComponent,
360
- errorComponent
361
- }: MemoryEfficientDataProps<T>) {
362
- const {
363
- chunkSize = 1000,
364
- maxMemoryItems = 10000,
365
- cacheStrategy = 'lru',
366
- compression = false,
367
- autoCleanup = true,
368
- cleanupThreshold = 0.8,
369
- streamingMode = false,
370
- enableAnalytics = false,
371
- analyticsCallback,
372
- // New configurations
373
- variableHeight = false,
374
- preloadStrategy = 'smart',
375
- performanceTracking = false,
376
- enableSearch = false,
377
- enableSort = false,
378
- enableFilter = false,
379
- enableExport = false,
380
- animations = true
381
- } = config
382
-
383
- // State management
384
- const [visibleRange, setVisibleRange] = useState({ start: 0, end: Math.min(chunkSize, data.length) })
385
- const [memoryStats, setMemoryStats] = useState<MemoryStats>({
386
- memoryUsage: 0,
387
- itemCount: 0,
388
- cacheHitRate: 0.95
389
- })
390
- const [tableFeatures, setTableFeatures] = useState<TableFeatures<T>>({
391
- searchTerm: '',
392
- sortConfig: undefined,
393
- filters: []
394
- })
395
-
396
- // Refs
397
- const containerRef = useRef<HTMLDivElement>(null)
398
- const cacheRef = useRef(new MemoryCache<T>(Math.floor(maxMemoryItems / chunkSize), cacheStrategy))
399
- const scrollTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined)
400
- const performanceTrackerRef = useRef(new PerformanceTracker())
401
- const heightManagerRef = useRef(new VariableHeightManager(typeof itemHeight === 'number' ? itemHeight : 60))
402
- const itemRefs = useRef<Map<number, HTMLDivElement>>(new Map())
403
-
404
- // Calculate processed data (search, sort, filter)
405
- const processedData = useMemo(() => {
406
- let result = [...data]
407
-
408
- try {
409
- // Search functionality
410
- if (enableSearch && tableFeatures.searchTerm && onSearch) {
411
- result = onSearch(tableFeatures.searchTerm)
412
- }
413
-
414
- // Filter functionality
415
- if (enableFilter && tableFeatures.filters && tableFeatures.filters.length > 0 && onFilter) {
416
- result = onFilter(result, tableFeatures.filters)
417
- }
418
-
419
- // Sort functionality
420
- if (enableSort && tableFeatures.sortConfig && onSort) {
421
- result = onSort(result, tableFeatures.sortConfig.key, tableFeatures.sortConfig.direction)
422
- }
423
-
424
- return result
425
- } catch (err) {
426
- console.error('Error processing data:', err)
427
- return data
428
- }
429
- }, [data, tableFeatures, enableSearch, enableFilter, enableSort, onSearch, onFilter, onSort])
430
-
431
- // Memoize visible data
432
- const visibleData = useMemo(() => {
433
- if (performanceTracking) {
434
- performanceTrackerRef.current.startRender()
435
- }
436
-
437
- const start = visibleRange.start
438
- const end = Math.min(visibleRange.end, processedData.length)
439
-
440
- // Check from cache
441
- const cacheKey = `${start}-${end}-${JSON.stringify(tableFeatures)}`
442
- const cachedData = cacheRef.current.get(cacheKey)
443
-
444
- if (cachedData && cachedData.length === (end - start)) {
445
- if (performanceTracking) {
446
- performanceTrackerRef.current.endRender()
447
- }
448
- return cachedData
449
- }
450
-
451
- // Create new data slice
452
- const newData = processedData.slice(start, end)
453
-
454
- // Save to cache
455
- cacheRef.current.set(cacheKey, newData, compression)
456
-
457
- if (performanceTracking) {
458
- performanceTrackerRef.current.endRender()
459
- }
460
-
461
- return newData
462
- }, [processedData, visibleRange, compression, tableFeatures, performanceTracking])
463
-
464
- // Item height measurement
465
- const measureItemHeight = useCallback((index: number, element: HTMLDivElement) => {
466
- if (!variableHeight) return
467
-
468
- const height = element.getBoundingClientRect().height
469
- heightManagerRef.current.setItemHeight(index, height)
470
-
471
- // Force re-render if height changed significantly
472
- const oldHeight = heightManagerRef.current.getItemHeight(index)
473
- if (Math.abs(height - oldHeight) > 5) {
474
- // Recalculate visible range
475
- const container = containerRef.current
476
- if (container) {
477
- handleScroll({ currentTarget: container } as React.UIEvent<HTMLDivElement>)
478
- }
479
- }
480
- }, [variableHeight])
481
-
482
- // Scroll handler
483
- const handleScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {
484
- if (performanceTracking) {
485
- performanceTrackerRef.current.recordFrame()
486
- }
487
-
488
- const scrollTop = e.currentTarget.scrollTop
489
- const containerHeight = e.currentTarget.clientHeight
490
-
491
- let newStart: number, newEnd: number
492
-
493
- if (variableHeight) {
494
- // Use variable height
495
- const range = heightManagerRef.current.getVisibleRange(scrollTop, containerHeight, processedData.length)
496
- newStart = range.start
497
- newEnd = range.end
498
- } else {
499
- // Use fixed height
500
- const itemHeightValue = typeof itemHeight === 'number' ? itemHeight : 60
501
- const startIndex = Math.floor(scrollTop / itemHeightValue)
502
- const visibleCount = Math.ceil(containerHeight / itemHeightValue)
503
-
504
- // Add buffer
505
- const bufferSize = Math.floor(visibleCount * 0.5)
506
- newStart = Math.max(0, startIndex - bufferSize)
507
- newEnd = Math.min(processedData.length, startIndex + visibleCount + bufferSize)
508
- }
509
-
510
- // Preloading strategy
511
- if (preloadStrategy === 'aggressive') {
512
- const extraBuffer = Math.floor((newEnd - newStart) * 0.5)
513
- newStart = Math.max(0, newStart - extraBuffer)
514
- newEnd = Math.min(processedData.length, newEnd + extraBuffer)
515
- } else if (preloadStrategy === 'smart') {
516
- // Preload based on scroll direction
517
- const currentScroll = scrollTop
518
- const lastScroll = scrollTimeoutRef.current ? parseInt(scrollTimeoutRef.current as any) : 0
519
- const isScrollingDown = currentScroll > lastScroll
520
-
521
- if (isScrollingDown) {
522
- newEnd = Math.min(processedData.length, newEnd + Math.floor((newEnd - newStart) * 0.2))
523
- } else {
524
- newStart = Math.max(0, newStart - Math.floor((newEnd - newStart) * 0.2))
525
- }
526
- }
527
-
528
- // Throttle scroll updates
529
- if (scrollTimeoutRef.current) {
530
- clearTimeout(scrollTimeoutRef.current)
531
- }
532
-
533
- scrollTimeoutRef.current = setTimeout(() => {
534
- setVisibleRange({ start: newStart, end: newEnd })
535
- }, 16) // ~60fps
536
- }, [processedData.length, variableHeight, itemHeight, preloadStrategy, performanceTracking])
537
-
538
- // Search handler
539
- const handleSearch = useCallback((searchTerm: string) => {
540
- setTableFeatures(prev => ({ ...prev, searchTerm }))
541
- }, [])
542
-
543
- // Export handler
544
- const handleExport = useCallback((format: 'csv' | 'json' | 'xlsx') => {
545
- if (onExport) {
546
- onExport(processedData, format)
547
- }
548
- }, [processedData, onExport])
549
-
550
- // Update memory statistics - debounced to prevent excessive updates
551
- useEffect(() => {
552
- if (!enableAnalytics && !onMemoryUpdate) return
553
-
554
- const updateStats = () => {
555
- const cacheStats = cacheRef.current.getStats()
556
- const performanceMetrics = performanceTracking ? performanceTrackerRef.current.getMetrics() : undefined
557
-
558
- const newStats: MemoryStats = {
559
- memoryUsage: cacheStats.memoryUsage,
560
- itemCount: visibleData.length,
561
- cacheHitRate: cacheStats.hitRate,
562
- compressionRatio: compression ? 0.7 : 1.0,
563
- lastCleanup: Date.now(),
564
- performance: performanceMetrics
565
- }
566
-
567
- setMemoryStats(newStats)
568
-
569
- if (enableAnalytics && analyticsCallback) {
570
- analyticsCallback(newStats)
571
- }
572
-
573
- if (onMemoryUpdate) {
574
- onMemoryUpdate(newStats)
575
- }
576
- }
577
-
578
- // Debounce updates to prevent loops
579
- const timeoutId = setTimeout(updateStats, 500)
580
-
581
- return () => clearTimeout(timeoutId)
582
- }, [visibleData.length, enableAnalytics, performanceTracking, compression]) // Remove callbacks from deps
583
-
584
- // Auto cleanup effect
585
- useEffect(() => {
586
- if (!autoCleanup) return
587
-
588
- const cleanupInterval = setInterval(() => {
589
- const memoryUsage = (visibleData.length / maxMemoryItems)
590
- if (memoryUsage > cleanupThreshold) {
591
- // Simple cleanup - clear cache
592
- cacheRef.current.clear()
593
- }
594
- }, 5000) // Check every 5 seconds
595
-
596
- return () => clearInterval(cleanupInterval)
597
- }, [autoCleanup, cleanupThreshold, maxMemoryItems, visibleData.length])
598
-
599
- // Render for loading and error states
600
- if (loadingComponent && data.length === 0) {
601
- return <>{loadingComponent}</>
602
- }
603
-
604
- // Calculate total height
605
- const totalHeight = variableHeight
606
- ? heightManagerRef.current.getTotalHeight(processedData.length)
607
- : processedData.length * (typeof itemHeight === 'number' ? itemHeight : 60)
608
-
609
- // Calculate offset
610
- const offsetY = variableHeight
611
- ? heightManagerRef.current.getOffsetForIndex(visibleRange.start)
612
- : visibleRange.start * (typeof itemHeight === 'number' ? itemHeight : 60)
613
-
614
- return (
615
- <div className={cn("flex flex-col", className)}>
616
- {/* Control Bar */}
617
- {(enableSearch || enableSort || enableFilter || enableExport) && (
618
- <motion.div
619
- className="flex items-center gap-2 p-3 border-b bg-muted/5"
620
- initial={animations ? { opacity: 0, y: -10 } : {}}
621
- animate={animations ? { opacity: 1, y: 0 } : {}}
622
- transition={{ duration: 0.2 }}
623
- >
624
- {enableSearch && (
625
- <div className="relative flex-1 max-w-sm">
626
- <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
627
- <input
628
- type="text"
629
- placeholder={searchPlaceholder}
630
- value={tableFeatures.searchTerm}
631
- onChange={(e) => handleSearch(e.target.value)}
632
- className="w-full pl-10 pr-4 py-2 border rounded-md bg-background text-sm focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary"
633
- />
634
- </div>
635
- )}
636
-
637
- <div className="flex items-center gap-1">
638
- {enableFilter && (
639
- <button
640
- onClick={() => {/* Filter modal will open */}}
641
- className="p-2 hover:bg-muted rounded-md transition-colors"
642
- title="Filter"
643
- >
644
- <Filter className="h-4 w-4" />
645
- </button>
646
- )}
647
-
648
- {enableExport && (
649
- <div className="relative">
650
- <button
651
- onClick={() => handleExport('csv')}
652
- className="p-2 hover:bg-muted rounded-md transition-colors"
653
- title="Export"
654
- >
655
- <Download className="h-4 w-4" />
656
- </button>
657
- </div>
658
- )}
659
- </div>
660
- </motion.div>
661
- )}
662
-
663
- {/* Data Container */}
664
- <div
665
- ref={containerRef}
666
- className="overflow-auto border rounded-lg bg-background"
667
- style={{ height: typeof height === 'number' ? height - (enableSearch || enableSort || enableFilter || enableExport ? 60 : 0) : height }}
668
- onScroll={handleScroll}
669
- >
670
- {processedData.length === 0 ? (
671
- <motion.div
672
- className="flex items-center justify-center h-full text-muted-foreground"
673
- initial={animations ? { opacity: 0 } : {}}
674
- animate={animations ? { opacity: 1 } : {}}
675
- >
676
- {emptyStateMessage}
677
- </motion.div>
678
- ) : (
679
- <div style={{ height: totalHeight, position: 'relative' }}>
680
- <motion.div
681
- style={{
682
- transform: `translateY(${offsetY}px)`,
683
- position: 'absolute',
684
- width: '100%'
685
- }}
686
- animate={animations ? { y: offsetY } : {}}
687
- transition={animations ? { duration: 0.1, ease: "linear" } : {}}
688
- >
689
- <AnimatePresence mode="popLayout">
690
- {visibleData.map((item, index) => {
691
- const globalIndex = visibleRange.start + index
692
- const itemHeightValue = typeof itemHeight === 'function'
693
- ? itemHeight(item, globalIndex)
694
- : (typeof itemHeight === 'number' ? itemHeight : 60)
695
-
696
- return (
697
- <motion.div
698
- key={globalIndex}
699
- ref={(el) => {
700
- if (el && variableHeight) {
701
- itemRefs.current.set(globalIndex, el)
702
- measureItemHeight(globalIndex, el)
703
- }
704
- }}
705
- style={variableHeight ? {} : { height: itemHeightValue }}
706
- initial={animations ? { opacity: 0, y: 20 } : {}}
707
- animate={animations ? { opacity: 1, y: 0 } : {}}
708
- exit={animations ? { opacity: 0, y: -20 } : {}}
709
- transition={animations ? { duration: 0.2 } : {}}
710
- layout={animations}
711
- >
712
- {renderItem(item, globalIndex)}
713
- </motion.div>
714
- )
715
- })}
716
- </AnimatePresence>
717
- </motion.div>
718
- </div>
719
- )}
720
- </div>
721
-
722
- {/* Performance Monitor */}
723
- {performanceTracking && memoryStats.performance && (
724
- <div className="p-2 border-t bg-muted/5 text-xs text-muted-foreground flex items-center gap-4">
725
- <div className="flex items-center gap-1">
726
- <Zap className="h-3 w-3" />
727
- <span>FPS: {memoryStats.performance.fps}</span>
728
- </div>
729
- <div className="flex items-center gap-1">
730
- <Clock className="h-3 w-3" />
731
- <span>Render: {memoryStats.performance.renderTime}ms</span>
732
- </div>
733
- <div className="flex items-center gap-1">
734
- <Cpu className="h-3 w-3" />
735
- <span>Scroll: {memoryStats.performance.scrollPerformance}%</span>
736
- </div>
737
- <div className="flex items-center gap-1">
738
- <BarChart3 className="h-3 w-3" />
739
- <span>Cache: {Math.round(memoryStats.cacheHitRate * 100)}%</span>
740
- </div>
741
- </div>
742
- )}
743
- </div>
744
- )
745
- }
746
-
747
- // Real-time Performance Monitor Component
748
- interface RealTimePerformanceMonitorProps {
749
- memoryStats?: MemoryStats
750
- className?: string
751
- showChart?: boolean
752
- updateInterval?: number
753
- }
754
-
755
- function RealTimePerformanceMonitor({
756
- memoryStats,
757
- className,
758
- showChart = false
759
- }: RealTimePerformanceMonitorProps) {
760
- const [history, setHistory] = useState<MemoryStats[]>([])
761
- const [isActive, setIsActive] = useState(true)
762
-
763
- useEffect(() => {
764
- if (!memoryStats || !isActive) return
765
-
766
- setHistory(prev => {
767
- const newHistory = [...prev, memoryStats]
768
- // Keep last 60 entries (1 minute)
769
- return newHistory.length > 60 ? newHistory.slice(-60) : newHistory
770
- })
771
- }, [memoryStats, isActive])
772
-
773
- const formatBytes = (bytes: number) => {
774
- if (bytes === 0) return '0 Bytes'
775
- const k = 1024
776
- const sizes = ['Bytes', 'KB', 'MB', 'GB']
777
- const i = Math.floor(Math.log(bytes) / Math.log(k))
778
- return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
779
- }
780
-
781
- const getPerformanceColor = (value: number, threshold: { good: number; warning: number }) => {
782
- if (value >= threshold.good) return 'text-green-500'
783
- if (value >= threshold.warning) return 'text-yellow-500'
784
- return 'text-red-500'
785
- }
786
-
787
- if (!memoryStats) {
788
- return (
789
- <div className={cn("p-4 border rounded-lg bg-muted/5", className)}>
790
- <div className="text-center text-muted-foreground">
791
- Performance monitoring disabled
792
- </div>
793
- </div>
794
- )
795
- }
796
-
797
- return (
798
- <motion.div
799
- className={cn("p-4 border rounded-lg bg-background space-y-4", className)}
800
- initial={{ opacity: 0, y: 20 }}
801
- animate={{ opacity: 1, y: 0 }}
802
- transition={{ duration: 0.3 }}
803
- >
804
- <div className="flex items-center justify-between">
805
- <h3 className="font-semibold flex items-center gap-2">
806
- <BarChart3 className="h-4 w-4" />
807
- Real-time Performance
808
- </h3>
809
- <button
810
- onClick={() => setIsActive(!isActive)}
811
- className={cn(
812
- "px-3 py-1 text-xs rounded-md transition-colors",
813
- isActive
814
- ? "bg-green-500/10 text-green-500 hover:bg-green-500/20"
815
- : "bg-muted text-muted-foreground hover:bg-muted/80"
816
- )}
817
- >
818
- {isActive ? 'Active' : 'Paused'}
819
- </button>
820
- </div>
821
-
822
- <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
823
- {/* FPS */}
824
- <div className="space-y-1">
825
- <div className="text-xs text-muted-foreground">FPS</div>
826
- <div className={cn(
827
- "text-lg font-mono font-bold",
828
- memoryStats.performance ? getPerformanceColor(memoryStats.performance.fps, { good: 55, warning: 30 }) : ''
829
- )}>
830
- {memoryStats.performance?.fps || 0}
831
- </div>
832
- </div>
833
-
834
- {/* Render Time */}
835
- <div className="space-y-1">
836
- <div className="text-xs text-muted-foreground">Render Time</div>
837
- <div className={cn(
838
- "text-lg font-mono font-bold",
839
- memoryStats.performance ? getPerformanceColor(100 - memoryStats.performance.renderTime, { good: 84, warning: 70 }) : ''
840
- )}>
841
- {memoryStats.performance?.renderTime.toFixed(2) || 0}ms
842
- </div>
843
- </div>
844
-
845
- {/* Memory Usage */}
846
- <div className="space-y-1">
847
- <div className="text-xs text-muted-foreground">Memory Usage</div>
848
- <div className="text-lg font-mono font-bold">
849
- {formatBytes(memoryStats.memoryUsage)}
850
- </div>
851
- </div>
852
-
853
- {/* Cache Hit Rate */}
854
- <div className="space-y-1">
855
- <div className="text-xs text-muted-foreground">Cache Hit Rate</div>
856
- <div className={cn(
857
- "text-lg font-mono font-bold",
858
- getPerformanceColor(memoryStats.cacheHitRate * 100, { good: 85, warning: 70 })
859
- )}>
860
- {Math.round(memoryStats.cacheHitRate * 100)}%
861
- </div>
862
- </div>
863
- </div>
864
-
865
- {/* Memory Leaks & Scroll Performance */}
866
- {memoryStats.performance && (
867
- <div className="grid grid-cols-2 gap-4 pt-2 border-t">
868
- <div className="space-y-1">
869
- <div className="text-xs text-muted-foreground">Memory Leaks</div>
870
- <div className={cn(
871
- "text-sm font-mono",
872
- memoryStats.performance.memoryLeaks > 5 ? 'text-red-500' : 'text-green-500'
873
- )}>
874
- {memoryStats.performance.memoryLeaks} detection
875
- </div>
876
- </div>
877
- <div className="space-y-1">
878
- <div className="text-xs text-muted-foreground">Scroll Performance</div>
879
- <div className={cn(
880
- "text-sm font-mono",
881
- getPerformanceColor(memoryStats.performance.scrollPerformance, { good: 85, warning: 70 })
882
- )}>
883
- {memoryStats.performance.scrollPerformance}%
884
- </div>
885
- </div>
886
- </div>
887
- )}
888
-
889
- {/* Mini Chart */}
890
- {showChart && history.length > 1 && (
891
- <div className="pt-2 border-t">
892
- <div className="text-xs text-muted-foreground mb-2">FPS History (Last 60 updates)</div>
893
- <div className="h-16 flex items-end gap-1">
894
- {history.slice(-30).map((stat, index) => {
895
- const fps = stat.performance?.fps || 0
896
- const height = Math.max(4, (fps / 60) * 100)
897
- const color = fps >= 55 ? 'bg-green-500' : fps >= 30 ? 'bg-yellow-500' : 'bg-red-500'
898
-
899
- return (
900
- <motion.div
901
- key={index}
902
- className={cn("w-1 rounded-t-sm", color)}
903
- style={{ height: `${height}%` }}
904
- initial={{ height: 0 }}
905
- animate={{ height: `${height}%` }}
906
- transition={{ duration: 0.2 }}
907
- />
908
- )
909
- })}
910
- </div>
911
- </div>
912
- )}
913
- </motion.div>
914
- )
915
- }
916
-
917
- // Memory Analytics Component (Backward compatibility)
918
- interface MemoryAnalyticsProps {
919
- onStatsUpdate?: (stats: MemoryStats) => void
920
- showRealTime?: boolean
921
- className?: string
922
- }
923
-
924
- function MemoryAnalytics({
925
- onStatsUpdate,
926
- showRealTime = false,
927
- className
928
- }: MemoryAnalyticsProps) {
929
- const [stats, setStats] = useState<MemoryStats>({
930
- memoryUsage: 0,
931
- itemCount: 0,
932
- cacheHitRate: 0.95
933
- })
934
-
935
- // Simulate real-time updates with realistic data
936
- useEffect(() => {
937
- if (!showRealTime) return
938
-
939
- // Initialize with some realistic base values
940
- let baseMemory = 10 * 1024 * 1024 // 10MB base
941
- let currentFPS = 60
942
- let currentRenderTime = 5
943
-
944
- const interval = setInterval(() => {
945
- // Simulate realistic memory usage growth
946
- baseMemory += Math.random() * 1024 * 1024 - 500 * 1024 // Fluctuate around base
947
-
948
- // Simulate FPS variations
949
- currentFPS = Math.min(60, Math.max(30, currentFPS + (Math.random() - 0.5) * 10))
950
-
951
- // Simulate render time variations
952
- currentRenderTime = Math.max(1, Math.min(16, currentRenderTime + (Math.random() - 0.5) * 2))
953
-
954
- const newStats: MemoryStats = {
955
- memoryUsage: Math.max(0, baseMemory),
956
- itemCount: 50000, // Fixed item count for demo
957
- cacheHitRate: 0.85 + Math.random() * 0.15, // 85-100% hit rate
958
- lastCleanup: Date.now(),
959
- performance: {
960
- fps: Math.round(currentFPS),
961
- renderTime: parseFloat(currentRenderTime.toFixed(2)),
962
- memoryLeaks: currentRenderTime > 10 ? Math.floor(currentRenderTime / 5) : 0,
963
- scrollPerformance: Math.round((currentFPS / 60) * 100),
964
- lastUpdate: Date.now()
965
- } as MemoryPerformanceMetrics
966
- }
967
-
968
- setStats(newStats)
969
- if (onStatsUpdate) {
970
- onStatsUpdate(newStats)
971
- }
972
- }, 1000)
973
-
974
- return () => clearInterval(interval)
975
- }, [showRealTime, onStatsUpdate])
976
-
977
- return <RealTimePerformanceMonitor memoryStats={stats} className={className} showChart={showRealTime} />
978
- }
979
-
980
- // Utility hook for streaming data
981
- function useStreamingData<T>(
982
- initialData: T[] = [],
983
- streamingConfig?: { maxItems?: number }
984
- ) {
985
- const [data, setData] = useState<T[]>(initialData)
986
- const { maxItems = 10000 } = streamingConfig || {}
987
-
988
- const addItem = useCallback((newItem: T) => {
989
- setData(prev => {
990
- const newData = [...prev, newItem]
991
- return newData.length > maxItems ? newData.slice(-maxItems) : newData
992
- })
993
- }, [maxItems])
994
-
995
- const clearData = useCallback(() => {
996
- setData([])
997
- }, [])
998
-
999
- return { data, addItem, clearData }
1000
- }
1001
-
1002
- // Export components and types
1003
- export {
1004
- MemoryEfficientData,
1005
- MemoryAnalytics,
1006
- RealTimePerformanceMonitor,
1007
- useStreamingData
1008
- };
1009
-
1010
- export type {
1011
- MemoryConfig,
1012
- MemoryStats,
1013
- MemoryAnalyticsProps,
1014
- MemoryPerformanceMetrics,
1015
- TableFeatures,
1016
- ItemHeightInfo,
1017
- RealTimePerformanceMonitorProps
1018
- };