@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.
- package/dist/index.d.ts +691 -261
- package/dist/index.mjs +7418 -4934
- package/package.json +11 -5
- package/plugin/index.d.ts +86 -0
- package/plugin/index.js +308 -0
- package/scripts/postbuild.js +27 -0
- package/scripts/postinstall.js +176 -23
- package/src/__tests__/use-intersection-observer.test.tsx +0 -216
- package/src/__tests__/use-local-storage.test.tsx +0 -174
- package/src/__tests__/use-pro-access.test.tsx +0 -183
- package/src/components/advanced-chart/advanced-chart.test.tsx +0 -281
- package/src/components/advanced-chart/index.tsx +0 -1242
- package/src/components/advanced-forms/index.tsx +0 -426
- package/src/components/animated-button/index.tsx +0 -385
- package/src/components/calendar/event-dialog.tsx +0 -372
- package/src/components/calendar/index.tsx +0 -1073
- package/src/components/calendar-pro/index.tsx +0 -1697
- package/src/components/color-picker/index.tsx +0 -432
- package/src/components/credit-card-input/index.tsx +0 -406
- package/src/components/dashboard/dashboard-grid.tsx +0 -462
- package/src/components/dashboard/demo.tsx +0 -425
- package/src/components/dashboard/index.tsx +0 -1046
- package/src/components/dashboard/time-range-picker.tsx +0 -336
- package/src/components/dashboard/types.ts +0 -222
- package/src/components/dashboard/widgets/activity-feed.tsx +0 -344
- package/src/components/dashboard/widgets/chart-widget.tsx +0 -418
- package/src/components/dashboard/widgets/metric-card.tsx +0 -343
- package/src/components/data-table/data-table-bulk-actions.tsx +0 -204
- package/src/components/data-table/data-table-column-toggle.tsx +0 -169
- package/src/components/data-table/data-table-export.ts +0 -156
- package/src/components/data-table/data-table-filter-drawer.tsx +0 -448
- package/src/components/data-table/data-table.test.tsx +0 -187
- package/src/components/data-table/index.tsx +0 -845
- package/src/components/draggable-list/index.tsx +0 -100
- package/src/components/enhanced/badge.tsx +0 -191
- package/src/components/enhanced/button.tsx +0 -362
- package/src/components/enhanced/card.tsx +0 -266
- package/src/components/enhanced/dialog.tsx +0 -246
- package/src/components/enhanced/index.ts +0 -4
- package/src/components/error-boundary/index.tsx +0 -109
- package/src/components/file-upload/file-upload.test.tsx +0 -243
- package/src/components/file-upload/index.tsx +0 -1660
- package/src/components/floating-action-button/index.tsx +0 -206
- package/src/components/form-wizard/form-wizard-context.tsx +0 -307
- package/src/components/form-wizard/form-wizard-navigation.tsx +0 -118
- package/src/components/form-wizard/form-wizard-progress.tsx +0 -298
- package/src/components/form-wizard/form-wizard-step.tsx +0 -111
- package/src/components/form-wizard/index.tsx +0 -102
- package/src/components/form-wizard/types.ts +0 -76
- package/src/components/gesture-drawer/index.tsx +0 -551
- package/src/components/github-stars/github-api.ts +0 -426
- package/src/components/github-stars/hooks.ts +0 -516
- package/src/components/github-stars/index.tsx +0 -375
- package/src/components/github-stars/types.ts +0 -148
- package/src/components/github-stars/variants.tsx +0 -513
- package/src/components/health-check/index.tsx +0 -439
- package/src/components/hover-card-3d/index.tsx +0 -530
- package/src/components/index.ts +0 -128
- package/src/components/internal/index.ts +0 -78
- package/src/components/kanban/add-card-modal.tsx +0 -502
- package/src/components/kanban/card-detail-modal.tsx +0 -761
- package/src/components/kanban/index.ts +0 -13
- package/src/components/kanban/kanban.tsx +0 -1684
- package/src/components/kanban/types.ts +0 -168
- package/src/components/lazy-component/index.tsx +0 -823
- package/src/components/license-error/index.tsx +0 -29
- package/src/components/magnetic-button/index.tsx +0 -167
- package/src/components/memory-efficient-data/index.tsx +0 -1016
- package/src/components/moonui-quiz-form/index.tsx +0 -817
- package/src/components/optimized-image/index.tsx +0 -425
- package/src/components/performance-debugger/index.tsx +0 -589
- package/src/components/performance-monitor/index.tsx +0 -794
- package/src/components/phone-number-input/index.tsx +0 -338
- package/src/components/pinch-zoom/index.tsx +0 -566
- package/src/components/quiz-form/index.tsx +0 -479
- package/src/components/rich-text-editor/index-old-backup.tsx +0 -437
- package/src/components/rich-text-editor/index.tsx +0 -2324
- package/src/components/rich-text-editor/slash-commands-extension.ts +0 -220
- package/src/components/rich-text-editor/slash-commands.css +0 -35
- package/src/components/rich-text-editor/table-styles.css +0 -65
- package/src/components/sidebar/index.tsx +0 -865
- package/src/components/spotlight-card/index.tsx +0 -191
- package/src/components/swipeable-card/index.tsx +0 -100
- package/src/components/timeline/index.tsx +0 -1148
- package/src/components/ui/accordion.tsx +0 -73
- package/src/components/ui/alert-dialog.tsx +0 -141
- package/src/components/ui/alert.tsx +0 -141
- package/src/components/ui/aspect-ratio.tsx +0 -245
- package/src/components/ui/avatar.tsx +0 -153
- package/src/components/ui/badge.tsx +0 -228
- package/src/components/ui/breadcrumb.tsx +0 -214
- package/src/components/ui/button.tsx +0 -222
- package/src/components/ui/calendar.tsx +0 -387
- package/src/components/ui/card.tsx +0 -214
- package/src/components/ui/checkbox.tsx +0 -259
- package/src/components/ui/collapsible.tsx +0 -135
- package/src/components/ui/color-picker.tsx +0 -97
- package/src/components/ui/command.tsx +0 -225
- package/src/components/ui/dialog.tsx +0 -334
- package/src/components/ui/dropdown-menu.tsx +0 -218
- package/src/components/ui/gesture-drawer.tsx +0 -11
- package/src/components/ui/hover-card.tsx +0 -29
- package/src/components/ui/index.ts +0 -190
- package/src/components/ui/input.tsx +0 -222
- package/src/components/ui/label.tsx +0 -29
- package/src/components/ui/lightbox.tsx +0 -606
- package/src/components/ui/magnetic-button.tsx +0 -129
- package/src/components/ui/media-gallery.tsx +0 -612
- package/src/components/ui/pagination.tsx +0 -123
- package/src/components/ui/popover.tsx +0 -185
- package/src/components/ui/progress.tsx +0 -30
- package/src/components/ui/radio-group.tsx +0 -257
- package/src/components/ui/scroll-area.tsx +0 -47
- package/src/components/ui/select.tsx +0 -374
- package/src/components/ui/separator.tsx +0 -145
- package/src/components/ui/sheet.tsx +0 -139
- package/src/components/ui/skeleton.tsx +0 -20
- package/src/components/ui/slider.tsx +0 -354
- package/src/components/ui/spotlight-card.tsx +0 -119
- package/src/components/ui/switch.tsx +0 -86
- package/src/components/ui/table.tsx +0 -329
- package/src/components/ui/tabs.tsx +0 -198
- package/src/components/ui/textarea.tsx +0 -28
- package/src/components/ui/toast.tsx +0 -317
- package/src/components/ui/toggle.tsx +0 -119
- package/src/components/ui/tooltip.tsx +0 -151
- package/src/components/virtual-list/index.tsx +0 -668
- package/src/hooks/use-chart.ts +0 -205
- package/src/hooks/use-data-table.ts +0 -182
- package/src/hooks/use-docs-pro-access.ts +0 -13
- package/src/hooks/use-license-check.ts +0 -65
- package/src/hooks/use-subscription.ts +0 -19
- package/src/hooks/use-toast.ts +0 -15
- package/src/index.ts +0 -14
- package/src/lib/ai-providers.ts +0 -377
- package/src/lib/component-metadata.ts +0 -18
- package/src/lib/micro-interactions.ts +0 -255
- package/src/lib/paddle.ts +0 -17
- package/src/lib/utils.ts +0 -6
- package/src/patterns/login-form/index.tsx +0 -276
- package/src/patterns/login-form/types.ts +0 -67
- package/src/setupTests.ts +0 -41
- package/src/styles/advanced-chart.css +0 -239
- package/src/styles/calendar.css +0 -35
- package/src/styles/design-system.css +0 -363
- package/src/styles/index.css +0 -85
- package/src/styles/tailwind.css +0 -7
- package/src/styles/tokens.css +0 -455
- package/src/types/moonui.d.ts +0 -22
- package/src/types/next-auth.d.ts +0 -21
- package/src/use-intersection-observer.tsx +0 -154
- package/src/use-local-storage.tsx +0 -71
- package/src/use-paddle.ts +0 -138
- package/src/use-performance-optimizer.ts +0 -389
- package/src/use-pro-access.ts +0 -141
- package/src/use-scroll-animation.ts +0 -219
- package/src/use-subscription.ts +0 -37
- package/src/use-toast.ts +0 -32
- package/src/utils/chart-helpers.ts +0 -357
- package/src/utils/cn.ts +0 -6
- package/src/utils/data-processing.ts +0 -151
- 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,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';
|