@moontra/moonui 2.0.8 → 2.0.9

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 (94) hide show
  1. package/package.json +9 -2
  2. package/src/__tests__/use-intersection-observer.test.tsx +216 -0
  3. package/src/__tests__/use-local-storage.test.tsx +174 -0
  4. package/src/__tests__/use-pro-access.test.tsx +183 -0
  5. package/src/components/ui/__tests__/accordion.test.tsx +571 -0
  6. package/src/components/ui/__tests__/alert.test.tsx +484 -0
  7. package/src/components/ui/__tests__/aspect-ratio.test.tsx +492 -0
  8. package/src/components/ui/__tests__/avatar.test.tsx +382 -0
  9. package/src/components/ui/__tests__/badge.test.tsx +364 -0
  10. package/src/components/ui/__tests__/breadcrumb.test.tsx +687 -0
  11. package/src/components/ui/__tests__/button.test.tsx +91 -0
  12. package/src/components/ui/__tests__/card.test.tsx +104 -0
  13. package/src/components/ui/__tests__/checkbox.test.tsx +591 -0
  14. package/src/components/ui/__tests__/collapsible.test.tsx +592 -0
  15. package/src/components/ui/__tests__/color-picker.test.tsx +365 -0
  16. package/src/components/ui/__tests__/command.test.tsx +677 -0
  17. package/src/components/ui/__tests__/data-table.test.tsx +256 -0
  18. package/src/components/ui/__tests__/date-picker.test.tsx +320 -0
  19. package/src/components/ui/__tests__/dialog.test.tsx +764 -0
  20. package/src/components/ui/__tests__/input.test.tsx +318 -0
  21. package/src/components/ui/__tests__/label.test.tsx +103 -0
  22. package/src/components/ui/__tests__/popover.test.tsx +637 -0
  23. package/src/components/ui/__tests__/progress.test.tsx +382 -0
  24. package/src/components/ui/__tests__/radio-group.test.tsx +555 -0
  25. package/src/components/ui/__tests__/select.test.tsx +705 -0
  26. package/src/components/ui/__tests__/skeleton.test.tsx +253 -0
  27. package/src/components/ui/__tests__/slider.test.tsx +493 -0
  28. package/src/components/ui/__tests__/switch.test.tsx +372 -0
  29. package/src/components/ui/__tests__/table.test.tsx +824 -0
  30. package/src/components/ui/__tests__/tabs.test.tsx +887 -0
  31. package/src/components/ui/__tests__/toast.test.tsx +458 -0
  32. package/src/components/ui/__tests__/tooltip.test.tsx +583 -0
  33. package/src/components/ui/accordion.tsx +63 -0
  34. package/src/components/ui/alert.tsx +130 -0
  35. package/src/components/ui/aspect-ratio.tsx +72 -0
  36. package/src/components/ui/avatar.tsx +135 -0
  37. package/src/components/ui/badge.tsx +225 -0
  38. package/src/components/ui/breadcrumb.tsx +207 -0
  39. package/src/components/ui/button.stories.tsx +162 -0
  40. package/src/components/ui/button.tsx +221 -0
  41. package/src/components/ui/calendar.tsx +262 -0
  42. package/src/components/ui/card.stories.tsx +208 -0
  43. package/src/components/ui/card.tsx +141 -0
  44. package/src/components/ui/checkbox.tsx +256 -0
  45. package/src/components/ui/collapsible.tsx +129 -0
  46. package/src/components/ui/color-picker.tsx +664 -0
  47. package/src/components/ui/command.tsx +218 -0
  48. package/src/components/ui/data-table.stories.tsx +509 -0
  49. package/src/components/ui/data-table.tsx +623 -0
  50. package/src/components/ui/date-picker.stories.tsx +321 -0
  51. package/src/components/ui/date-picker.tsx +603 -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/file-upload.tsx +400 -0
  55. package/src/components/ui/github-stars.tsx +201 -0
  56. package/src/components/ui/index.ts +12 -0
  57. package/src/components/ui/input.stories.tsx +255 -0
  58. package/src/components/ui/input.tsx +219 -0
  59. package/src/components/ui/label.tsx +26 -0
  60. package/src/components/ui/locked-component.tsx +215 -0
  61. package/src/components/ui/moon-logo.tsx +97 -0
  62. package/src/components/ui/pagination.tsx +116 -0
  63. package/src/components/ui/popover.tsx +183 -0
  64. package/src/components/ui/progress.tsx +182 -0
  65. package/src/components/ui/radio-group.tsx +243 -0
  66. package/src/components/ui/select.tsx +273 -0
  67. package/src/components/ui/separator.tsx +140 -0
  68. package/src/components/ui/simple-editor.tsx +652 -0
  69. package/src/components/ui/skeleton.tsx +351 -0
  70. package/src/components/ui/slider.tsx +351 -0
  71. package/src/components/ui/switch.tsx +83 -0
  72. package/src/components/ui/table.tsx +322 -0
  73. package/src/components/ui/tabs.tsx +195 -0
  74. package/src/components/ui/textarea.tsx +46 -0
  75. package/src/components/ui/toast.tsx +313 -0
  76. package/src/components/ui/toggle.tsx +47 -0
  77. package/src/components/ui/tooltip.tsx +152 -0
  78. package/src/docs/theme-system.md +1194 -0
  79. package/src/index.tsx +39 -0
  80. package/src/lib/micro-interactions.ts +255 -0
  81. package/src/lib/theme.tsx +398 -0
  82. package/src/lib/utils.ts +69 -0
  83. package/src/styles/design-system.css +365 -0
  84. package/src/styles/index.css +4 -0
  85. package/src/styles/tailwind.css +6 -0
  86. package/src/styles/tokens.css +453 -0
  87. package/src/use-intersection-observer.tsx +154 -0
  88. package/src/use-local-storage.tsx +71 -0
  89. package/src/use-paddle.ts +138 -0
  90. package/src/use-performance-optimizer.ts +379 -0
  91. package/src/use-pro-access.ts +141 -0
  92. package/src/use-scroll-animation.ts +221 -0
  93. package/src/use-subscription.ts +37 -0
  94. package/src/use-toast.ts +32 -0
