@moontra/moonui-pro 2.1.0 → 2.1.1

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 (49) hide show
  1. package/dist/index.d.ts +790 -0
  2. package/dist/index.mjs +758 -326
  3. package/package.json +2 -3
  4. package/scripts/postinstall.js +144 -66
  5. package/src/components/advanced-chart/index.tsx +3 -3
  6. package/src/components/advanced-forms/index.tsx +4 -9
  7. package/src/components/animated-button/index.tsx +4 -8
  8. package/src/components/calendar/index.tsx +2 -28
  9. package/src/components/color-picker/index.tsx +2 -4
  10. package/src/components/dashboard/index.tsx +3 -3
  11. package/src/components/data-table/index.tsx +5 -8
  12. package/src/components/enhanced/badge.tsx +191 -0
  13. package/src/components/enhanced/button.tsx +7 -5
  14. package/src/components/enhanced/card.tsx +11 -17
  15. package/src/components/enhanced/dialog.tsx +26 -28
  16. package/src/components/enhanced/index.ts +2 -1
  17. package/src/components/error-boundary/index.tsx +2 -4
  18. package/src/components/file-upload/index.tsx +3 -5
  19. package/src/components/floating-action-button/index.tsx +1 -4
  20. package/src/components/github-stars/index.tsx +4 -6
  21. package/src/components/health-check/index.tsx +5 -7
  22. package/src/components/hover-card-3d/index.tsx +3 -6
  23. package/src/components/kanban/index.tsx +4 -6
  24. package/src/components/lazy-component/index.tsx +4 -7
  25. package/src/components/magnetic-button/index.tsx +3 -6
  26. package/src/components/memory-efficient-data/index.tsx +6 -6
  27. package/src/components/optimized-image/index.tsx +4 -6
  28. package/src/components/performance-debugger/index.tsx +8 -10
  29. package/src/components/performance-monitor/index.tsx +37 -18
  30. package/src/components/pinch-zoom/index.tsx +2 -4
  31. package/src/components/rich-text-editor/index-old-backup.tsx +3 -9
  32. package/src/components/rich-text-editor/index.tsx +75 -10
  33. package/src/components/rich-text-editor/slash-commands-extension.ts +1 -1
  34. package/src/components/spotlight-card/index.tsx +1 -4
  35. package/src/components/swipeable-card/index.tsx +1 -1
  36. package/src/components/timeline/index.tsx +2 -2
  37. package/src/components/ui/color-picker.tsx +1 -1
  38. package/src/components/ui/index.ts +2 -0
  39. package/src/components/ui/progress.tsx +27 -0
  40. package/src/components/ui/skeleton.tsx +17 -0
  41. package/src/components/ui/tooltip.tsx +1 -1
  42. package/src/components/virtual-list/index.tsx +3 -4
  43. package/src/hooks/use-chart.ts +2 -2
  44. package/src/index.ts +0 -3
  45. package/src/patterns/login-form/types.ts +6 -6
  46. package/src/use-pro-access.ts +2 -2
  47. package/src/utils/chart-helpers.ts +1 -1
  48. package/src/utils/license-guard.tsx +0 -177
  49. package/src/utils/package-guard.ts +0 -60
@@ -97,28 +97,77 @@ import { toast } from '../ui/toast';
97
97
  // Note: AI providers should be handled by consuming application
98
98
 
99
99
  // Type definitions for AI functionality
100
- type AIProvider = 'openai' | 'anthropic' | 'gemini'
100
+ type AIProvider = 'openai' | 'anthropic' | 'gemini' | 'claude' | 'cohere'
101
101
 
102
102
  interface AISettingsType {
103
103
  provider: AIProvider
104
104
  apiKey?: string
105
105
  model?: string
106
+ temperature?: number
106
107
  maxTokens?: number
107
108
  }
108
109
 
