@moontra/moonui-pro 2.0.21 → 2.0.23

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 (97) hide show
  1. package/dist/index.mjs +771 -20
  2. package/package.json +2 -1
  3. package/src/__tests__/use-intersection-observer.test.tsx +216 -0
  4. package/src/__tests__/use-local-storage.test.tsx +174 -0
  5. package/src/__tests__/use-pro-access.test.tsx +183 -0
  6. package/src/components/advanced-chart/advanced-chart.test.tsx +281 -0
  7. package/src/components/advanced-chart/index.tsx +412 -0
  8. package/src/components/advanced-forms/index.tsx +431 -0
  9. package/src/components/animated-button/index.tsx +202 -0
  10. package/src/components/calendar/event-dialog.tsx +372 -0
  11. package/src/components/calendar/index.tsx +531 -0
  12. package/src/components/color-picker/index.tsx +434 -0
  13. package/src/components/dashboard/index.tsx +334 -0
  14. package/src/components/data-table/data-table.test.tsx +187 -0
  15. package/src/components/data-table/index.tsx +368 -0
  16. package/src/components/draggable-list/index.tsx +100 -0
  17. package/src/components/enhanced/button.tsx +360 -0
  18. package/src/components/enhanced/card.tsx +272 -0
  19. package/src/components/enhanced/dialog.tsx +248 -0
  20. package/src/components/enhanced/index.ts +3 -0
  21. package/src/components/error-boundary/index.tsx +111 -0
  22. package/src/components/file-upload/file-upload.test.tsx +242 -0
  23. package/src/components/file-upload/index.tsx +362 -0
  24. package/src/components/floating-action-button/index.tsx +209 -0
  25. package/src/components/github-stars/index.tsx +414 -0
  26. package/src/components/health-check/index.tsx +441 -0
  27. package/src/components/hover-card-3d/index.tsx +170 -0
  28. package/src/components/index.ts +76 -0
  29. package/src/components/kanban/index.tsx +436 -0
  30. package/src/components/lazy-component/index.tsx +342 -0
  31. package/src/components/magnetic-button/index.tsx +170 -0
  32. package/src/components/memory-efficient-data/index.tsx +352 -0
  33. package/src/components/optimized-image/index.tsx +427 -0
  34. package/src/components/performance-debugger/index.tsx +591 -0
  35. package/src/components/performance-monitor/index.tsx +775 -0
  36. package/src/components/pinch-zoom/index.tsx +172 -0
  37. package/src/components/rich-text-editor/index-old-backup.tsx +443 -0
  38. package/src/components/rich-text-editor/index.tsx +1537 -0
  39. package/src/components/rich-text-editor/slash-commands-extension.ts +220 -0
  40. package/src/components/rich-text-editor/slash-commands.css +35 -0
  41. package/src/components/rich-text-editor/table-styles.css +65 -0
  42. package/src/components/spotlight-card/index.tsx +194 -0
  43. package/src/components/swipeable-card/index.tsx +100 -0
  44. package/src/components/timeline/index.tsx +333 -0
  45. package/src/components/ui/animated-button.tsx +185 -0
  46. package/src/components/ui/avatar.tsx +135 -0
  47. package/src/components/ui/badge.tsx +225 -0
  48. package/src/components/ui/button.tsx +221 -0
  49. package/src/components/ui/card.tsx +141 -0
  50. package/src/components/ui/checkbox.tsx +256 -0
  51. package/src/components/ui/color-picker.tsx +95 -0
  52. package/src/components/ui/dialog.tsx +332 -0
  53. package/src/components/ui/dropdown-menu.tsx +200 -0
  54. package/src/components/ui/hover-card-3d.tsx +103 -0
  55. package/src/components/ui/index.ts +33 -0
  56. package/src/components/ui/input.tsx +219 -0
  57. package/src/components/ui/label.tsx +26 -0
  58. package/src/components/ui/magnetic-button.tsx +129 -0
  59. package/src/components/ui/popover.tsx +183 -0
  60. package/src/components/ui/select.tsx +273 -0
  61. package/src/components/ui/separator.tsx +140 -0
  62. package/src/components/ui/slider.tsx +351 -0
  63. package/src/components/ui/spotlight-card.tsx +119 -0
  64. package/src/components/ui/switch.tsx +83 -0
  65. package/src/components/ui/tabs.tsx +195 -0
  66. package/src/components/ui/textarea.tsx +25 -0
  67. package/src/components/ui/toast.tsx +313 -0
  68. package/src/components/ui/tooltip.tsx +152 -0
  69. package/src/components/virtual-list/index.tsx +369 -0
  70. package/src/hooks/use-chart.ts +205 -0
  71. package/src/hooks/use-data-table.ts +182 -0
  72. package/src/hooks/use-docs-pro-access.ts +13 -0
  73. package/src/hooks/use-license-check.ts +65 -0
  74. package/src/hooks/use-subscription.ts +19 -0
  75. package/src/index.ts +11 -0
  76. package/src/lib/micro-interactions.ts +255 -0
  77. package/src/lib/utils.ts +6 -0
  78. package/src/patterns/login-form/index.tsx +276 -0
  79. package/src/patterns/login-form/types.ts +67 -0
  80. package/src/setupTests.ts +41 -0
  81. package/src/styles/design-system.css +365 -0
  82. package/src/styles/index.css +4 -0
  83. package/src/styles/tailwind.css +6 -0
  84. package/src/styles/tokens.css +453 -0
  85. package/src/types/moonui.d.ts +22 -0
  86. package/src/use-intersection-observer.tsx +154 -0
  87. package/src/use-local-storage.tsx +71 -0
  88. package/src/use-paddle.ts +138 -0
  89. package/src/use-performance-optimizer.ts +379 -0
  90. package/src/use-pro-access.ts +141 -0
  91. package/src/use-scroll-animation.ts +221 -0
  92. package/src/use-subscription.ts +37 -0
  93. package/src/use-toast.ts +32 -0
  94. package/src/utils/chart-helpers.ts +257 -0
  95. package/src/utils/cn.ts +69 -0
  96. package/src/utils/data-processing.ts +151 -0
  97. package/src/utils/license-validator.tsx +183 -0
@@ -0,0 +1,151 @@
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
@@ -0,0 +1,183 @@
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';