@moontra/moonui-pro 2.20.1 → 2.20.3

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 (162) hide show
  1. package/dist/index.d.ts +691 -261
  2. package/dist/index.mjs +7418 -4934
  3. package/package.json +11 -5
  4. package/plugin/index.d.ts +86 -0
  5. package/plugin/index.js +308 -0
  6. package/scripts/postbuild.js +27 -0
  7. package/scripts/postinstall.js +176 -23
  8. package/src/__tests__/use-intersection-observer.test.tsx +0 -216
  9. package/src/__tests__/use-local-storage.test.tsx +0 -174
  10. package/src/__tests__/use-pro-access.test.tsx +0 -183
  11. package/src/components/advanced-chart/advanced-chart.test.tsx +0 -281
  12. package/src/components/advanced-chart/index.tsx +0 -1242
  13. package/src/components/advanced-forms/index.tsx +0 -426
  14. package/src/components/animated-button/index.tsx +0 -385
  15. package/src/components/calendar/event-dialog.tsx +0 -372
  16. package/src/components/calendar/index.tsx +0 -1073
  17. package/src/components/calendar-pro/index.tsx +0 -1697
  18. package/src/components/color-picker/index.tsx +0 -432
  19. package/src/components/credit-card-input/index.tsx +0 -406
  20. package/src/components/dashboard/dashboard-grid.tsx +0 -462
  21. package/src/components/dashboard/demo.tsx +0 -425
  22. package/src/components/dashboard/index.tsx +0 -1046
  23. package/src/components/dashboard/time-range-picker.tsx +0 -336
  24. package/src/components/dashboard/types.ts +0 -222
  25. package/src/components/dashboard/widgets/activity-feed.tsx +0 -344
  26. package/src/components/dashboard/widgets/chart-widget.tsx +0 -418
  27. package/src/components/dashboard/widgets/metric-card.tsx +0 -343
  28. package/src/components/data-table/data-table-bulk-actions.tsx +0 -204
  29. package/src/components/data-table/data-table-column-toggle.tsx +0 -169
  30. package/src/components/data-table/data-table-export.ts +0 -156
  31. package/src/components/data-table/data-table-filter-drawer.tsx +0 -448
  32. package/src/components/data-table/data-table.test.tsx +0 -187
  33. package/src/components/data-table/index.tsx +0 -845
  34. package/src/components/draggable-list/index.tsx +0 -100
  35. package/src/components/enhanced/badge.tsx +0 -191
  36. package/src/components/enhanced/button.tsx +0 -362
  37. package/src/components/enhanced/card.tsx +0 -266
  38. package/src/components/enhanced/dialog.tsx +0 -246
  39. package/src/components/enhanced/index.ts +0 -4
  40. package/src/components/error-boundary/index.tsx +0 -109
  41. package/src/components/file-upload/file-upload.test.tsx +0 -243
  42. package/src/components/file-upload/index.tsx +0 -1660
  43. package/src/components/floating-action-button/index.tsx +0 -206
  44. package/src/components/form-wizard/form-wizard-context.tsx +0 -307
  45. package/src/components/form-wizard/form-wizard-navigation.tsx +0 -118
  46. package/src/components/form-wizard/form-wizard-progress.tsx +0 -298
  47. package/src/components/form-wizard/form-wizard-step.tsx +0 -111
  48. package/src/components/form-wizard/index.tsx +0 -102
  49. package/src/components/form-wizard/types.ts +0 -76
  50. package/src/components/gesture-drawer/index.tsx +0 -551
  51. package/src/components/github-stars/github-api.ts +0 -426
  52. package/src/components/github-stars/hooks.ts +0 -516
  53. package/src/components/github-stars/index.tsx +0 -375
  54. package/src/components/github-stars/types.ts +0 -148
  55. package/src/components/github-stars/variants.tsx +0 -513
  56. package/src/components/health-check/index.tsx +0 -439
  57. package/src/components/hover-card-3d/index.tsx +0 -530
  58. package/src/components/index.ts +0 -128
  59. package/src/components/internal/index.ts +0 -78
  60. package/src/components/kanban/add-card-modal.tsx +0 -502
  61. package/src/components/kanban/card-detail-modal.tsx +0 -761
  62. package/src/components/kanban/index.ts +0 -13
  63. package/src/components/kanban/kanban.tsx +0 -1684
  64. package/src/components/kanban/types.ts +0 -168
  65. package/src/components/lazy-component/index.tsx +0 -823
  66. package/src/components/license-error/index.tsx +0 -29
  67. package/src/components/magnetic-button/index.tsx +0 -167
  68. package/src/components/memory-efficient-data/index.tsx +0 -1016
  69. package/src/components/moonui-quiz-form/index.tsx +0 -817
  70. package/src/components/optimized-image/index.tsx +0 -425
  71. package/src/components/performance-debugger/index.tsx +0 -589
  72. package/src/components/performance-monitor/index.tsx +0 -794
  73. package/src/components/phone-number-input/index.tsx +0 -338
  74. package/src/components/pinch-zoom/index.tsx +0 -566
  75. package/src/components/quiz-form/index.tsx +0 -479
  76. package/src/components/rich-text-editor/index-old-backup.tsx +0 -437
  77. package/src/components/rich-text-editor/index.tsx +0 -2324
  78. package/src/components/rich-text-editor/slash-commands-extension.ts +0 -220
  79. package/src/components/rich-text-editor/slash-commands.css +0 -35
  80. package/src/components/rich-text-editor/table-styles.css +0 -65
  81. package/src/components/sidebar/index.tsx +0 -865
  82. package/src/components/spotlight-card/index.tsx +0 -191
  83. package/src/components/swipeable-card/index.tsx +0 -100
  84. package/src/components/timeline/index.tsx +0 -1148
  85. package/src/components/ui/accordion.tsx +0 -73
  86. package/src/components/ui/alert-dialog.tsx +0 -141
  87. package/src/components/ui/alert.tsx +0 -141
  88. package/src/components/ui/aspect-ratio.tsx +0 -245
  89. package/src/components/ui/avatar.tsx +0 -153
  90. package/src/components/ui/badge.tsx +0 -228
  91. package/src/components/ui/breadcrumb.tsx +0 -214
  92. package/src/components/ui/button.tsx +0 -222
  93. package/src/components/ui/calendar.tsx +0 -387
  94. package/src/components/ui/card.tsx +0 -214
  95. package/src/components/ui/checkbox.tsx +0 -259
  96. package/src/components/ui/collapsible.tsx +0 -135
  97. package/src/components/ui/color-picker.tsx +0 -97
  98. package/src/components/ui/command.tsx +0 -225
  99. package/src/components/ui/dialog.tsx +0 -334
  100. package/src/components/ui/dropdown-menu.tsx +0 -218
  101. package/src/components/ui/gesture-drawer.tsx +0 -11
  102. package/src/components/ui/hover-card.tsx +0 -29
  103. package/src/components/ui/index.ts +0 -190
  104. package/src/components/ui/input.tsx +0 -222
  105. package/src/components/ui/label.tsx +0 -29
  106. package/src/components/ui/lightbox.tsx +0 -606
  107. package/src/components/ui/magnetic-button.tsx +0 -129
  108. package/src/components/ui/media-gallery.tsx +0 -612
  109. package/src/components/ui/pagination.tsx +0 -123
  110. package/src/components/ui/popover.tsx +0 -185
  111. package/src/components/ui/progress.tsx +0 -30
  112. package/src/components/ui/radio-group.tsx +0 -257
  113. package/src/components/ui/scroll-area.tsx +0 -47
  114. package/src/components/ui/select.tsx +0 -374
  115. package/src/components/ui/separator.tsx +0 -145
  116. package/src/components/ui/sheet.tsx +0 -139
  117. package/src/components/ui/skeleton.tsx +0 -20
  118. package/src/components/ui/slider.tsx +0 -354
  119. package/src/components/ui/spotlight-card.tsx +0 -119
  120. package/src/components/ui/switch.tsx +0 -86
  121. package/src/components/ui/table.tsx +0 -329
  122. package/src/components/ui/tabs.tsx +0 -198
  123. package/src/components/ui/textarea.tsx +0 -28
  124. package/src/components/ui/toast.tsx +0 -317
  125. package/src/components/ui/toggle.tsx +0 -119
  126. package/src/components/ui/tooltip.tsx +0 -151
  127. package/src/components/virtual-list/index.tsx +0 -668
  128. package/src/hooks/use-chart.ts +0 -205
  129. package/src/hooks/use-data-table.ts +0 -182
  130. package/src/hooks/use-docs-pro-access.ts +0 -13
  131. package/src/hooks/use-license-check.ts +0 -65
  132. package/src/hooks/use-subscription.ts +0 -19
  133. package/src/hooks/use-toast.ts +0 -15
  134. package/src/index.ts +0 -14
  135. package/src/lib/ai-providers.ts +0 -377
  136. package/src/lib/component-metadata.ts +0 -18
  137. package/src/lib/micro-interactions.ts +0 -255
  138. package/src/lib/paddle.ts +0 -17
  139. package/src/lib/utils.ts +0 -6
  140. package/src/patterns/login-form/index.tsx +0 -276
  141. package/src/patterns/login-form/types.ts +0 -67
  142. package/src/setupTests.ts +0 -41
  143. package/src/styles/advanced-chart.css +0 -239
  144. package/src/styles/calendar.css +0 -35
  145. package/src/styles/design-system.css +0 -363
  146. package/src/styles/index.css +0 -85
  147. package/src/styles/tailwind.css +0 -7
  148. package/src/styles/tokens.css +0 -455
  149. package/src/types/moonui.d.ts +0 -22
  150. package/src/types/next-auth.d.ts +0 -21
  151. package/src/use-intersection-observer.tsx +0 -154
  152. package/src/use-local-storage.tsx +0 -71
  153. package/src/use-paddle.ts +0 -138
  154. package/src/use-performance-optimizer.ts +0 -389
  155. package/src/use-pro-access.ts +0 -141
  156. package/src/use-scroll-animation.ts +0 -219
  157. package/src/use-subscription.ts +0 -37
  158. package/src/use-toast.ts +0 -32
  159. package/src/utils/chart-helpers.ts +0 -357
  160. package/src/utils/cn.ts +0 -6
  161. package/src/utils/data-processing.ts +0 -151
  162. package/src/utils/license-validator.tsx +0 -183