109
110
  interface SlashCommand {
110
- title: string
111
+ id?: string
112
+ title?: string
111
113
  description: string
112
114
  command: string
113
- action: () => void
115
+ icon?: string
116
+ action: (text: string) => Promise<{ text: string; error?: string }> | void
114
117
  }
115
118
 
116
119
  // Mock AI provider function
117
120
  const getAIProvider = (settings: AISettingsType) => {
121
+ const generateWithPrompt = async (systemPrompt: string, userText: string) => {
122
+ // Mock implementation - consuming app should provide real AI integration
123
+ const result = `[${systemPrompt}] ${userText}`
124
+ return { text: result, error: undefined }
125
+ }
126
+
118
127
  return {
119
128
  generateText: async (prompt: string) => {
120
- // Mock implementation - consuming app should provide real AI integration
121
- return 'AI functionality requires proper API configuration'
129
+ const result = await generateWithPrompt('Generate text', prompt)
130
+ return result.text
131
+ },
132
+ rewrite: async (text: string) => {
133
+ const result = await generateWithPrompt('Rewrite this text', text)
134
+ return result
135
+ },
136
+ expand: async (text: string) => {
137
+ const result = await generateWithPrompt('Expand this text', text)
138
+ return result
139
+ },
140
+ summarize: async (text: string) => {
141
+ const result = await generateWithPrompt('Summarize this text', text)
142
+ return result
143
+ },
144
+ fixGrammar: async (text: string) => {
145
+ const result = await generateWithPrompt('Fix grammar and spelling', text)
146
+ return result
147
+ },
148
+ translate: async (text: string, targetLang: string) => {
149
+ const result = await generateWithPrompt(`Translate to ${targetLang}`, text)
150
+ return result
151
+ },
152
+ changeTone: async (text: string, tone: string) => {
153
+ const result = await generateWithPrompt(`Change tone to ${tone}`, text)
154
+ return result
155
+ },
156
+ continueWriting: async (text: string) => {
157
+ const result = await generateWithPrompt('Continue writing', text)
158
+ return result
159
+ },
160
+ improveWriting: async (text: string) => {
161
+ const result = await generateWithPrompt('Improve writing quality', text)
162
+ return result
163
+ },
164
+ generateIdeas: async (text: string) => {
165
+ const result = await generateWithPrompt('Generate writing ideas', text)
166
+ return result
167
+ },
168
+ complete: async (text: string) => {
169
+ const result = await generateWithPrompt('Complete this text', text)
170
+ return result
122
171
  }
123
172
  }
124
173
  }