package/src/index.tsx ADDED
@@ -0,0 +1,39 @@
1
+ // Import CSS - Must be first
2
+ import "./styles/index.css"
3
+
4
+ // FREE UI Components Export - Source of Truth
5
+ export * from "./components/ui/accordion"
6
+ export * from "./components/ui/alert"
7
+ export * from "./components/ui/aspect-ratio"
8
+ export * from "./components/ui/avatar"
9
+ export * from "./components/ui/badge"
10
+ export * from "./components/ui/breadcrumb"
11
+ export * from "./components/ui/button"
12
+ export * from "./components/ui/calendar"
13
+ export * from "./components/ui/card"
14
+ export * from "./components/ui/checkbox"
15
+ export * from "./components/ui/collapsible"
16
+ export * from "./components/ui/command"
17
+ export * from "./components/ui/date-picker"
18
+ export * from "./components/ui/dialog"
19
+ export * from "./components/ui/dropdown-menu"
20
+ export * from "./components/ui/input"
21
+ export * from "./components/ui/label"
22
+ export * from "./components/ui/pagination"
23
+ export * from "./components/ui/popover"
24
+ export * from "./components/ui/progress"
25
+ export * from "./components/ui/radio-group"
26
+ export * from "./components/ui/select"
27
+ export * from "./components/ui/separator"
28
+ export * from "./components/ui/skeleton"
29
+ export * from "./components/ui/slider"
30
+ export * from "./components/ui/switch"
31
+ export * from "./components/ui/table"
32
+ export * from "./components/ui/tabs"
33
+ export * from "./components/ui/textarea"
34
+ export * from "./components/ui/toast"
35
+ export * from "./components/ui/toggle"
36
+ export * from "./components/ui/tooltip"
37
+
38
+ // Utility exports
39
+ export * from "./lib/utils"
@@ -0,0 +1,255 @@
1
+ // MoonUI Micro-interactions System
2
+ // Provides consistent hover, focus, and active states across all components
3
+
4
+ import { cva, type VariantProps } from "class-variance-authority";
5
+
6
+ /**
7
+ * Micro-interaction variants for consistent component behavior
8
+ */
9
+ export const microInteractionVariants = cva("", {
10
+ variants: {
11
+ hover: {
12
+ lift: [
13
+ "transition-all duration-200 ease-out",
14
+ "hover:-translate-y-0.5",
15
+ "hover:shadow-md",
16
+ ],
17
+ glow: [
18
+ "transition-all duration-300 ease-out",
19
+ "hover:shadow-lg",
20
+ "hover:shadow-primary/20",
21
+ ],
22
+ scale: [
23
+ "transition-transform duration-200 ease-out",
24
+ "hover:scale-105",
25
+ "active:scale-95",
26
+ ],
27
+ brightness: [
28
+ "transition-all duration-200 ease-out",
29
+ "hover:brightness-110",
30
+ "active:brightness-95",
31
+ ],
32
+ border: [
33
+ "transition-all duration-200 ease-out",
34
+ "hover:border-primary/50",
35
+ ],
36
+ },
37
+ focus: {
38
+ ring: [
39
+ "focus:outline-none",
40
+ "focus-visible:ring-2",
41
+ "focus-visible:ring-primary/50",
42
+ "focus-visible:ring-offset-2",
43
+ ],
44
+ glow: [
45
+ "focus:outline-none",
46
+ "focus-visible:shadow-lg",
47
+ "focus-visible:shadow-primary/30",
48
+ ],
49
+ border: [
50
+ "focus:outline-none",
51
+ "focus-visible:border-primary",
52
+ "focus-visible:border-2",
53
+ ],
54
+ },
55
+ active: {
56
+ scale: [
57
+ "active:scale-95",
58
+ "transition-transform duration-100",
59
+ ],
60
+ darken: [
61
+ "active:brightness-90",
62
+ "transition-all duration-100",
63
+ ],
64
+ depress: [
65
+ "active:translate-y-0.5",
66
+ "active:shadow-sm",
67
+ "transition-all duration-100",
68
+ ],
69
+ },
70
+ cursor: {
71
+ pointer: "cursor-pointer",
72
+ grab: "cursor-grab active:cursor-grabbing",
73
+ text: "cursor-text",
74
+ wait: "cursor-wait",
75
+ help: "cursor-help",
76
+ notAllowed: "cursor-not-allowed",
77
+ },
78
+ },
79
+ defaultVariants: {
80
+ hover: "lift",
81
+ focus: "ring",
82
+ active: "scale",
83
+ cursor: "pointer",
84
+ },
85
+ });
86
+
87
+ /**
88
+ * Spring animation configurations
89
+ */
90
+ export const springAnimations = {
91
+ // Smooth spring for general use
92
+ smooth: {
93
+ type: "spring",
94
+ stiffness: 260,
95
+ damping: 20,
96
+ },
97
+ // Bouncy spring for playful interactions
98
+ bouncy: {
99
+ type: "spring",
100
+ stiffness: 300,
101
+ damping: 15,
102
+ },
103
+ // Stiff spring for quick responses
104
+ stiff: {
105
+ type: "spring",
106
+ stiffness: 400,
107
+ damping: 25,
108
+ },
109
+ // Gentle spring for subtle movements
110
+ gentle: {
111
+ type: "spring",
112
+ stiffness: 150,
113
+ damping: 15,
114
+ },
115
+ };
116
+
117
+ /**
118
+ * Hover animation presets
119
+ */
120
+ export const hoverAnimations = {
121
+ lift: {
122
+ y: -2,
123
+ transition: springAnimations.smooth,
124
+ },
125
+ scale: {
126
+ scale: 1.05,
127
+ transition: springAnimations.smooth,
128
+ },
129
+ glow: {
130
+ boxShadow: "0 0 20px rgba(var(--primary), 0.3)",
131
+ transition: springAnimations.smooth,
132
+ },
133
+ rotate: {
134
+ rotate: 2,
135
+ transition: springAnimations.bouncy,
136
+ },
137
+ };
138
+
139
+ /**
140
+ * Tap/Click animation presets
141
+ */
142
+ export const tapAnimations = {
143
+ scale: {
144
+ scale: 0.95,
145
+ transition: { duration: 0.1 },
146
+ },
147
+ depress: {
148
+ y: 1,
149
+ transition: { duration: 0.1 },
150
+ },
151
+ };
152
+
153
+ /**
154
+ * Focus animation presets
155
+ */
156
+ export const focusAnimations = {
157
+ ring: {
158
+ boxShadow: "0 0 0 2px var(--background), 0 0 0 4px var(--primary)",
159
+ transition: springAnimations.smooth,
160
+ },
161
+ glow: {
162
+ boxShadow: "0 0 0 3px rgba(var(--primary), 0.3)",
163
+ transition: springAnimations.smooth,
164
+ },
165
+ };
166
+
167
+ /**
168
+ * Stagger animation for lists
169
+ */
170
+ export const staggerAnimation = {
171
+ container: {
172
+ hidden: { opacity: 0 },
173
+ show: {
174
+ opacity: 1,
175
+ transition: {
176
+ staggerChildren: 0.05,
177
+ },
178
+ },
179
+ },
180
+ item: {
181
+ hidden: { opacity: 0, y: 20 },
182
+ show: {
183
+ opacity: 1,
184
+ y: 0,
185
+ transition: springAnimations.smooth,
186
+ },
187
+ },
188
+ };
189
+
190
+ /**
191
+ * Page transition animations
192
+ */
193
+ export const pageTransitions = {
194
+ fadeIn: {
195
+ initial: { opacity: 0 },
196
+ animate: { opacity: 1 },
197
+ exit: { opacity: 0 },
198
+ transition: { duration: 0.3 },
199
+ },
200
+ slideUp: {
201
+ initial: { opacity: 0, y: 20 },
202
+ animate: { opacity: 1, y: 0 },
203
+ exit: { opacity: 0, y: -20 },
204
+ transition: springAnimations.smooth,
205
+ },
206
+ slideRight: {
207
+ initial: { opacity: 0, x: -20 },
208
+ animate: { opacity: 1, x: 0 },
209
+ exit: { opacity: 0, x: 20 },
210
+ transition: springAnimations.smooth,
211
+ },
212
+ scale: {
213
+ initial: { opacity: 0, scale: 0.95 },
214
+ animate: { opacity: 1, scale: 1 },
215
+ exit: { opacity: 0, scale: 1.05 },
216
+ transition: springAnimations.smooth,
217
+ },
218
+ };
219
+
220
+ /**
221
+ * Skeleton loading animation
222
+ */
223
+ export const skeletonAnimation = {
224
+ initial: { opacity: 0.5 },
225
+ animate: {
226
+ opacity: [0.5, 0.8, 0.5],
227
+ transition: {
228
+ duration: 1.5,
229
+ repeat: Infinity,
230
+ ease: "easeInOut" as const,
231
+ },
232
+ },
233
+ };
234
+
235
+ /**
236
+ * Tooltip animation
237
+ */
238
+ export const tooltipAnimation = {
239
+ initial: { opacity: 0, scale: 0.95 },
240
+ animate: { opacity: 1, scale: 1 },
241
+ exit: { opacity: 0, scale: 0.95 },
242
+ transition: { duration: 0.15 },
243
+ };
244
+
245
+ /**
246
+ * Notification animation
247
+ */
248
+ export const notificationAnimation = {
249
+ initial: { opacity: 0, y: -20, scale: 0.95 },
250
+ animate: { opacity: 1, y: 0, scale: 1 },
251
+ exit: { opacity: 0, scale: 0.95, transition: { duration: 0.15 } },
252
+ transition: springAnimations.bouncy,
253
+ };
254
+
255
+ export type MicroInteractionProps = VariantProps<typeof microInteractionVariants>;
@@ -0,0 +1,398 @@
1
+ import * as React from 'react';
2
+ import { createContext, useContext, useState, useMemo, ReactNode } from 'react';
3
+
4
+ /**
5
+ * Tema türleri için temel renk paletini tanımlayan tip
6
+ */
7
+ export type ThemeColors = {
8
+ primary: string;
9
+ secondary: string;
10
+ success: string;
11
+ warning: string;
12
+ error: string;
13
+ background: string;
14
+ foreground: string;
15
+ card: string;
16
+ cardForeground: string;
17
+ border: string;
18
+ muted: string;
19
+ mutedForeground: string;
20
+ accent: string;
21
+ accentForeground: string;
22
+ };
23
+
24
+ /**
25
+ * Tema yapılandırma tipi
26
+ */
27
+ export type ThemeConfig = {
28
+ colors: ThemeColors;
29
+ borderRadius: {
30
+ sm: string;
31
+ md: string;
32
+ lg: string;
33
+ full: string;
34
+ };
35
+ fontSizes: {
36
+ xs: string;
37
+ sm: string;
38
+ base: string;
39
+ lg: string;
40
+ xl: string;
41
+ '2xl': string;
42
+ '3xl': string;
43
+ };
44
+ spacing: {
45
+ 1: string;
46
+ 2: string;
47
+ 4: string;
48
+ 6: string;
49
+ 8: string;
50
+ };
51
+ // Kullanıcıların kendi özel değişkenlerini ekleyebilmesi için
52
+ extensions?: Record<string, Record<string, string> | string>;
53
+ };
54
+
55
+ /**
56
+ * Tema hazır şablonları
57
+ */
58
+ export type ThemePreset = 'default' | 'modern' | 'rounded' | 'minimal';
59
+
60
+ /**
61
+ * Varsayılan açık tema
62
+ */
63
+ // Modern teması için değerler
64
+ const modernTheme: Partial<ThemeConfig> = {
65
+ borderRadius: {
66
+ sm: '0.5rem',
67
+ md: '0.75rem',
68
+ lg: '1rem',
69
+ full: '9999px',
70
+ },
71
+ colors: {
72
+ primary: 'hsl(250, 95%, 64%)',
73
+ secondary: 'hsl(250, 70%, 80%)',
74
+ success: 'hsl(142, 71%, 45%)',
75
+ warning: 'hsl(38, 92%, 50%)',
76
+ error: 'hsl(0, 84%, 60%)',
77
+ background: 'hsl(0, 0%, 100%)',
78
+ foreground: 'hsl(221, 39%, 11%)',
79
+ card: 'hsl(0, 0%, 100%)',
80
+ cardForeground: 'hsl(221, 39%, 11%)',
81
+ border: 'hsl(210, 20%, 90%)',
82
+ muted: 'hsl(210, 20%, 96%)',
83
+ mutedForeground: 'hsl(215, 16%, 47%)',
84
+ accent: 'hsl(328, 85%, 70%)',
85
+ accentForeground: 'hsl(210, 20%, 98%)',
86
+ }
87
+ };
88
+
89
+ // Yuvarlak teması için değerler
90
+ const roundedTheme = {
91
+ borderRadius: {
92
+ sm: '1rem',
93
+ md: '1.25rem',
94
+ lg: '1.5rem',
95
+ full: '9999px',
96
+ }
97
+ };
98
+
99
+ // Minimal teması için değerler
100
+ const minimalTheme: Partial<ThemeConfig> = {
101
+ borderRadius: {
102
+ sm: '0.125rem',
103
+ md: '0.25rem',
104
+ lg: '0.375rem',
105
+ full: '9999px',
106
+ },
107
+ colors: {
108
+ primary: 'hsl(220, 14%, 40%)',
109
+ secondary: 'hsl(220, 9%, 60%)',
110
+ success: 'hsl(142, 71%, 45%)',
111
+ warning: 'hsl(38, 92%, 50%)',
112
+ error: 'hsl(0, 84%, 60%)',
113
+ background: 'hsl(0, 0%, 100%)',
114
+ foreground: 'hsl(221, 39%, 11%)',
115
+ card: 'hsl(0, 0%, 100%)',
116
+ cardForeground: 'hsl(221, 39%, 11%)',
117
+ border: 'hsl(220, 13%, 91%)',
118
+ muted: 'hsl(220, 14%, 96%)',
119
+ mutedForeground: 'hsl(215, 16%, 47%)',
120
+ accent: 'hsl(210, 20%, 96%)',
121
+ accentForeground: 'hsl(221, 39%, 11%)',
122
+ }
123
+ };
124
+
125
+ export const defaultLightTheme: ThemeConfig = {
126
+ colors: {
127
+ primary: 'hsl(221, 83%, 53%)',
128
+ secondary: 'hsl(215, 20%, 65%)',
129
+ success: 'hsl(142, 71%, 45%)',
130
+ warning: 'hsl(38, 92%, 50%)',
131
+ error: 'hsl(0, 84%, 60%)',
132
+ background: 'hsl(0, 0%, 100%)',
133
+ foreground: 'hsl(221, 39%, 11%)',
134
+ card: 'hsl(0, 0%, 100%)',
135
+ cardForeground: 'hsl(221, 39%, 11%)',
136
+ border: 'hsl(210, 20%, 90%)',
137
+ muted: 'hsl(210, 20%, 96%)',
138
+ mutedForeground: 'hsl(215, 16%, 47%)',
139
+ accent: 'hsl(210, 20%, 96%)',
140
+ accentForeground: 'hsl(221, 39%, 11%)',
141
+ },
142
+ borderRadius: {
143
+ sm: '0.25rem',
144
+ md: '0.375rem',
145
+ lg: '0.5rem',
146
+ full: '9999px',
147
+ },
148
+ fontSizes: {
149
+ xs: '0.75rem',
150
+ sm: '0.875rem',
151
+ base: '1rem',
152
+ lg: '1.125rem',
153
+ xl: '1.25rem',
154
+ '2xl': '1.5rem',
155
+ '3xl': '1.875rem',
156
+ },
157
+ spacing: {
158
+ 1: '0.25rem',
159
+ 2: '0.5rem',
160
+ 4: '1rem',
161
+ 6: '1.5rem',
162
+ 8: '2rem',
163
+ },
164
+ };
165
+
166
+ /**
167
+ * Varsayılan koyu tema
168
+ */
169
+ export const defaultDarkTheme: ThemeConfig = {
170
+ ...defaultLightTheme,
171
+ colors: {
172
+ primary: 'hsl(221, 83%, 53%)',
173
+ secondary: 'hsl(215, 20%, 65%)',
174
+ success: 'hsl(142, 71%, 45%)',
175
+ warning: 'hsl(38, 92%, 50%)',
176
+ error: 'hsl(0, 84%, 60%)',
177
+ background: 'hsl(221, 39%, 11%)',
178
+ foreground: 'hsl(210, 20%, 98%)',
179
+ card: 'hsl(220, 26%, 14%)',
180
+ cardForeground: 'hsl(210, 20%, 98%)',
181
+ border: 'hsl(215, 28%, 17%)',
182
+ muted: 'hsl(215, 27%, 16%)',
183
+ mutedForeground: 'hsl(215, 16%, 57%)',
184
+ accent: 'hsl(215, 27%, 16%)',
185
+ accentForeground: 'hsl(210, 20%, 98%)',
186
+ },
187
+ };
188
+
189
+ /**
190
+ * Tema bağlamı için tip
191
+ */
192
+ export interface ThemeContextType {
193
+ theme: ThemeConfig;
194
+ colorMode: 'light' | 'dark';
195
+ setColorMode: (mode: 'light' | 'dark') => void;
196
+ updateTheme: (config: Partial<ThemeConfig>) => void;
197
+ }
198
+
199
+ // Tema bağlamı
200
+ const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
201
+
202
+ // Tema sağlayıcı props
203
+ export interface ThemeProviderProps {
204
+ children: ReactNode;
205
+ defaultColorMode?: 'light' | 'dark';
206
+ preset?: ThemePreset;
207
+ lightTheme?: Partial<ThemeConfig>;
208
+ darkTheme?: Partial<ThemeConfig>;
209
+ extensions?: Record<string, Record<string, string> | string>;
210
+ }
211
+
212
+ /**
213
+ * Tema önayarını getir
214
+ */
215
+ const getPresetTheme = (preset: ThemePreset): Partial<ThemeConfig> => {
216
+ switch (preset) {
217
+ case 'modern':
218
+ return modernTheme;
219
+ case 'rounded':
220
+ return roundedTheme;
221
+ case 'minimal':
222
+ return minimalTheme;
223
+ default:
224
+ return {};
225
+ }
226
+ };
227
+
228
+ /**
229
+ * MoonUI tema sağlayıcısı
230
+ */
231
+ export const ThemeProvider = ({
232
+ children,
233
+ defaultColorMode = 'light',
234
+ preset = 'default',
235
+ lightTheme = {},
236
+ darkTheme = {},
237
+ extensions = {},
238
+ }: ThemeProviderProps) => {
239
+ // Renk modu state'i
240
+ const [colorMode, setColorMode] = useState<'light' | 'dark'>(defaultColorMode);
241
+
242
+ // Preset tema değerlerini al
243
+ const presetThemeValues = getPresetTheme(preset);
244
+
245
+ // Özelleştirilmiş temalar
246
+ const [customLightTheme, setCustomLightTheme] = useState<ThemeConfig>({
247
+ ...defaultLightTheme,
248
+ ...presetThemeValues,
249
+ ...lightTheme,
250
+ colors: {
251
+ ...defaultLightTheme.colors,
252
+ ...(presetThemeValues.colors || {}),
253
+ ...(lightTheme.colors || {}),
254
+ },
255
+ extensions: extensions,
256
+ });
257
+
258
+ const [customDarkTheme, setCustomDarkTheme] = useState<ThemeConfig>({
259
+ ...defaultDarkTheme,
260
+ ...presetThemeValues,
261
+ ...darkTheme,
262
+ colors: {
263
+ ...defaultDarkTheme.colors,
264
+ ...(presetThemeValues.colors || {}),
265
+ ...(darkTheme.colors || {}),
266
+ },
267
+ extensions: extensions,
268
+ });
269
+
270
+ // Aktif tema
271
+ const theme = useMemo(() => {
272
+ return colorMode === 'light' ? customLightTheme : customDarkTheme;
273
+ }, [colorMode, customLightTheme, customDarkTheme]);
274
+
275
+ // Tema güncelleme fonksiyonu
276
+ const updateTheme = (config: Partial<ThemeConfig>) => {
277
+ if (colorMode === 'light') {
278
+ setCustomLightTheme(prev => ({
279
+ ...prev,
280
+ ...config,
281
+ colors: {
282
+ ...prev.colors,
283
+ ...(config.colors || {}),
284
+ },
285
+ extensions: {
286
+ ...(prev.extensions || {}),
287
+ ...(config.extensions || {}),
288
+ },
289
+ }));
290
+ } else {
291
+ setCustomDarkTheme(prev => ({
292
+ ...prev,
293
+ ...config,
294
+ colors: {
295
+ ...prev.colors,
296
+ ...(config.colors || {}),
297
+ },
298
+ extensions: {
299
+ ...(prev.extensions || {}),
300
+ ...(config.extensions || {}),
301
+ },
302
+ }));
303
+ }
304
+ };
305
+
306
+ // Tema değiştirme fonksiyonu
307
+ const setThemePreset = (preset: ThemePreset) => {
308
+ const presetValues = getPresetTheme(preset);
309
+
310
+ updateTheme({
311
+ ...presetValues,
312
+ colors: presetValues.colors as ThemeColors,
313
+ });
314
+ };
315
+
316
+ const value = {
317
+ theme,
318
+ colorMode,
319
+ setColorMode,
320
+ updateTheme,
321
+ setThemePreset,
322
+ };
323
+
324
+ return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
325
+ };
326
+
327
+ /**
328
+ * Tema bağlamı için tip
329
+ */
330
+ export interface ThemeContextType {
331
+ theme: ThemeConfig;
332
+ colorMode: 'light' | 'dark';
333
+ setColorMode: (mode: 'light' | 'dark') => void;
334
+ updateTheme: (config: Partial<ThemeConfig>) => void;
335
+ setThemePreset: (preset: ThemePreset) => void;
336
+ }
337
+
338
+ /**
339
+ * Tema kullanma kancası
340
+ */
341
+ export const useTheme = (): ThemeContextType => {
342
+ const context = useContext(ThemeContext);
343
+
344
+ if (context === undefined) {
345
+ throw new Error('useTheme must be used within a ThemeProvider');
346
+ }
347
+
348
+ return context;
349
+ };
350
+
351
+ /**
352
+ * CSS değişkenlerini tema konfigürasyonundan oluşturma fonksiyonu
353
+ */
354
+ export const createCssVariables = (theme: ThemeConfig): Record<string, string> => {
355
+ const variables: Record<string, string> = {};
356
+
357
+ // Renkleri CSS değişkenlerine dönüştür
358
+ Object.entries(theme.colors).forEach(([key, value]) => {
359
+ variables[`--color-${key}`] = value;
360
+ });
361
+
362
+ // Border radius değerlerini CSS değişkenlerine dönüştür
363
+ Object.entries(theme.borderRadius).forEach(([key, value]) => {
364
+ variables[`--radius-${key}`] = value;
365
+ });
366
+
367
+ // Font boyutlarını CSS değişkenlerine dönüştür
368
+ Object.entries(theme.fontSizes).forEach(([key, value]) => {
369
+ variables[`--font-size-${key}`] = value;
370
+ });
371
+
372
+ // Boşluk değerlerini CSS değişkenlerine dönüştür
373
+ Object.entries(theme.spacing).forEach(([key, value]) => {
374
+ variables[`--space-${key}`] = value;
375
+ });
376
+
377
+ // Özel uzantı değişkenlerini CSS'e dönüştür
378
+ if (theme.extensions) {
379
+ Object.entries(theme.extensions).forEach(([categoryKey, categoryValue]) => {
380
+ if (typeof categoryValue === 'object' && categoryValue !== null) {
381
+ Object.entries(categoryValue as Record<string, string>).forEach(([key, value]) => {
382
+ variables[`--${categoryKey}-${key}`] = value;
383
+ });
384
+ } else if (typeof categoryValue === 'string') {
385
+ variables[`--${categoryKey}`] = categoryValue;
386
+ }
387
+ });
388
+ }
389
+
390
+ return variables;
391
+ };
392
+
393
+ /**
394
+ * CSS sınıflarını tema değerlerine göre üretme yardımcı fonksiyonu
395
+ */
396
+ export const getCssClass = (themeKey: keyof ThemeConfig, value: string): string => {
397
+ return `var(--${themeKey}-${value})`;
398
+ };