@@ -1,1016 +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
- // Memory konfigürasyonu için tip tanımları
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
- // Yeni özellikler
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
- // Performance metrikleri için tip tanımı
31
- interface MemoryPerformanceMetrics {
32
- fps: number
33
- renderTime: number
34
- memoryLeaks: number
35
- scrollPerformance: number
36
- lastUpdate: number
37
- }
38
-
39
- // Search/Sort/Filter için tip tanımları
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
- // Height measurement için tip tanımı
54
- interface ItemHeightInfo {
55
- index: number
56
- height: number
57
- offset: number
58
- }
59
-
60
- // Memory istatistikleri için tip tanımı
61
- interface MemoryStats {
62
- memoryUsage: number
63
- itemCount: number
64
- cacheHitRate: number
65
- compressionRatio?: number
66
- lastCleanup?: number
67
- performance?: MemoryPerformanceMetrics
68
- }
69
-
70
- // Ana 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
- // Yeni özellikler
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
- // En eski erişileni sil
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
- // En az kullanılanı sil
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
- // İlk gireni sil
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
- // Hit/miss tracking için güncelle
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
- // Son 60 render time'ı tut
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
- // Son 60 frame'i tut
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
- // Basit memory leak detection
257
- return this.renderTimes.filter(time => time > 16).length // 16ms = 60fps threshold
258
- }
259
-
260
- private calculateScrollPerformance(): number {
261
- // Scroll performance hesaplama (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
- // Scroll position'a kadar olan itemları say
322
- while (start < itemCount && currentOffset < scrollTop) {
323
- currentOffset += this.getItemHeight(start)
324
- start++
325
- }
326
-
327
- start = Math.max(0, start - 1)
328
-
329
- // Görünür alan boyunca devam et
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
- // Ana Memory Efficient Data Component
344
- export function MemoryEfficientData<T = any>({
345
- data,
346
- config = {},
347
- renderItem,
348
- height = 400,
349
- onMemoryUpdate,
350
- className,
351
- // Yeni props
352
- itemHeight = 60,
353
- onSearch,
354
- onSort,
355
- onFilter,
356
- onExport,
357
- searchPlaceholder = "Ara...",
358
- emptyStateMessage = "Veri bulunamadı",
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
- // Yeni konfigürasyonlar
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 yönetimi
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
- const [isLoading, setIsLoading] = useState(false)
396
- const [error, setError] = useState<string | null>(null)
397
-
398
- // Refs
399
- const containerRef = useRef<HTMLDivElement>(null)
400
- const cacheRef = useRef(new MemoryCache<T>(Math.floor(maxMemoryItems / chunkSize), cacheStrategy))
401
- const scrollTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined)
402
- const performanceTrackerRef = useRef(new PerformanceTracker())
403
- const heightManagerRef = useRef(new VariableHeightManager(typeof itemHeight === 'number' ? itemHeight : 60))
404
- const itemRefs = useRef<Map<number, HTMLDivElement>>(new Map())
405
-
406
- // İşlenmiş data'yı hesapla (search, sort, filter)
407
- const processedData = useMemo(() => {
408
- let result = [...data]
409
-
410
- try {
411
- setIsLoading(true)
412
-
413
- // Search functionality
414
- if (enableSearch && tableFeatures.searchTerm && onSearch) {
415
- result = onSearch(tableFeatures.searchTerm)
416
- }
417
-
418
- // Filter functionality
419
- if (enableFilter && tableFeatures.filters && tableFeatures.filters.length > 0 && onFilter) {
420
- result = onFilter(result, tableFeatures.filters)
421
- }
422
-
423
- // Sort functionality
424
- if (enableSort && tableFeatures.sortConfig && onSort) {
425
- result = onSort(result, tableFeatures.sortConfig.key, tableFeatures.sortConfig.direction)
426
- }
427
-
428
- setError(null)
429
- return result
430
- } catch (err) {
431
- setError(err instanceof Error ? err.message : 'Veri işlenirken hata oluştu')
432
- return data
433
- } finally {
434
- setIsLoading(false)
435
- }
436
- }, [data, tableFeatures, enableSearch, enableFilter, enableSort, onSearch, onFilter, onSort])
437
-
438
- // Visible data'yı memoize et
439
- const visibleData = useMemo(() => {
440
- if (performanceTracking) {
441
- performanceTrackerRef.current.startRender()
442
- }
443
-
444
- const start = visibleRange.start
445
- const end = Math.min(visibleRange.end, processedData.length)
446
-
447
- // Cache'den kontrol et
448
- const cacheKey = `${start}-${end}-${JSON.stringify(tableFeatures)}`
449
- const cachedData = cacheRef.current.get(cacheKey)
450
-
451
- if (cachedData && cachedData.length === (end - start)) {
452
- if (performanceTracking) {
453
- performanceTrackerRef.current.endRender()
454
- }
455
- return cachedData
456
- }
457
-
458
- // Yeni data slice'ını oluştur
459
- const newData = processedData.slice(start, end)
460
-
461
- // Cache'e kaydet
462
- cacheRef.current.set(cacheKey, newData, compression)
463
-
464
- if (performanceTracking) {
465
- performanceTrackerRef.current.endRender()
466
- }
467
-
468
- return newData
469
- }, [processedData, visibleRange, compression, tableFeatures, performanceTracking])
470
-
471
- // Item height measurement
472
- const measureItemHeight = useCallback((index: number, element: HTMLDivElement) => {
473
- if (!variableHeight) return
474
-
475
- const height = element.getBoundingClientRect().height
476
- heightManagerRef.current.setItemHeight(index, height)
477
-
478
- // Force re-render if height changed significantly
479
- const oldHeight = heightManagerRef.current.getItemHeight(index)
480
- if (Math.abs(height - oldHeight) > 5) {
481
- // Recalculate visible range
482
- const container = containerRef.current
483
- if (container) {
484
- handleScroll({ currentTarget: container } as React.UIEvent<HTMLDivElement>)
485
- }
486
- }
487
- }, [variableHeight])
488
-
489
- // Scroll handler
490
- const handleScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {
491
- if (performanceTracking) {
492
- performanceTrackerRef.current.recordFrame()
493
- }
494
-
495
- const scrollTop = e.currentTarget.scrollTop
496
- const containerHeight = e.currentTarget.clientHeight
497
-
498
- let newStart: number, newEnd: number
499
-
500
- if (variableHeight) {
501
- // Variable height kullan
502
- const range = heightManagerRef.current.getVisibleRange(scrollTop, containerHeight, processedData.length)
503
- newStart = range.start
504
- newEnd = range.end
505
- } else {
506
- // Fixed height kullan
507
- const itemHeightValue = typeof itemHeight === 'number' ? itemHeight : 60
508
- const startIndex = Math.floor(scrollTop / itemHeightValue)
509
- const visibleCount = Math.ceil(containerHeight / itemHeightValue)
510
-
511
- // Buffer ekle
512
- const bufferSize = Math.floor(visibleCount * 0.5)
513
- newStart = Math.max(0, startIndex - bufferSize)
514
- newEnd = Math.min(processedData.length, startIndex + visibleCount + bufferSize)
515
- }
516
-
517
- // Preloading strategy
518
- if (preloadStrategy === 'aggressive') {
519
- const extraBuffer = Math.floor((newEnd - newStart) * 0.5)
520
- newStart = Math.max(0, newStart - extraBuffer)
521
- newEnd = Math.min(processedData.length, newEnd + extraBuffer)
522
- } else if (preloadStrategy === 'smart') {
523
- // Scroll direction'a göre preload
524
- const currentScroll = scrollTop
525
- const lastScroll = scrollTimeoutRef.current ? parseInt(scrollTimeoutRef.current as any) : 0
526
- const isScrollingDown = currentScroll > lastScroll
527
-
528
- if (isScrollingDown) {
529
- newEnd = Math.min(processedData.length, newEnd + Math.floor((newEnd - newStart) * 0.2))
530
- } else {
531
- newStart = Math.max(0, newStart - Math.floor((newEnd - newStart) * 0.2))
532
- }
533
- }
534
-
535
- // Throttle scroll updates
536
- if (scrollTimeoutRef.current) {
537
- clearTimeout(scrollTimeoutRef.current)
538
- }
539
-
540
- scrollTimeoutRef.current = setTimeout(() => {
541
- setVisibleRange({ start: newStart, end: newEnd })
542
- }, 16) // ~60fps
543
- }, [processedData.length, variableHeight, itemHeight, preloadStrategy, performanceTracking])
544
-
545
- // Search handler
546
- const handleSearch = useCallback((searchTerm: string) => {
547
- setTableFeatures(prev => ({ ...prev, searchTerm }))
548
- }, [])
549
-
550
- // Sort handler
551
- const handleSort = useCallback((key: keyof T) => {
552
- setTableFeatures(prev => {
553
- const currentDirection = prev.sortConfig?.key === key && prev.sortConfig?.direction === 'asc' ? 'desc' : 'asc'
554
- return {
555
- ...prev,
556
- sortConfig: { key, direction: currentDirection }
557
- }
558
- })
559
- }, [])
560
-
561
- // Filter handler
562
- const handleFilter = useCallback((filters: TableFeatures<T>['filters']) => {
563
- setTableFeatures(prev => ({ ...prev, filters }))
564
- }, [])
565
-
566
- // Export handler
567
- const handleExport = useCallback((format: 'csv' | 'json' | 'xlsx') => {
568
- if (onExport) {
569
- onExport(processedData, format)
570
- }
571
- }, [processedData, onExport])
572
-
573
- // Memory statistics'i güncelle
574
- useEffect(() => {
575
- const cacheStats = cacheRef.current.getStats()
576
- const performanceMetrics = performanceTracking ? performanceTrackerRef.current.getMetrics() : undefined
577
-
578
- const newStats: MemoryStats = {
579
- memoryUsage: cacheStats.memoryUsage,
580
- itemCount: visibleData.length,
581
- cacheHitRate: cacheStats.hitRate,
582
- compressionRatio: compression ? 0.7 : 1.0,
583
- lastCleanup: Date.now(),
584
- performance: performanceMetrics
585
- }
586
-
587
- setMemoryStats(newStats)
588
-
589
- if (enableAnalytics && analyticsCallback) {
590
- analyticsCallback(newStats)
591
- }
592
-
593
- if (onMemoryUpdate) {
594
- onMemoryUpdate(newStats)
595
- }
596
- }, [visibleData, enableAnalytics, analyticsCallback, onMemoryUpdate, compression, performanceTracking])
597
-
598
- // Auto cleanup effect
599
- useEffect(() => {
600
- if (!autoCleanup) return
601
-
602
- const cleanupInterval = setInterval(() => {
603
- const memoryUsage = (visibleData.length / maxMemoryItems)
604
- if (memoryUsage > cleanupThreshold) {
605
- // Basit cleanup - cache'i temizle
606
- cacheRef.current.clear()
607
- }
608
- }, 5000) // Her 5 saniyede kontrol et
609
-
610
- return () => clearInterval(cleanupInterval)
611
- }, [autoCleanup, cleanupThreshold, maxMemoryItems, visibleData.length])
612
-
613
- // Loading ve Error states için render
614
- if (error && errorComponent) {
615
- return errorComponent
616
- }
617
-
618
- if (isLoading && loadingComponent) {
619
- return loadingComponent
620
- }
621
-
622
- // Total height hesapla
623
- const totalHeight = variableHeight
624
- ? heightManagerRef.current.getTotalHeight(processedData.length)
625
- : processedData.length * (typeof itemHeight === 'number' ? itemHeight : 60)
626
-
627
- // Offset hesapla
628
- const offsetY = variableHeight
629
- ? heightManagerRef.current.getOffsetForIndex(visibleRange.start)
630
- : visibleRange.start * (typeof itemHeight === 'number' ? itemHeight : 60)
631
-
632
- return (
633
- <div className={cn("flex flex-col", className)}>
634
- {/* Control Bar */}
635
- {(enableSearch || enableSort || enableFilter || enableExport) && (
636
- <motion.div
637
- className="flex items-center gap-2 p-3 border-b bg-muted/5"
638
- initial={animations ? { opacity: 0, y: -10 } : {}}
639
- animate={animations ? { opacity: 1, y: 0 } : {}}
640
- transition={{ duration: 0.2 }}
641
- >
642
- {enableSearch && (
643
- <div className="relative flex-1 max-w-sm">
644
- <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
645
- <input
646
- type="text"
647
- placeholder={searchPlaceholder}
648
- value={tableFeatures.searchTerm}
649
- onChange={(e) => handleSearch(e.target.value)}
650
- 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"
651
- />
652
- </div>
653
- )}
654
-
655
- <div className="flex items-center gap-1">
656
- {enableFilter && (
657
- <button
658
- onClick={() => {/* Filter modal açılacak */}}
659
- className="p-2 hover:bg-muted rounded-md transition-colors"
660
- title="Filtrele"
661
- >
662
- <Filter className="h-4 w-4" />
663
- </button>
664
- )}
665
-
666
- {enableExport && (
667
- <div className="relative">
668
- <button
669
- onClick={() => handleExport('csv')}
670
- className="p-2 hover:bg-muted rounded-md transition-colors"
671
- title="Dışa Aktar"
672
- >
673
- <Download className="h-4 w-4" />
674
- </button>
675
- </div>
676
- )}
677
- </div>
678
- </motion.div>
679
- )}
680
-
681
- {/* Data Container */}
682
- <div
683
- ref={containerRef}
684
- className="overflow-auto border rounded-lg bg-background"
685
- style={{ height: typeof height === 'number' ? height - (enableSearch || enableSort || enableFilter || enableExport ? 60 : 0) : height }}
686
- onScroll={handleScroll}
687
- >
688
- {processedData.length === 0 ? (
689
- <motion.div
690
- className="flex items-center justify-center h-full text-muted-foreground"
691
- initial={animations ? { opacity: 0 } : {}}
692
- animate={animations ? { opacity: 1 } : {}}
693
- >
694
- {emptyStateMessage}
695
- </motion.div>
696
- ) : (
697
- <div style={{ height: totalHeight, position: 'relative' }}>
698
- <motion.div
699
- style={{
700
- transform: `translateY(${offsetY}px)`,
701
- position: 'absolute',
702
- width: '100%'
703
- }}
704
- animate={animations ? { y: offsetY } : {}}
705
- transition={animations ? { duration: 0.1, ease: "linear" } : {}}
706
- >
707
- <AnimatePresence mode="popLayout">
708
- {visibleData.map((item, index) => {
709
- const globalIndex = visibleRange.start + index
710
- const itemHeightValue = typeof itemHeight === 'function'
711
- ? itemHeight(item, globalIndex)
712
- : (typeof itemHeight === 'number' ? itemHeight : 60)
713
-
714
- return (
715
- <motion.div
716
- key={globalIndex}
717
- ref={(el) => {
718
- if (el && variableHeight) {
719
- itemRefs.current.set(globalIndex, el)
720
- measureItemHeight(globalIndex, el)
721
- }
722
- }}
723
- style={variableHeight ? {} : { height: itemHeightValue }}
724
- initial={animations ? { opacity: 0, y: 20 } : {}}
725
- animate={animations ? { opacity: 1, y: 0 } : {}}
726
- exit={animations ? { opacity: 0, y: -20 } : {}}
727
- transition={animations ? { duration: 0.2 } : {}}
728
- layout={animations}
729
- >
730
- {renderItem(item, globalIndex)}
731
- </motion.div>
732
- )
733
- })}
734
- </AnimatePresence>
735
- </motion.div>
736
- </div>
737
- )}
738
- </div>
739
-
740
- {/* Performance Monitor */}
741
- {performanceTracking && memoryStats.performance && (
742
- <div className="p-2 border-t bg-muted/5 text-xs text-muted-foreground flex items-center gap-4">
743
- <div className="flex items-center gap-1">
744
- <Zap className="h-3 w-3" />
745
- <span>FPS: {memoryStats.performance.fps}</span>
746
- </div>
747
- <div className="flex items-center gap-1">
748
- <Clock className="h-3 w-3" />
749
- <span>Render: {memoryStats.performance.renderTime}ms</span>
750
- </div>
751
- <div className="flex items-center gap-1">
752
- <Cpu className="h-3 w-3" />
753
- <span>Scroll: {memoryStats.performance.scrollPerformance}%</span>
754
- </div>
755
- <div className="flex items-center gap-1">
756
- <BarChart3 className="h-3 w-3" />
757
- <span>Cache: {Math.round(memoryStats.cacheHitRate * 100)}%</span>
758
- </div>
759
- </div>
760
- )}
761
- </div>
762
- )
763
- }
764
-
765
- // Real-time Performance Monitor Component
766
- interface RealTimePerformanceMonitorProps {
767
- memoryStats?: MemoryStats
768
- className?: string
769
- showChart?: boolean
770
- updateInterval?: number
771
- }
772
-
773
- export function RealTimePerformanceMonitor({
774
- memoryStats,
775
- className,
776
- showChart = false,
777
- updateInterval = 1000
778
- }: RealTimePerformanceMonitorProps) {
779
- const [history, setHistory] = useState<MemoryStats[]>([])
780
- const [isActive, setIsActive] = useState(true)
781
-
782
- useEffect(() => {
783
- if (!memoryStats || !isActive) return
784
-
785
- setHistory(prev => {
786
- const newHistory = [...prev, memoryStats]
787
- // Son 60 entry'yi tut (1 dakika)
788
- return newHistory.length > 60 ? newHistory.slice(-60) : newHistory
789
- })
790
- }, [memoryStats, isActive])
791
-
792
- const formatBytes = (bytes: number) => {
793
- if (bytes === 0) return '0 Bytes'
794
- const k = 1024
795
- const sizes = ['Bytes', 'KB', 'MB', 'GB']
796
- const i = Math.floor(Math.log(bytes) / Math.log(k))
797
- return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
798
- }
799
-
800
- const getPerformanceColor = (value: number, threshold: { good: number; warning: number }) => {
801
- if (value >= threshold.good) return 'text-green-500'
802
- if (value >= threshold.warning) return 'text-yellow-500'
803
- return 'text-red-500'
804
- }
805
-
806
- if (!memoryStats) {
807
- return (
808
- <div className={cn("p-4 border rounded-lg bg-muted/5", className)}>
809
- <div className="text-center text-muted-foreground">
810
- Performance monitoring devre dışı
811
- </div>
812
- </div>
813
- )
814
- }
815
-
816
- return (
817
- <motion.div
818
- className={cn("p-4 border rounded-lg bg-background space-y-4", className)}
819
- initial={{ opacity: 0, y: 20 }}
820
- animate={{ opacity: 1, y: 0 }}
821
- transition={{ duration: 0.3 }}
822
- >
823
- <div className="flex items-center justify-between">
824
- <h3 className="font-semibold flex items-center gap-2">
825
- <BarChart3 className="h-4 w-4" />
826
- Gerçek Zamanlı Performans
827
- </h3>
828
- <button
829
- onClick={() => setIsActive(!isActive)}
830
- className={cn(
831
- "px-3 py-1 text-xs rounded-md transition-colors",
832
- isActive
833
- ? "bg-green-500/10 text-green-500 hover:bg-green-500/20"
834
- : "bg-muted text-muted-foreground hover:bg-muted/80"
835
- )}
836
- >
837
- {isActive ? 'Aktif' : 'Durduruldu'}
838
- </button>
839
- </div>
840
-
841
- <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
842
- {/* FPS */}
843
- <div className="space-y-1">
844
- <div className="text-xs text-muted-foreground">FPS</div>
845
- <div className={cn(
846
- "text-lg font-mono font-bold",
847
- memoryStats.performance ? getPerformanceColor(memoryStats.performance.fps, { good: 55, warning: 30 }) : ''
848
- )}>
849
- {memoryStats.performance?.fps || 0}
850
- </div>
851
- </div>
852
-
853
- {/* Render Time */}
854
- <div className="space-y-1">
855
- <div className="text-xs text-muted-foreground">Render Süresi</div>
856
- <div className={cn(
857
- "text-lg font-mono font-bold",
858
- memoryStats.performance ? getPerformanceColor(100 - memoryStats.performance.renderTime, { good: 84, warning: 70 }) : ''
859
- )}>
860
- {memoryStats.performance?.renderTime.toFixed(2) || 0}ms
861
- </div>
862
- </div>
863
-
864
- {/* Memory Usage */}
865
- <div className="space-y-1">
866
- <div className="text-xs text-muted-foreground">Bellek Kullanımı</div>
867
- <div className="text-lg font-mono font-bold">
868
- {formatBytes(memoryStats.memoryUsage)}
869
- </div>
870
- </div>
871
-
872
- {/* Cache Hit Rate */}
873
- <div className="space-y-1">
874
- <div className="text-xs text-muted-foreground">Cache Hit Rate</div>
875
- <div className={cn(
876
- "text-lg font-mono font-bold",
877
- getPerformanceColor(memoryStats.cacheHitRate * 100, { good: 85, warning: 70 })
878
- )}>
879
- {Math.round(memoryStats.cacheHitRate * 100)}%
880
- </div>
881
- </div>
882
- </div>
883
-
884
- {/* Memory Leaks & Scroll Performance */}
885
- {memoryStats.performance && (
886
- <div className="grid grid-cols-2 gap-4 pt-2 border-t">
887
- <div className="space-y-1">
888
- <div className="text-xs text-muted-foreground">Memory Leaks</div>
889
- <div className={cn(
890
- "text-sm font-mono",
891
- memoryStats.performance.memoryLeaks > 5 ? 'text-red-500' : 'text-green-500'
892
- )}>
893
- {memoryStats.performance.memoryLeaks} detection
894
- </div>
895
- </div>
896
- <div className="space-y-1">
897
- <div className="text-xs text-muted-foreground">Scroll Performance</div>
898
- <div className={cn(
899
- "text-sm font-mono",
900
- getPerformanceColor(memoryStats.performance.scrollPerformance, { good: 85, warning: 70 })
901
- )}>
902
- {memoryStats.performance.scrollPerformance}%
903
- </div>
904
- </div>
905
- </div>
906
- )}
907
-
908
- {/* Mini Chart */}
909
- {showChart && history.length > 1 && (
910
- <div className="pt-2 border-t">
911
- <div className="text-xs text-muted-foreground mb-2">FPS Geçmişi (Son 60 güncelleme)</div>
912
- <div className="h-16 flex items-end gap-1">
913
- {history.slice(-30).map((stat, index) => {
914
- const fps = stat.performance?.fps || 0
915
- const height = Math.max(4, (fps / 60) * 100)
916
- const color = fps >= 55 ? 'bg-green-500' : fps >= 30 ? 'bg-yellow-500' : 'bg-red-500'
917
-
918
- return (
919
- <motion.div
920
- key={index}
921
- className={cn("w-1 rounded-t-sm", color)}
922
- style={{ height: `${height}%` }}
923
- initial={{ height: 0 }}
924
- animate={{ height: `${height}%` }}
925
- transition={{ duration: 0.2 }}
926
- />
927
- )
928
- })}
929
- </div>
930
- </div>
931
- )}
932
- </motion.div>
933
- )
934
- }
935
-
936
- // Memory Analytics Component (Backward compatibility)
937
- interface MemoryAnalyticsProps {
938
- onStatsUpdate?: (stats: MemoryStats) => void
939
- showRealTime?: boolean
940
- className?: string
941
- }
942
-
943
- export function MemoryAnalytics({
944
- onStatsUpdate,
945
- showRealTime = false,
946
- className
947
- }: MemoryAnalyticsProps) {
948
- const [stats, setStats] = useState<MemoryStats>({
949
- memoryUsage: 0,
950
- itemCount: 0,
951
- cacheHitRate: 0.95
952
- })
953
-
954
- // Mock real-time updates for backward compatibility
955
- useEffect(() => {
956
- if (!showRealTime) return
957
-
958
- const interval = setInterval(() => {
959
- const newStats: MemoryStats = {
960
- memoryUsage: Math.random() * 50 * 1024 * 1024,
961
- itemCount: Math.floor(Math.random() * 50000),
962
- cacheHitRate: 0.9 + Math.random() * 0.1,
963
- lastCleanup: Date.now(),
964
- performance: {
965
- fps: Math.floor(30 + Math.random() * 30),
966
- renderTime: Math.random() * 16,
967
- memoryLeaks: Math.floor(Math.random() * 3),
968
- scrollPerformance: 70 + Math.random() * 30,
969
- lastUpdate: Date.now()
970
- } as MemoryPerformanceMetrics
971
- }
972
-
973
- setStats(newStats)
974
- if (onStatsUpdate) {
975
- onStatsUpdate(newStats)
976
- }
977
- }, 1000)
978
-
979
- return () => clearInterval(interval)
980
- }, [showRealTime, onStatsUpdate])
981
-
982
- return <RealTimePerformanceMonitor memoryStats={stats} className={className} showChart={showRealTime} />
983
- }
984
-
985
- // Utility hook for streaming data
986
- export function useStreamingData<T>(
987
- initialData: T[] = [],
988
- streamingConfig?: { interval?: number; maxItems?: number }
989
- ) {
990
- const [data, setData] = useState<T[]>(initialData)
991
- const { interval = 1000, maxItems = 10000 } = streamingConfig || {}
992
-
993
- const addItem = useCallback((newItem: T) => {
994
- setData(prev => {
995
- const newData = [...prev, newItem]
996
- return newData.length > maxItems ? newData.slice(-maxItems) : newData
997
- })
998
- }, [maxItems])
999
-
1000
- const clearData = useCallback(() => {
1001
- setData([])
1002
- }, [])
1003
-
1004
- return { data, addItem, clearData }
1005
- }
1006
-
1007
- // Export types
1008
- export type {
1009
- MemoryConfig,
1010
- MemoryStats,
1011
- MemoryAnalyticsProps,
1012
- MemoryPerformanceMetrics,
1013
- TableFeatures,
1014
- ItemHeightInfo,
1015
- RealTimePerformanceMonitorProps
1016
- }