@@ -255,14 +304,12 @@ export function RichTextEditor({
255
304
  },
256
305
  }: RichTextEditorProps) {
257
306
  // Pro access kontrolü
258
- const docsProAccess = { hasAccess: true }; // Pro access assumed in package
259
307
  const { hasProAccess, isLoading } = useSubscription();
260
308
 
261
309
  // In docs mode, always show the component
262
- const canShowComponent = docsProAccess.isDocsMode || hasProAccess;
263
310
 
264
311
  // If not in docs mode and no pro access, show upgrade prompt
265
- if (!docsProAccess.isDocsMode && !isLoading && !hasProAccess) {
312
+ if (!isLoading && !hasProAccess) {
266
313
  return (
267
314
  <Card className={cn("w-full", className)}>
268
315
  <CardContent className="py-12 text-center">
@@ -548,10 +595,10 @@ export function RichTextEditor({
548
595
  response = await provider.improveWriting(text);
549
596
  break;
550
597
  case 'ideas':
551
- response = await provider.generateIdeas(text, 5);
598
+ response = await provider.generateIdeas(text);
552
599
  break;
553
600
  default:
554
- response = await provider.complete(action, text);
601
+ response = await provider.complete(text);
555
602
  }
556
603
 
557
604
  if (response.error) {
@@ -938,6 +985,16 @@ export function RichTextEditor({
938
985
  <DialogTrigger asChild>
939
986
  <ToolbarButton
940
987
  active={editor.isActive('link')}
988
+ onClick={() => {
989
+ const previousUrl = editor.getAttributes('link').href
990
+ const url = window.prompt('URL', previousUrl)
991
+ if (url === null) return
992
+ if (url === '') {
993
+ editor.chain().focus().extendMarkRange('link').unsetLink().run()
994
+ } else {
995
+ editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run()
996
+ }
997
+ }}
941
998
  tooltip="Add link"
942
999
  disabled={isSourceView}
943
1000
  >
@@ -994,6 +1051,12 @@ export function RichTextEditor({
994
1051
  <Dialog open={isImageDialogOpen} onOpenChange={setIsImageDialogOpen}>
995
1052
  <DialogTrigger asChild>
996
1053
  <ToolbarButton
1054
+ onClick={() => {
1055
+ const url = window.prompt('Image URL')
1056
+ if (url) {
1057
+ editor.chain().focus().setImage({ src: url }).run()
1058
+ }
1059
+ }}
997
1060
  tooltip="Add image"
998
1061
  disabled={isSourceView}
999
1062
  >
@@ -1038,6 +1101,7 @@ export function RichTextEditor({
1038
1101
  <Dialog open={isTableDialogOpen} onOpenChange={setIsTableDialogOpen}>
1039
1102
  <DialogTrigger asChild>
1040
1103
  <ToolbarButton
1104
+ onClick={() => editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run()}
1041
1105
  tooltip="Create table"
1042
1106
  disabled={isSourceView}
1043
1107
  >
@@ -1255,6 +1319,7 @@ export function RichTextEditor({
1255
1319
  <Dialog open={isAiSettingsOpen} onOpenChange={setIsAiSettingsOpen}>
1256
1320
  <DialogTrigger asChild>
1257
1321
  <ToolbarButton
1322
+ onClick={() => setIsAiSettingsOpen(true)}
1258
1323
  tooltip="AI Settings - Configure your API keys here"
1259
1324
  disabled={isSourceView}
1260
1325
  >
@@ -11,7 +11,7 @@ declare module '@tiptap/core' {
11
11
  }
12
12
  }
13
13
 
14
- export interface SlashCommandsOptions {
14
+ interface SlashCommandsOptions {
15
15
  commands: SlashCommand[];
16
16
  onSelectCommand: (command: SlashCommand) => void;
17
17
  }
@@ -66,7 +66,6 @@ const SpotlightCardInternal = React.forwardRef<HTMLDivElement, SpotlightCardProp
66
66
  onMouseLeave={handleMouseLeave}
67
67
  whileHover={{ scale: 1.02 }}
68
68
  transition={{ duration: 0.2 }}
69
- {...props}
70
69
  >
71
70
  {/* Spotlight effect */}
72
71
  <motion.div
@@ -154,14 +153,12 @@ SpotlightCardInternal.displayName = "SpotlightCardInternal"
154
153
  export const SpotlightCard = React.forwardRef<HTMLDivElement, SpotlightCardProps>(
155
154
  ({ className, ...props }, ref) => {
156
155
  // Check if we're in docs mode or have pro access
157
- const docsProAccess = { hasAccess: true } // Pro access assumed in package
158
156
  const { hasProAccess, isLoading } = useSubscription()
159
157
 
160
158
  // In docs mode, always show the component
161
- const canShowComponent = docsProAccess.isDocsMode || hasProAccess
162
159
 
163
160
  // If not in docs mode and no pro access, show upgrade prompt
164
- if (!docsProAccess.isDocsMode && !isLoading && !hasProAccess) {
161
+ if (!isLoading && !hasProAccess) {
165
162
  return (
166
163
  <Card className={cn("w-fit", className)}>
167
164
  <CardContent className="py-6 text-center">
@@ -4,7 +4,7 @@ import React, { ReactNode } from "react"
4
4
  import { motion, useMotionValue, useTransform, animate, PanInfo } from "framer-motion"
5
5
  import { cn } from "../../lib/utils"
6
6
 
7
- export interface SwipeableCardProps {
7
+ interface SwipeableCardProps {
8
8
  children: ReactNode
9
9
  onSwipeLeft?: () => void
10
10
  onSwipeRight?: () => void
@@ -21,7 +21,7 @@ import {
21
21
  } from 'lucide-react'
22
22
  import { cn } from '@moontra/moonui'
23
23
 
24
- export interface TimelineEvent {
24
+ interface TimelineEvent {
25
25
  id: string
26
26
  title: string
27
27
  description?: string
@@ -44,7 +44,7 @@ export interface TimelineEvent {
44
44
  color?: string
45
45
  }
46
46
 
47
- export interface TimelineProps {
47
+ interface TimelineProps {
48
48
  events: TimelineEvent[]
49
49
  onEventClick?: (event: TimelineEvent) => void
50
50
  className?: string
@@ -3,7 +3,7 @@
3
3
  import React, { useState } from "react"
4
4
  import { cn } from "../../lib/utils"
5
5
 
6
- export interface ColorPickerProps {
6
+ interface ColorPickerProps {
7
7
  value?: string
8
8
  onChange?: (color: string) => void
9
9
  className?: string
@@ -18,6 +18,8 @@ export * from './switch';
18
18
  export * from './checkbox';
19
19
  export * from './color-picker';
20
20
  export * from './textarea';
21
+ export * from './skeleton';
22
+ export * from './progress';
21
23
 
22
24
  // Micro-interaction Components
23
25
  export { AnimatedButton, animatedButtonVariants } from "./animated-button";
@@ -0,0 +1,27 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as ProgressPrimitive from "@radix-ui/react-progress"
5
+ import { cn } from "../../lib/utils"
6
+
7
+ const Progress = React.forwardRef<
8
+ React.ElementRef<typeof ProgressPrimitive.Root>,
9
+ React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
10
+ >(({ className, value, ...props }, ref) => (
11
+ <ProgressPrimitive.Root
12
+ ref={ref}
13
+ className={cn(
14
+ "relative h-4 w-full overflow-hidden rounded-full bg-secondary",
15
+ className
16
+ )}
17
+ {...props}
18
+ >
19
+ <ProgressPrimitive.Indicator
20
+ className="h-full w-full flex-1 bg-primary transition-all"
21
+ style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
22
+ />
23
+ </ProgressPrimitive.Root>
24
+ ))
25
+ Progress.displayName = ProgressPrimitive.Root.displayName
26
+
27
+ export { Progress }
@@ -0,0 +1,17 @@
1
+ "use client"
2
+
3
+ import { cn } from "../../lib/utils"
4
+
5
+ interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {}
6
+
7
+ export function Skeleton({
8
+ className,
9
+ ...props
10
+ }: SkeletonProps) {
11
+ return (
12
+ <div
13
+ className={cn("animate-pulse rounded-md bg-muted", className)}
14
+ {...props}
15
+ />
16
+ )
17
+ }
@@ -72,7 +72,7 @@ const TooltipContent = React.forwardRef<
72
72
  TooltipContent.displayName = TooltipPrimitive.Content.displayName
73
73
 
74
74
  // Simplified Tooltip component for easy usage
75
- export interface SimpleTooltipProps {
75
+ interface SimpleTooltipProps {
76
76
  children: React.ReactElement
77
77
  content: React.ReactNode
78
78
  variant?: TooltipContentProps["variant"]
@@ -43,8 +43,8 @@ export function VirtualList<T = any>({
43
43
  // Refs
44
44
  const containerRef = useRef<HTMLDivElement>(null)
45
45
  const scrollElementRef = useRef<HTMLDivElement>(null)
46
- const scrollTimeoutRef = useRef<NodeJS.Timeout>()
47
- const isScrollingTimeoutRef = useRef<NodeJS.Timeout>()
46
+ const scrollTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined)
47
+ const isScrollingTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined)
48
48
 
49
49
  // Item pozisyonlarını hesapla
50
50
  const itemPositions = useMemo(() => {
@@ -365,5 +365,4 @@ export function SelectableVirtualList<T = any>({
365
365
  return <VirtualList {...props} renderItem={renderItem} />
366
366
  }
367
367
 
368
- // Export types
369
- export type { VirtualListProps, SelectableVirtualListProps }
368
+ // Export types
@@ -3,7 +3,7 @@
3
3
  import React from 'react'
4
4
  import { ChartDataPoint, ChartSeries } from '../components/advanced-chart'
5
5
 
6
- export interface UseChartOptions {
6
+ interface UseChartOptions {
7
7
  data: ChartDataPoint[]
8
8
  series: ChartSeries[]
9
9
  realtime?: boolean
@@ -11,7 +11,7 @@ export interface UseChartOptions {
11
11
  maxDataPoints?: number
12
12
  }
13
13
 
14
- export interface UseChartReturn {
14
+ interface UseChartReturn {
15
15
  data: ChartDataPoint[]
16
16
  series: ChartSeries[]
17
17
  isLoading: boolean
package/src/index.ts CHANGED
@@ -1,9 +1,6 @@
1
1
  // Pro Components Export - Source of Truth: packages/moonui-pro
2
2
  // Development environment imports from local packages
3
3
 
4
- // Package access guard - ensures CLI usage
5
- import "./utils/package-guard"
6
-
7
4
  // Import CSS for auto-loading
8
5
  import "./styles/index.css"
9
6
 
@@ -1,4 +1,4 @@
1
- export interface LoginFormTheme {
1
+ interface LoginFormTheme {
2
2
  primary?: string
3
3
  secondary?: string
4
4
  background?: string
@@ -7,7 +7,7 @@ export interface LoginFormTheme {
7
7
  spacing?: 'compact' | 'normal' | 'relaxed'
8
8
  }
9
9
 
10
- export interface LoginFormFeatures {
10
+ interface LoginFormFeatures {
11
11
  socialLogin?: boolean | string[]
12
12
  rememberMe?: boolean
13
13
  forgotPassword?: boolean
@@ -15,7 +15,7 @@ export interface LoginFormFeatures {
15
15
  passwordStrength?: boolean
16
16
  }
17
17
 
18
- export interface LoginFormTexts {
18
+ interface LoginFormTexts {
19
19
  title?: string
20
20
  subtitle?: string
21
21
  emailLabel?: string
@@ -27,18 +27,18 @@ export interface LoginFormTexts {
27
27
  orContinueWith?: string
28
28
  }
29
29
 
30
- export interface LoginData {
30
+ interface LoginData {
31
31
  email: string
32
32
  password: string
33
33
  rememberMe?: boolean
34
34
  }
35
35
 
36
- export interface ValidationRules {
36
+ interface ValidationRules {
37
37
  email?: (value: string) => string | null
38
38
  password?: (value: string) => string | null
39
39
  }
40
40
 
41
- export interface LoginFormProps {
41
+ interface LoginFormProps {
42
42
  // Stil özelleştirme
43
43
  theme?: LoginFormTheme
44
44
  className?: string
@@ -6,7 +6,7 @@ import { useSession } from 'next-auth/react'
6
6
  import { useQuery } from '@tanstack/react-query'
7
7
  import { getComponentAccess } from '@/lib/component-metadata'
8
8
 
9
- export interface UserSubscription {
9
+ interface UserSubscription {
10
10
  userId: string
11
11
  plan: 'free' | 'pro_monthly' | 'pro_annual' | 'pro_lifetime'
12
12
  status: 'active' | 'expired' | 'cancelled' | 'trial'
@@ -15,7 +15,7 @@ export interface UserSubscription {
15
15
  updatedAt: Date
16
16
  }
17
17
 
18
- export interface ProAccessStatus {
18
+ interface ProAccessStatus {
19
19
  hasProAccess: boolean
20
20
  subscription: UserSubscription | null | undefined
21
21
  isLoading: boolean
@@ -1,6 +1,6 @@
1
1
  import { ChartDataPoint, ChartSeries } from '../components/advanced-chart'
2
2
 
3
- export interface ChartTheme {
3
+ interface ChartTheme {
4
4
  colors: string[]
5
5
  backgroundColor: string
6
6
  textColor: string
@@ -1,177 +0,0 @@
1
- "use client"
2
-
3
- import React, { useEffect, useState } from 'react';
4
-
5
- const API_BASE = process.env.NEXT_PUBLIC_MOONUI_API || 'https://moonui.dev';
6
-
7
- interface LicenseCheckResult {
8
- valid: boolean;
9
- error?: string;
10
- loading: boolean;
11
- }
12
-
13
- // In-memory cache for license check
14
- let licenseCache: {
15
- result: boolean;
16
- timestamp: number;
17
- } | null = null;
18
-
19
- const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
20
-
21
- export function useLicenseCheck(): LicenseCheckResult {
22
- const [state, setState] = useState<LicenseCheckResult>({
23
- valid: false,
24
- loading: true,
25
- error: undefined
26
- });
27
-
28
- useEffect(() => {
29
- checkLicense().then(result => {
30
- setState({
31
- valid: result.valid,
32
- loading: false,
33
- error: result.error
34
- });
35
- });
36
- }, []);
37
-
38
- return state;
39
- }
40
-
41
- async function checkLicense(): Promise<{ valid: boolean; error?: string }> {
42
- // Check cache first
43
- if (licenseCache && Date.now() - licenseCache.timestamp < CACHE_DURATION) {
44
- return { valid: licenseCache.result };
45
- }
46
-
47
- try {
48
- // Get auth token from localStorage or cookie
49
- const token = getAuthToken();
50
-
51
- if (!token) {
52
- return { valid: false, error: 'No authentication token found' };
53
- }
54
-
55
- const response = await fetch(`${API_BASE}/api/license/verify`, {
56
- method: 'POST',
57
- headers: {
58
- 'Authorization': `Bearer ${token}`,
59
- 'Content-Type': 'application/json'
60
- },
61
- body: JSON.stringify({
62
- component: 'runtime-check',
63
- source: 'moonui-pro'
64
- })
65
- });
66
-
67
- if (!response.ok) {
68
- return { valid: false, error: 'License verification failed' };
69
- }
70
-
71
- const data = await response.json();
72
-
73
- // Cache the result
74
- licenseCache = {
75
- result: data.valid && data.planType !== 'free',
76
- timestamp: Date.now()
77
- };
78
-
79
- return { valid: licenseCache.result };
80
- } catch (error) {
81
- return { valid: false, error: 'Network error during license check' };
82
- }
83
- }
84
-
85
- function getAuthToken(): string | null {
86
- // First check localStorage (for client-side)
87
- if (typeof window !== 'undefined') {
88
- const stored = localStorage.getItem('moonui_auth');
89
- if (stored) {
90
- try {
91
- const auth = JSON.parse(stored);
92
- return auth.accessToken;
93
- } catch {
94
- // Invalid JSON
95
- }
96
- }
97
- }
98
-
99
- // Check cookies (for SSR)
100
- if (typeof document !== 'undefined') {
101
- const cookies = document.cookie.split(';');
102
- for (const cookie of cookies) {
103
- const [name, value] = cookie.trim().split('=');
104
- if (name === 'moonui_token') {
105
- return decodeURIComponent(value);
106
- }
107
- }
108
- }
109
-
110
- return null;
111
- }
112
-
113
- // License Guard HOC
114
- export function withLicenseGuard<P extends object>(
115
- Component: React.ComponentType<P>,
116
- options?: {
117
- fallback?: React.ReactNode;
118
- onUnauthorized?: () => void;
119
- }
120
- ) {
121
- return function LicenseGuardedComponent(props: P) {
122
- const { valid, loading, error } = useLicenseCheck();
123
-
124
- useEffect(() => {
125
- if (!loading && !valid && options?.onUnauthorized) {
126
- options.onUnauthorized();
127
- }
128
- }, [loading, valid]);
129
-
130
- if (loading) {
131
- return (
132
- <div className="flex items-center justify-center p-8">
133
- <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"></div>
134
- </div>
135
- );
136
- }
137
-
138
- if (!valid) {
139
- if (options?.fallback) {
140
- return <>{options.fallback}</>;
141
- }
142
-
143
- return (
144
- <div className="rounded-lg border border-red-200 bg-red-50 p-8 text-center">
145
- <h3 className="text-lg font-semibold text-red-900 mb-2">
146
- Pro License Required
147
- </h3>
148
- <p className="text-red-700 mb-4">
149
- This component requires a MoonUI Pro license.
150
- </p>
151
- <a
152
- href="https://moonui.dev/pricing"
153
- className="inline-flex items-center justify-center rounded-md bg-red-600 px-4 py-2 text-sm font-medium text-white hover:bg-red-700"
154
- >
155
- Get Pro License
156
- </a>
157
- {error && (
158
- <p className="text-xs text-red-600 mt-4">
159
- Error: {error}
160
- </p>
161
- )}
162
- </div>
163
- );
164
- }
165
-
166
- return <Component {...props} />;
167
- };
168
- }
169
-
170
- // Self-protecting component wrapper
171
- export function ProComponent<P extends object>({
172
- component: Component,
173
- ...props
174
- }: P & { component: React.ComponentType<P> }) {
175
- const GuardedComponent = withLicenseGuard(Component);
176
- return <GuardedComponent {...(props as P)} />;
177
- }
@@ -1,60 +0,0 @@
1
- /**
2
- * Package Access Guard
3
- * Prevents direct NPM package usage without CLI
4
- */
5
-
6
- const ALLOWED_CALLERS = [
7
- '@moontra/moonui-cli',
8
- 'moonui-cli',
9
- '.moonui/temp', // CLI temp directory
10
- ];
11
-
12
- const DEV_MODE = process.env.NODE_ENV === 'development';
13
-
14
- export function checkPackageAccess(): void {
15
- // Skip in development mode for easier testing
16
- if (DEV_MODE) {
17
- return;
18
- }
19
-
20
- // Check if running in a browser (client-side)
21
- if (typeof window !== 'undefined') {
22
- // Client-side access is allowed after server-side validation
23
- return;
24
- }
25
-
26
- // Server-side check
27
- const stack = new Error().stack;
28
-
29
- if (!stack) {
30
- throw new Error(
31
- 'MoonUI Pro: This package can only be used via @moontra/moonui-cli. ' +
32
- 'Please install components using: npx @moontra/moonui-cli add <component>'
33
- );
34
- }
35
-
36
- // Check if called from allowed sources
37
- const isAllowed = ALLOWED_CALLERS.some(caller => stack.includes(caller));
38
-
39
- // Also check for local file paths that indicate CLI usage
40
- const isCliGenerated = stack.includes('/components/ui/') ||
41
- stack.includes('/components/pro/');
42
-
43
- if (!isAllowed && !isCliGenerated) {
44
- console.error('Stack trace:', stack);
45
- throw new Error(
46
- 'MoonUI Pro: Unauthorized package access detected.\n' +
47
- 'This package can only be used via @moontra/moonui-cli.\n' +
48
- 'Install components using: npx @moontra/moonui-cli add <component>\n\n' +
49
- 'If you have a Pro license, make sure to:\n' +
50
- '1. Login with: npx @moontra/moonui-cli login\n' +
51
- '2. Install components via CLI\n\n' +
52
- 'Learn more at: https://moonui.dev/docs/installation'
53
- );
54
- }
55
- }
56
-
57
- // Auto-check on import
58
- if (typeof window === 'undefined') {
59
- checkPackageAccess();
60
- }