@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,357 +0,0 @@
1
- import { ChartDataPoint, ChartSeries } from '../components/advanced-chart'
2
-
3
- interface ChartTheme {
4
- colors: string[]
5
- backgroundColor: string
6
- textColor: string
7
- gridColor: string
8
- tooltipBackground: string
9
- tooltipBorder: string
10
- }
11
-
12
- export const CHART_THEMES: Record<string, ChartTheme> = {
13
- default: {
14
- colors: ['#3b82f6', '#ef4444', '#10b981', '#f59e0b', '#8b5cf6', '#06b6d4', '#f97316', '#84cc16', '#ec4899', '#6366f1'],
15
- backgroundColor: '#ffffff',
16
- textColor: '#374151',
17
- gridColor: '#e5e7eb',
18
- tooltipBackground: '#1f2937',
19
- tooltipBorder: '#374151',
20
- },
21
- dark: {
22
- colors: ['#60a5fa', '#f87171', '#34d399', '#fbbf24', '#a78bfa', '#22d3ee', '#fb923c', '#a3e635', '#f472b6', '#818cf8'],
23
- backgroundColor: '#1f2937',
24
- textColor: '#f9fafb',
25
- gridColor: '#374151',
26
- tooltipBackground: '#374151',
27
- tooltipBorder: '#4b5563',
28
- },
29
- minimal: {
30
- colors: ['#000000', '#666666', '#999999', '#cccccc'],
31
- backgroundColor: '#ffffff',
32
- textColor: '#000000',
33
- gridColor: '#f3f4f6',
34
- tooltipBackground: '#000000',
35
- tooltipBorder: '#000000',
36
- },
37
- }
38
-
39
- export function generateChartData(
40
- count: number,
41
- series: string[],
42
- options?: {
43
- startDate?: Date
44
- interval?: 'hour' | 'day' | 'week' | 'month'
45
- trend?: 'up' | 'down' | 'random'
46
- baseValue?: number
47
- variance?: number
48
- }
49
- ): ChartDataPoint[] {
50
- const {
51
- startDate = new Date(),
52
- interval = 'day',
53
- trend = 'random',
54
- baseValue = 100,
55
- variance = 20,
56
- } = options || {}
57
-
58
- const data: ChartDataPoint[] = []
59
- const current = new Date(startDate)
60
-
61
- for (let i = 0; i < count; i++) {
62
- const point: ChartDataPoint = {
63
- name: formatDateForInterval(current, interval),
64
- timestamp: current.getTime(),
65
- }
66
-
67
- series.forEach((seriesName, index) => {
68
- let value = baseValue
69
-
70
- if (trend === 'up') {
71
- value += (i * 5) + (Math.random() - 0.5) * variance
72
- } else if (trend === 'down') {
73
- value -= (i * 5) + (Math.random() - 0.5) * variance
74
- } else {
75
- value += (Math.random() - 0.5) * variance * 2
76
- }
77
-
78
- // Add some series-specific variation
79
- value += index * 10 + (Math.random() - 0.5) * 10
80
-
81
- point[seriesName] = Math.max(0, Math.round(value))
82
- })
83
-
84
- data.push(point)
85
-
86
- // Increment date based on interval
87
- switch (interval) {
88
- case 'hour':
89
- current.setHours(current.getHours() + 1)
90
- break
91
- case 'day':
92
- current.setDate(current.getDate() + 1)
93
- break
94
- case 'week':
95
- current.setDate(current.getDate() + 7)
96
- break
97
- case 'month':
98
- current.setMonth(current.getMonth() + 1)
99
- break
100
- }
101
- }
102
-
103
- return data
104
- }
105
-
106
- function formatDateForInterval(date: Date, interval: 'hour' | 'day' | 'week' | 'month'): string {
107
- switch (interval) {
108
- case 'hour':
109
- return date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' })
110
- case 'day':
111
- return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })
112
- case 'week':
113
- return `Week ${getWeekNumber(date)}`
114
- case 'month':
115
- return date.toLocaleDateString('en-US', { month: 'short', year: 'numeric' })
116
- default:
117
- return date.toLocaleDateString()
118
- }
119
- }
120
-
121
- function getWeekNumber(date: Date): number {
122
- const firstDayOfYear = new Date(date.getFullYear(), 0, 1)
123
- const pastDaysOfYear = (date.getTime() - firstDayOfYear.getTime()) / 86400000
124
- return Math.ceil((pastDaysOfYear + firstDayOfYear.getDay() + 1) / 7)
125
- }
126
-
127
- export function calculateMovingAverage(data: ChartDataPoint[], key: string, window: number): ChartDataPoint[] {
128
- if (window <= 0 || window > data.length) return data
129
-
130
- return data.map((point, index) => {
131
- if (index < window - 1) return point
132
-
133
- const windowData = data.slice(index - window + 1, index + 1)
134
- const sum = windowData.reduce((acc, item) => acc + (Number(item[key]) || 0), 0)
135
- const average = sum / window
136
-
137
- return {
138
- ...point,
139
- [`${key}_ma${window}`]: Math.round(average * 100) / 100,
140
- }
141
- })
142
- }
143
-
144
- export function detectOutliers(data: ChartDataPoint[], key: string, threshold: number = 2): ChartDataPoint[] {
145
- const values = data.map(point => Number(point[key]) || 0)
146
- const mean = values.reduce((sum, val) => sum + val, 0) / values.length
147
- const variance = values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / values.length
148
- const stdDev = Math.sqrt(variance)
149
-
150
- return data.map(point => {
151
- const value = Number(point[key]) || 0
152
- const zScore = Math.abs((value - mean) / stdDev)
153
-
154
- return {
155
- ...point,
156
- [`${key}_outlier`]: zScore > threshold,
157
- [`${key}_zscore`]: Math.round(zScore * 100) / 100,
158
- }
159
- })
160
- }
161
-
162
- export function interpolateData(data: ChartDataPoint[], key: string, method: 'linear' | 'polynomial' = 'linear'): ChartDataPoint[] {
163
- const result = [...data]
164
-
165
- for (let i = 0; i < result.length; i++) {
166
- const point = result[i]
167
-
168
- if (point[key] == null || point[key] === '') {
169
- // Find nearest non-null values
170
- let prevIndex = i - 1
171
- let nextIndex = i + 1
172
-
173
- while (prevIndex >= 0 && (result[prevIndex][key] == null || result[prevIndex][key] === '')) {
174
- prevIndex--
175
- }
176
-
177
- while (nextIndex < result.length && (result[nextIndex][key] == null || result[nextIndex][key] === '')) {
178
- nextIndex++
179
- }
180
-
181
- if (prevIndex >= 0 && nextIndex < result.length) {
182
- const prevValue = Number(result[prevIndex][key])
183
- const nextValue = Number(result[nextIndex][key])
184
-
185
- if (method === 'linear') {
186
- const ratio = (i - prevIndex) / (nextIndex - prevIndex)
187
- point[key] = prevValue + (nextValue - prevValue) * ratio
188
- }
189
- } else if (prevIndex >= 0) {
190
- point[key] = result[prevIndex][key]
191
- } else if (nextIndex < result.length) {
192
- point[key] = result[nextIndex][key]
193
- }
194
- }
195
- }
196
-
197
- return result
198
- }
199
-
200
- export function aggregateDataByPeriod(
201
- data: ChartDataPoint[],
202
- period: 'hour' | 'day' | 'week' | 'month',
203
- aggregations: Record<string, 'sum' | 'avg' | 'min' | 'max' | 'count'>
204
- ): ChartDataPoint[] {
205
- const groups: Record<string, ChartDataPoint[]> = {}
206
-
207
- data.forEach(point => {
208
- const timestamp = point.timestamp ? new Date(point.timestamp as number) : new Date()
209
- const key = formatDateForInterval(timestamp, period)
210
-
211
- if (!groups[key]) {
212
- groups[key] = []
213
- }
214
- groups[key].push(point)
215
- })
216
-
217
- return Object.entries(groups).map(([key, groupData]) => {
218
- const result: ChartDataPoint = { name: key }
219
-
220
- Object.entries(aggregations).forEach(([field, operation]) => {
221
- const values = groupData.map(point => Number(point[field]) || 0)
222
-
223
- switch (operation) {
224
- case 'sum':
225
- result[field] = values.reduce((sum, val) => sum + val, 0)
226
- break
227
- case 'avg':
228
- result[field] = values.reduce((sum, val) => sum + val, 0) / values.length
229
- break
230
- case 'min':
231
- result[field] = Math.min(...values)
232
- break
233
- case 'max':
234
- result[field] = Math.max(...values)
235
- break
236
- case 'count':
237
- result[field] = values.length
238
- break
239
- }
240
- })
241
-
242
- return result
243
- })
244
- }
245
-
246
- export function exportChartAsImage(
247
- chartElement: HTMLElement,
248
- filename: string = 'chart',
249
- format: 'png' | 'jpeg' | 'svg' = 'png'
250
- ): void {
251
- // This would typically use html2canvas or similar library
252
- // For now, we'll provide a basic implementation
253
- console.log(`Exporting chart as ${format} with filename: ${filename}`)
254
-
255
- // Implementation would go here
256
- // This is a placeholder for the actual export functionality
257
- }
258
-
259
- export function exportChartData(
260
- data: ChartDataPoint[],
261
- filename: string = 'chart-data',
262
- format: 'json' | 'csv' = 'json'
263
- ): void {
264
- let content: string
265
- let mimeType: string
266
-
267
- if (format === 'json') {
268
- content = JSON.stringify(data, null, 2)
269
- mimeType = 'application/json'
270
- } else {
271
- // CSV export
272
- const headers = Object.keys(data[0] || {})
273
- const csvRows = [
274
- headers.join(','),
275
- ...data.map(row =>
276
- headers.map(header => {
277
- const value = row[header]
278
- return typeof value === 'string' && value.includes(',')
279
- ? `"${value}"`
280
- : value
281
- }).join(',')
282
- )
283
- ]
284
- content = csvRows.join('\n')
285
- mimeType = 'text/csv'
286
- }
287
-
288
- const blob = new Blob([content], { type: mimeType })
289
- const url = window.URL.createObjectURL(blob)
290
- const link = document.createElement('a')
291
- link.href = url
292
- link.download = `${filename}.${format}`
293
- document.body.appendChild(link)
294
- link.click()
295
- document.body.removeChild(link)
296
- window.URL.revokeObjectURL(url)
297
- }
298
-
299
- // Gradient color generator
300
- export function generateGradientColors(baseColor: string, count: number = 5): string[] {
301
- const colors: string[] = []
302
- const rgb = hexToRgb(baseColor)
303
-
304
- if (!rgb) return [baseColor]
305
-
306
- for (let i = 0; i < count; i++) {
307
- const factor = i / (count - 1)
308
- const r = Math.round(rgb.r + (255 - rgb.r) * factor * 0.5)
309
- const g = Math.round(rgb.g + (255 - rgb.g) * factor * 0.5)
310
- const b = Math.round(rgb.b + (255 - rgb.b) * factor * 0.5)
311
- colors.push(`rgb(${r}, ${g}, ${b})`)
312
- }
313
-
314
- return colors
315
- }
316
-
317
- function hexToRgb(hex: string): { r: number; g: number; b: number } | null {
318
- const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
319
- return result ? {
320
- r: parseInt(result[1], 16),
321
- g: parseInt(result[2], 16),
322
- b: parseInt(result[3], 16)
323
- } : null
324
- }
325
-
326
- // Performance optimization helpers
327
- export function throttleChartData(data: ChartDataPoint[], maxPoints: number = 1000): ChartDataPoint[] {
328
- if (data.length <= maxPoints) return data
329
-
330
- const step = Math.ceil(data.length / maxPoints)
331
- return data.filter((_, index) => index % step === 0)
332
- }
333
-
334
- // Format large numbers
335
- export function formatChartValue(value: number): string {
336
- if (value >= 1e9) return `${(value / 1e9).toFixed(1)}B`
337
- if (value >= 1e6) return `${(value / 1e6).toFixed(1)}M`
338
- if (value >= 1e3) return `${(value / 1e3).toFixed(1)}K`
339
- return value.toString()
340
- }
341
-
342
- // Calculate chart statistics
343
- export function calculateChartStats(data: ChartDataPoint[], keys: string[]): Record<string, { min: number; max: number; avg: number; total: number }> {
344
- const stats: Record<string, { min: number; max: number; avg: number; total: number }> = {}
345
-
346
- keys.forEach(key => {
347
- const values = data.map(point => Number(point[key]) || 0)
348
- stats[key] = {
349
- min: Math.min(...values),
350
- max: Math.max(...values),
351
- avg: values.reduce((sum, val) => sum + val, 0) / values.length,
352
- total: values.reduce((sum, val) => sum + val, 0)
353
- }
354
- })
355
-
356
- return stats
357
- }
package/src/utils/cn.ts DELETED
@@ -1,6 +0,0 @@
1
- import { type ClassValue, clsx } from 'clsx';
2
- import { twMerge } from 'tailwind-merge';
3
-
4
- export function cn(...inputs: ClassValue[]) {
5
- return twMerge(clsx(inputs));
6
- }
@@ -1,151 +0,0 @@
1
- export interface DataProcessor<T = any> {
2
- filter: (data: T[], predicate: (item: T) => boolean) => T[]
3
- sort: (data: T[], key: keyof T, direction?: 'asc' | 'desc') => T[]
4
- group: (data: T[], key: keyof T) => Record<string, T[]>
5
- aggregate: (data: T[], key: keyof T, operation: 'sum' | 'avg' | 'min' | 'max' | 'count') => number
6
- paginate: (data: T[], page: number, pageSize: number) => T[]
7
- search: (data: T[], query: string, searchKeys?: (keyof T)[]) => T[]
8
- transform: <U>(data: T[], transformer: (item: T) => U) => U[]
9
- }
10
-
11
- export function createDataProcessor<T = any>(): DataProcessor<T> {
12
- return {
13
- filter: (data: T[], predicate: (item: T) => boolean) => {
14
- return data.filter(predicate)
15
- },
16
-
17
- sort: (data: T[], key: keyof T, direction: 'asc' | 'desc' = 'asc') => {
18
- return [...data].sort((a, b) => {
19
- const aVal = a[key]
20
- const bVal = b[key]
21
-
22
- if (aVal === bVal) return 0
23
-
24
- const comparison = aVal < bVal ? -1 : 1
25
- return direction === 'asc' ? comparison : -comparison
26
- })
27
- },
28
-
29
- group: (data: T[], key: keyof T) => {
30
- return data.reduce((groups, item) => {
31
- const groupKey = String(item[key])
32
- if (!groups[groupKey]) {
33
- groups[groupKey] = []
34
- }
35
- groups[groupKey].push(item)
36
- return groups
37
- }, {} as Record<string, T[]>)
38
- },
39
-
40
- aggregate: (data: T[], key: keyof T, operation: 'sum' | 'avg' | 'min' | 'max' | 'count') => {
41
- const values = data.map(item => Number(item[key])).filter(val => !isNaN(val))
42
-
43
- if (values.length === 0) return 0
44
-
45
- switch (operation) {
46
- case 'sum':
47
- return values.reduce((sum, val) => sum + val, 0)
48
- case 'avg':
49
- return values.reduce((sum, val) => sum + val, 0) / values.length
50
- case 'min':
51
- return Math.min(...values)
52
- case 'max':
53
- return Math.max(...values)
54
- case 'count':
55
- return values.length
56
- default:
57
- return 0
58
- }
59
- },
60
-
61
- paginate: (data: T[], page: number, pageSize: number) => {
62
- const startIndex = (page - 1) * pageSize
63
- const endIndex = startIndex + pageSize
64
- return data.slice(startIndex, endIndex)
65
- },
66
-
67
- search: (data: T[], query: string, searchKeys?: (keyof T)[]) => {
68
- if (!query.trim()) return data
69
-
70
- const lowerQuery = query.toLowerCase()
71
-
72
- return data.filter(item => {
73
- const keysToSearch = searchKeys || Object.keys(item as Record<string, any>) as (keyof T)[]
74
-
75
- return keysToSearch.some(key => {
76
- const value = item[key]
77
- if (value == null) return false
78
- return String(value).toLowerCase().includes(lowerQuery)
79
- })
80
- })
81
- },
82
-
83
- transform: <U>(data: T[], transformer: (item: T) => U) => {
84
- return data.map(transformer)
85
- }
86
- }
87
- }
88
-
89
- // Utility functions for common data operations
90
- export function calculatePercentageChange(current: number, previous: number): number {
91
- if (previous === 0) return current > 0 ? 100 : 0
92
- return ((current - previous) / previous) * 100
93
- }
94
-
95
- export function formatNumber(value: number, options?: {
96
- decimals?: number
97
- currency?: string
98
- percentage?: boolean
99
- compact?: boolean
100
- }): string {
101
- const { decimals = 2, currency, percentage = false, compact = false } = options || {}
102
-
103
- if (percentage) {
104
- return `${value.toFixed(decimals)}%`
105
- }
106
-
107
- if (currency) {
108
- return new Intl.NumberFormat('en-US', {
109
- style: 'currency',
110
- currency,
111
- minimumFractionDigits: decimals,
112
- maximumFractionDigits: decimals,
113
- }).format(value)
114
- }
115
-
116
- if (compact && Math.abs(value) >= 1000) {
117
- return new Intl.NumberFormat('en-US', {
118
- notation: 'compact',
119
- minimumFractionDigits: 0,
120
- maximumFractionDigits: 1,
121
- }).format(value)
122
- }
123
-
124
- return value.toFixed(decimals)
125
- }
126
-
127
- export function generateDateRange(start: Date, end: Date, interval: 'day' | 'week' | 'month' = 'day'): Date[] {
128
- const dates: Date[] = []
129
- const current = new Date(start)
130
-
131
- while (current <= end) {
132
- dates.push(new Date(current))
133
-
134
- switch (interval) {
135
- case 'day':
136
- current.setDate(current.getDate() + 1)
137
- break
138
- case 'week':
139
- current.setDate(current.getDate() + 7)
140
- break
141
- case 'month':
142
- current.setMonth(current.getMonth() + 1)
143
- break
144
- }
145
- }
146
-
147
- return dates
148
- }
149
-
150
- // debounce function removed to avoid conflicts with @moontra/moonui
151
- // Use debounce from @moontra/moonui instead
@@ -1,183 +0,0 @@
1
- /**
2
- * License Validation System for MoonUI Pro
3
- * This ensures that only licensed users can access pro components
4
- */
5
-
6
- interface LicenseData {
7
- key: string;
8
- email: string;
9
- expiresAt?: string;
10
- features?: string[];
11
- }
12
-
13
- class LicenseValidator {
14
- private static instance: LicenseValidator;
15
- private licenseData: LicenseData | null = null;
16
- private validationCache: Map<string, boolean> = new Map();
17
- private readonly VALIDATION_ENDPOINT = 'https://api.moonui.dev/v1/license/validate';
18
-
19
- private constructor() {
20
- // Initialize license from environment or stored data
21
- this.initializeLicense();
22
- }
23
-
24
- static getInstance(): LicenseValidator {
25
- if (!LicenseValidator.instance) {
26
- LicenseValidator.instance = new LicenseValidator();
27
- }
28
- return LicenseValidator.instance;
29
- }
30
-
31
- private initializeLicense(): void {
32
- // Check environment variables
33
- const licenseKey = process.env.MOONUI_LICENSE_KEY;
34
- const licenseEmail = process.env.MOONUI_LICENSE_EMAIL;
35
-
36
- if (licenseKey && licenseEmail) {
37
- this.licenseData = {
38
- key: licenseKey,
39
- email: licenseEmail
40
- };
41
- }
42
-
43
- // Check for license file
44
- try {
45
- const fs = require('fs');
46
- const path = require('path');
47
- const licensePath = path.join(process.cwd(), '.moonui', 'license.json');
48
-
49
- if (fs.existsSync(licensePath)) {
50
- const fileData = fs.readFileSync(licensePath, 'utf-8');
51
- this.licenseData = JSON.parse(fileData);
52
- }
53
- } catch (error) {
54
- // Ignore file reading errors in browser environment
55
- }
56
- }
57
-
58
- async validateLicense(): Promise<boolean> {
59
- if (!this.licenseData) {
60
- console.warn('[MoonUI Pro] No license found. Please run "moonui add <pro-component>" to activate your license.');
61
- return false;
62
- }
63
-
64
- // Check cache first
65
- const cacheKey = `${this.licenseData.key}-${this.licenseData.email}`;
66
- if (this.validationCache.has(cacheKey)) {
67
- return this.validationCache.get(cacheKey)!;
68
- }
69
-
70
- // Check expiration date if available
71
- if (this.licenseData.expiresAt) {
72
- const expiryDate = new Date(this.licenseData.expiresAt);
73
- if (expiryDate < new Date()) {
74
- console.error('[MoonUI Pro] License has expired. Please renew your subscription.');
75
- this.validationCache.set(cacheKey, false);
76
- return false;
77
- }
78
- }
79
-
80
- // Validate with server (with fallback for offline mode)
81
- try {
82
- const response = await fetch(this.VALIDATION_ENDPOINT, {
83
- method: 'POST',
84
- headers: {
85
- 'Content-Type': 'application/json',
86
- },
87
- body: JSON.stringify({
88
- key: this.licenseData.key,
89
- email: this.licenseData.email,
90
- }),
91
- });
92
-
93
- if (response.ok) {
94
- const result = await response.json();
95
- const isValid = result.valid === true;
96
- this.validationCache.set(cacheKey, isValid);
97
-
98
- if (!isValid) {
99
- console.error('[MoonUI Pro] Invalid license. Please check your license key and email.');
100
- }
101
-
102
- return isValid;
103
- }
104
- } catch (error) {
105
- // Fallback for offline mode or network errors
106
- // Allow usage if license format is valid
107
- const isValidFormat = this.isValidLicenseFormat();
108
- this.validationCache.set(cacheKey, isValidFormat);
109
- return isValidFormat;
110
- }
111
-
112
- return false;
113
- }
114
-
115
- private isValidLicenseFormat(): boolean {
116
- if (!this.licenseData) return false;
117
-
118
- // Basic format validation
119
- const { key, email } = this.licenseData;
120
- return (
121
- typeof key === 'string' &&
122
- key.length >= 32 &&
123
- typeof email === 'string' &&
124
- email.includes('@')
125
- );
126
- }
127
-
128
- hasFeature(feature: string): boolean {
129
- if (!this.licenseData || !this.licenseData.features) {
130
- return false;
131
- }
132
- return this.licenseData.features.includes(feature);
133
- }
134
-
135
- getLicenseInfo(): Readonly<LicenseData> | null {
136
- return this.licenseData ? { ...this.licenseData } : null;
137
- }
138
- }
139
-
140
- // Export singleton instance
141
- export const licenseValidator = LicenseValidator.getInstance();
142
-
143
- // Higher-order component for license protection
144
- export function withLicenseProtection<P extends object>(
145
- Component: React.ComponentType<P>,
146
- componentName: string
147
- ): React.ComponentType<P> {
148
- return (props: P) => {
149
- const [isValid, setIsValid] = React.useState<boolean | null>(null);
150
-
151
- React.useEffect(() => {
152
- licenseValidator.validateLicense().then(setIsValid);
153
- }, []);
154
-
155
- if (isValid === null) {
156
- // Loading state
157
- return null;
158
- }
159
-
160
- if (!isValid) {
161
- if (process.env.NODE_ENV === 'development') {
162
- console.error(
163
- `[MoonUI Pro] Component "${componentName}" requires a valid Pro license.\n` +
164
- 'Get your license at: https://moonui.dev/pricing'
165
- );
166
- }
167
-
168
- // Return a placeholder in production
169
- return (
170
- <div className="rounded-lg border-2 border-dashed border-gray-300 p-4 text-center">
171
- <p className="text-sm text-gray-500">
172
- This component requires a MoonUI Pro license.
173
- </p>
174
- </div>
175
- );
176
- }
177
-
178
- return <Component {...props} />;
179
- };
180
- }
181
-
182
- // Export React for component usage
183
- import * as React from 'react';