@space-man/react-theme-animation 1.0.0

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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +623 -0
  3. package/dist/cjs/components/SpacemanThemeProvider.d.ts +51 -0
  4. package/dist/cjs/components/SpacemanThemeProvider.js +93 -0
  5. package/dist/cjs/components/ThemeSelector.d.ts +3 -0
  6. package/dist/cjs/components/ThemeSelector.js +39 -0
  7. package/dist/cjs/components/ThemeSwitcher.d.ts +3 -0
  8. package/dist/cjs/components/ThemeSwitcher.js +100 -0
  9. package/dist/cjs/components/ui/select.d.ts +15 -0
  10. package/dist/cjs/components/ui/select.js +83 -0
  11. package/dist/cjs/hooks/use-theme-animation.d.ts +2 -0
  12. package/dist/cjs/hooks/use-theme-animation.js +149 -0
  13. package/dist/cjs/index.d.ts +7 -0
  14. package/dist/cjs/index.js +20 -0
  15. package/dist/cjs/types/index.d.ts +65 -0
  16. package/dist/cjs/types/index.js +8 -0
  17. package/dist/cjs/utils/animations.d.ts +18 -0
  18. package/dist/cjs/utils/animations.js +156 -0
  19. package/dist/components/SpacemanThemeProvider.d.ts +51 -0
  20. package/dist/components/SpacemanThemeProvider.js +88 -0
  21. package/dist/components/ThemeSelector.d.ts +3 -0
  22. package/dist/components/ThemeSelector.js +35 -0
  23. package/dist/components/ThemeSwitcher.d.ts +3 -0
  24. package/dist/components/ThemeSwitcher.js +96 -0
  25. package/dist/components/ui/select.d.ts +15 -0
  26. package/dist/components/ui/select.js +39 -0
  27. package/dist/esm/components/SpacemanThemeProvider.d.ts +51 -0
  28. package/dist/esm/components/SpacemanThemeProvider.js +88 -0
  29. package/dist/esm/components/ThemeSelector.d.ts +3 -0
  30. package/dist/esm/components/ThemeSelector.js +35 -0
  31. package/dist/esm/components/ThemeSwitcher.d.ts +3 -0
  32. package/dist/esm/components/ThemeSwitcher.js +96 -0
  33. package/dist/esm/components/ui/select.d.ts +15 -0
  34. package/dist/esm/components/ui/select.js +39 -0
  35. package/dist/esm/hooks/use-theme-animation.d.ts +2 -0
  36. package/dist/esm/hooks/use-theme-animation.js +145 -0
  37. package/dist/esm/index.d.ts +7 -0
  38. package/dist/esm/index.js +6 -0
  39. package/dist/esm/types/index.d.ts +65 -0
  40. package/dist/esm/types/index.js +5 -0
  41. package/dist/esm/utils/animations.d.ts +18 -0
  42. package/dist/esm/utils/animations.js +145 -0
  43. package/dist/hooks/use-theme-animation.d.ts +2 -0
  44. package/dist/hooks/use-theme-animation.js +145 -0
  45. package/dist/index.d.ts +7 -0
  46. package/dist/index.js +6 -0
  47. package/dist/types/index.d.ts +65 -0
  48. package/dist/types/index.js +5 -0
  49. package/dist/utils/animations.d.ts +18 -0
  50. package/dist/utils/animations.js +145 -0
  51. package/package.json +74 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Tony Edgal
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,623 @@
1
+ # @spaceman/react-theme-animation
2
+
3
+ React theme switching with smooth view transition animations, multi-theme support, and synchronized state management.
4
+
5
+ ## Features
6
+
7
+ - 🎨 **Smooth Animations**: Beautiful view transition animations for theme switching with customizable origins
8
+ - 🌓 **Multi-Theme Support**: Support for light, dark, and system themes
9
+ - 🎯 **Color Themes**: Additional color theme variants (brand colors, etc.)
10
+ - 🪝 **Powerful Hook**: `useThemeAnimation` hook with full control
11
+ - 🧩 **Ready Components**: `ThemeSwitcher` and `ThemeSelector` components
12
+ - 🎛️ **Provider Pattern**: Centralized theme state management with `SpacemanThemeProvider`
13
+ - 🔄 **State Synchronization**: Prevents state drift between multiple components
14
+ - 📱 **Responsive**: Works on all screen sizes including high-resolution displays
15
+ - ⚡ **Performance**: Optimized animations with reduced motion support
16
+ - 🔧 **TypeScript**: Full TypeScript support with comprehensive types
17
+ - 🎛️ **Customizable**: Extensive configuration options
18
+ - 🔙 **Backward Compatible**: Works with existing implementations
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install @spaceman/react-theme-animation
24
+ ```
25
+
26
+ ## Usage Patterns
27
+
28
+ This library supports two main usage patterns:
29
+
30
+ 1. **Hook-Only Usage**: Direct hook usage for custom implementations
31
+ 2. **Provider Pattern**: Centralized state management (recommended)
32
+
33
+ ---
34
+
35
+ ## 1. Hook-Only Usage For Light and Dark mode animation
36
+
37
+ Perfect for custom theme toggle buttons and complete control over animated theme logic.
38
+
39
+ ### Basic Theme Toggle
40
+
41
+ ```tsx
42
+ import { useThemeAnimation } from '@spaceman/react-theme-animation';
43
+
44
+ function ThemeToggle() {
45
+ const { theme, toggleTheme, ref } = useThemeAnimation();
46
+
47
+ return (
48
+ <button ref={ref} onClick={toggleTheme} className="theme-toggle-btn">
49
+ {theme === 'light' ? '🌙' : '🌞'} {theme}
50
+ </button>
51
+ );
52
+ }
53
+ ```
54
+
55
+ ---
56
+
57
+ ## 2. Provider Pattern (Recommended)
58
+
59
+ The most powerful pattern using `SpacemanThemeProvider` for centralized theme state management. This prevents state drift and provides synchronized animations.
60
+
61
+ ### Basic Provider Setup
62
+
63
+ ```tsx
64
+ import {
65
+ SpacemanThemeProvider,
66
+ ThemeSwitcher,
67
+ ThemeSelector,
68
+ } from '@spaceman/react-theme-animation';
69
+
70
+ function App() {
71
+ return (
72
+ <SpacemanThemeProvider>
73
+ <div className="app">
74
+ <header>
75
+ <ThemeSwitcher />
76
+ </header>
77
+
78
+ <aside>
79
+ <ThemeSelector colorThemes={['default', 'blue', 'green', 'purple']} />
80
+ </aside>
81
+
82
+ <main>
83
+ <YourAppContent />
84
+ </main>
85
+ </div>
86
+ </SpacemanThemeProvider>
87
+ );
88
+ }
89
+ ```
90
+
91
+ ### Advanced Provider Configuration
92
+
93
+ ```tsx
94
+ import {
95
+ SpacemanThemeProvider,
96
+ ThemeSwitcher,
97
+ ThemeSelector,
98
+ ThemeAnimationType,
99
+ } from '@spaceman/react-theme-animation';
100
+
101
+ function App() {
102
+ return (
103
+ <SpacemanThemeProvider
104
+ defaultTheme="system"
105
+ defaultColorTheme="blue"
106
+ themes={['light', 'dark', 'system']}
107
+ colorThemes={['default', 'blue', 'green', 'purple', 'red']}
108
+ animationType={ThemeAnimationType.BLUR_CIRCLE}
109
+ blurAmount={10}
110
+ duration={1000}
111
+ onThemeChange={theme => {
112
+ // Analytics, localStorage, etc.
113
+ console.log('Global theme changed:', theme);
114
+ }}
115
+ onColorThemeChange={colorTheme => {
116
+ console.log('Global color theme changed:', colorTheme);
117
+ }}
118
+ >
119
+ <AppLayout />
120
+ </SpacemanThemeProvider>
121
+ );
122
+ }
123
+
124
+ function AppLayout() {
125
+ return (
126
+ <div className="app-layout">
127
+ <Header />
128
+ <Sidebar />
129
+ <MainContent />
130
+ </div>
131
+ );
132
+ }
133
+
134
+ function Header() {
135
+ return (
136
+ <header className="header">
137
+ <h1>My App</h1>
138
+ <ThemeSwitcher className="ml-auto" />
139
+ </header>
140
+ );
141
+ }
142
+
143
+ function Sidebar() {
144
+ return (
145
+ <aside className="sidebar">
146
+ <h2>Settings</h2>
147
+ <ThemeSelector colorThemes={['default', 'blue', 'green', 'purple', 'red']} />
148
+ </aside>
149
+ );
150
+ }
151
+ ```
152
+
153
+ ### Using the Provider Hook
154
+
155
+ Access theme state anywhere in your component tree. This hook also enables you to set a reference point for the animation to start from.
156
+
157
+ ```tsx
158
+ import { useSpacemanTheme } from '@spaceman/react-theme-animation';
159
+
160
+ function ThemeStatus() {
161
+ const { theme, colorTheme, switchTheme, setColorTheme, switchThemeFromElement } =
162
+ useSpacemanTheme();
163
+
164
+ const handleCustomThemeSwitch = event => {
165
+ // Animate from the clicked element
166
+ switchThemeFromElement('dark', event.currentTarget);
167
+ };
168
+
169
+ return (
170
+ <div className="theme-status">
171
+ <p>Current theme: {theme}</p>
172
+ <p>Current color: {colorTheme}</p>
173
+
174
+ <button onClick={handleCustomThemeSwitch}>Switch to Dark (with animation)</button>
175
+ </div>
176
+ );
177
+ }
178
+ ```
179
+
180
+ ---
181
+
182
+ ## Complete Example: Advanced Theme System
183
+
184
+ Here's a complete example showcasing all features:
185
+
186
+ ```tsx
187
+ import React from 'react';
188
+ import {
189
+ SpacemanThemeProvider,
190
+ ThemeSwitcher,
191
+ ThemeSelector,
192
+ useSpacemanTheme,
193
+ ThemeAnimationType,
194
+ } from '@spaceman/react-theme-animation';
195
+
196
+ // Main App with Provider
197
+ function App() {
198
+ return (
199
+ <SpacemanThemeProvider
200
+ defaultTheme="system"
201
+ defaultColorTheme="blue"
202
+ themes={['light', 'dark', 'system']}
203
+ colorThemes={['default', 'blue', 'green', 'purple', 'red', 'orange']}
204
+ animationType={ThemeAnimationType.CIRCLE}
205
+ duration={800}
206
+ onThemeChange={theme => {
207
+ // Save to localStorage, analytics, etc.
208
+ localStorage.setItem('preferred-theme', theme);
209
+ }}
210
+ onColorThemeChange={colorTheme => {
211
+ localStorage.setItem('preferred-color-theme', colorTheme);
212
+ }}
213
+ >
214
+ <AppContent />
215
+ </SpacemanThemeProvider>
216
+ );
217
+ }
218
+
219
+ // App Layout
220
+ function AppContent() {
221
+ return (
222
+ <div className="min-h-screen bg-background text-foreground">
223
+ <Header />
224
+ <div className="container mx-auto px-4 py-8">
225
+ <div className="grid grid-cols-1 lg:grid-cols-4 gap-8">
226
+ <Sidebar />
227
+ <MainContent />
228
+ </div>
229
+ </div>
230
+ </div>
231
+ );
232
+ }
233
+
234
+ // Header with Theme Switcher
235
+ function Header() {
236
+ return (
237
+ <header className="border-b bg-card">
238
+ <div className="container mx-auto px-4 py-4 flex items-center justify-between">
239
+ <h1 className="text-2xl font-bold">Theme Demo</h1>
240
+ <div className="flex items-center gap-4">
241
+ <ThemeSwitcher className="rounded-lg" />
242
+ </div>
243
+ </div>
244
+ </header>
245
+ );
246
+ }
247
+
248
+ // Sidebar with Theme Selector
249
+ function Sidebar() {
250
+ return (
251
+ <aside className="space-y-6">
252
+ <div className="bg-card p-6 rounded-lg border">
253
+ <h2 className="text-lg font-semibold mb-4">Theme Settings</h2>
254
+ <div className="space-y-4">
255
+ <div>
256
+ <label className="text-sm font-medium mb-2 block">Color Theme</label>
257
+ <ThemeSelector colorThemes={['default', 'blue', 'green', 'purple', 'red', 'orange']} />
258
+ </div>
259
+ </div>
260
+ </div>
261
+
262
+ <ThemeInfo />
263
+ </aside>
264
+ );
265
+ }
266
+
267
+ // Component using the theme hook
268
+ function ThemeInfo() {
269
+ const { theme, colorTheme, switchThemeFromElement } = useSpacemanTheme();
270
+
271
+ const quickSwitchTheme = (newTheme, event) => {
272
+ switchThemeFromElement(newTheme, event.currentTarget);
273
+ };
274
+
275
+ return (
276
+ <div className="bg-card p-6 rounded-lg border">
277
+ <h3 className="text-lg font-semibold mb-4">Current State</h3>
278
+ <div className="space-y-2 text-sm">
279
+ <p>
280
+ <strong>Theme:</strong> {theme}
281
+ </p>
282
+ <p>
283
+ <strong>Color:</strong> {colorTheme}
284
+ </p>
285
+ </div>
286
+
287
+ <div className="mt-4 space-y-2">
288
+ <p className="text-sm font-medium">Quick Switch:</p>
289
+ <div className="flex gap-2">
290
+ {['light', 'dark'].map(t => (
291
+ <button
292
+ key={t}
293
+ onClick={e => quickSwitchTheme(t, e)}
294
+ className="px-3 py-1 text-xs bg-primary text-primary-foreground rounded hover:bg-primary/90 transition-colors"
295
+ >
296
+ {t}
297
+ </button>
298
+ ))}
299
+ </div>
300
+ </div>
301
+ </div>
302
+ );
303
+ }
304
+
305
+ // Main content area
306
+ function MainContent() {
307
+ return (
308
+ <main className="lg:col-span-3 space-y-6">
309
+ <div className="bg-card p-6 rounded-lg border">
310
+ <h2 className="text-xl font-semibold mb-4">Welcome to Theme Demo</h2>
311
+ <p className="text-muted-foreground">
312
+ This demo showcases the spaceman-react-theme-animation library with synchronized theme
313
+ state, smooth animations, and multiple color themes.
314
+ </p>
315
+ </div>
316
+
317
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
318
+ {[1, 2, 3, 4].map(i => (
319
+ <div key={i} className="bg-card p-6 rounded-lg border">
320
+ <h3 className="font-semibold mb-2">Card {i}</h3>
321
+ <p className="text-sm text-muted-foreground">
322
+ Sample content that adapts to the current theme and color scheme.
323
+ </p>
324
+ </div>
325
+ ))}
326
+ </div>
327
+ </main>
328
+ );
329
+ }
330
+
331
+ export default App;
332
+ ```
333
+
334
+ ---
335
+
336
+ ## API Reference
337
+
338
+ ### SpacemanThemeProvider
339
+
340
+ Context provider for centralized theme state management.
341
+
342
+ ```tsx
343
+ <SpacemanThemeProvider
344
+ defaultTheme="system"
345
+ defaultColorTheme="blue"
346
+ themes={['light', 'dark', 'system']}
347
+ colorThemes={['default', 'blue', 'green', 'purple']}
348
+ animationType={ThemeAnimationType.CIRCLE}
349
+ duration={800}
350
+ onThemeChange={theme => console.log('Theme:', theme)}
351
+ onColorThemeChange={colorTheme => console.log('Color:', colorTheme)}
352
+ >
353
+ <App />
354
+ </SpacemanThemeProvider>
355
+ ```
356
+
357
+ #### SpacemanThemeProvider Props
358
+
359
+ | Property | Type | Default | Description |
360
+ | -------------------- | ---------------------------------- | ----------------------------- | ------------------------------------- |
361
+ | `defaultTheme` | `Theme` | `'system'` | Initial theme |
362
+ | `defaultColorTheme` | `ColorTheme` | `'default'` | Initial color theme |
363
+ | `themes` | `Theme[]` | `['light', 'dark', 'system']` | Available themes |
364
+ | `colorThemes` | `ColorTheme[]` | `['default']` | Available color themes |
365
+ | `animationType` | `ThemeAnimationType` | `ThemeAnimationType.CIRCLE` | Animation type |
366
+ | `duration` | `number` | `500` | Animation duration in ms |
367
+ | `blurAmount` | `number` | `2` | Blur amount for blur-circle animation |
368
+ | `onThemeChange` | `(theme: Theme) => void` | - | Global theme change callback |
369
+ | `onColorThemeChange` | `(colorTheme: ColorTheme) => void` | - | Global color theme change callback |
370
+
371
+ ### useSpacemanTheme
372
+
373
+ Hook to access theme state from SpacemanThemeProvider context.
374
+
375
+ ```tsx
376
+ const { theme, colorTheme, switchTheme, setColorTheme, switchThemeFromElement, ref } =
377
+ useSpacemanTheme();
378
+ ```
379
+
380
+ #### Returns
381
+
382
+ | Property | Type | Description |
383
+ | ------------------------ | ------------------------------------------------------- | ------------------------------------------------- |
384
+ | `theme` | `Theme` | Current theme |
385
+ | `colorTheme` | `ColorTheme` | Current color theme |
386
+ | `switchTheme` | `(theme: Theme) => Promise<void>` | Switch to specific theme |
387
+ | `setColorTheme` | `(colorTheme: ColorTheme) => void` | Set color theme |
388
+ | `switchThemeFromElement` | `(theme: Theme, element: HTMLElement) => Promise<void>` | Switch theme with animation from specific element |
389
+ | `ref` | `RefObject<HTMLElement>` | Ref for animation origin |
390
+
391
+ ### useThemeAnimation
392
+
393
+ Standalone hook for theme management and animations.
394
+
395
+ ```tsx
396
+ const { theme, colorTheme, switchTheme, setColorTheme, toggleTheme, ref } = useThemeAnimation({
397
+ themes: ['light', 'dark', 'system'],
398
+ colorThemes: ['default', 'blue', 'green', 'purple'],
399
+ animationType: ThemeAnimationType.SCALE,
400
+ duration: 800,
401
+ onThemeChange: theme => console.log('Theme changed:', theme),
402
+ onColorThemeChange: colorTheme => console.log('Color changed:', colorTheme),
403
+ });
404
+ ```
405
+
406
+ #### Options
407
+
408
+ | Property | Type | Default | Description |
409
+ | -------------------- | ---------------------------------- | ----------------------------- | ------------------------------------- |
410
+ | `themes` | `Theme[]` | `['light', 'dark', 'system']` | Available themes |
411
+ | `colorThemes` | `ColorTheme[]` | `['default']` | Available color themes |
412
+ | `theme` | `Theme` | `'system'` | Initial theme |
413
+ | `colorTheme` | `ColorTheme` | `'default'` | Initial color theme |
414
+ | `animationType` | `ThemeAnimationType` | `ThemeAnimationType.CIRCLE` | Animation type |
415
+ | `duration` | `number` | `500` | Animation duration in ms |
416
+ | `blurAmount` | `number` | `2` | Blur amount for blur-circle animation |
417
+ | `onThemeChange` | `(theme: Theme) => void` | - | Theme change callback |
418
+ | `onColorThemeChange` | `(colorTheme: ColorTheme) => void` | - | Color theme change callback |
419
+
420
+ #### Return
421
+
422
+ | Property | Type | Description |
423
+ | --------------- | ---------------------------------- | ------------------------- |
424
+ | `theme` | `Theme` | Current theme |
425
+ | `colorTheme` | `ColorTheme` | Current color theme |
426
+ | `switchTheme` | `(theme: Theme) => Promise<void>` | Switch to specific theme |
427
+ | `setColorTheme` | `(colorTheme: ColorTheme) => void` | Set color theme |
428
+ | `toggleTheme` | `() => Promise<void>` | Toggle between light/dark |
429
+ | `ref` | `RefObject<HTMLElement>` | Ref for animation origin |
430
+
431
+ ### ThemeSwitcher
432
+
433
+ Pre-built theme switcher component with animated buttons.
434
+
435
+ ```tsx
436
+ <ThemeSwitcher
437
+ themes={['light', 'dark', 'system']}
438
+ currentTheme="light"
439
+ onThemeChange={theme => console.log(theme)}
440
+ animationType={ThemeAnimationType.CIRCLE}
441
+ duration={600}
442
+ className="custom-class"
443
+ />
444
+ ```
445
+
446
+ #### ThemeSwitcher Props
447
+
448
+ | Property | Type | Default | Description |
449
+ | --------------- | ------------------------ | ----------------------------- | ----------------------------------- |
450
+ | `themes` | `Theme[]` | `['light', 'dark', 'system']` | Available themes |
451
+ | `currentTheme` | `Theme` | - | Controlled current theme (optional) |
452
+ | `onThemeChange` | `(theme: Theme) => void` | - | Theme change callback (optional) |
453
+ | `animationType` | `ThemeAnimationType` | `ThemeAnimationType.CIRCLE` | Animation type |
454
+ | `duration` | `number` | `500` | Animation duration in ms |
455
+ | `className` | `string` | - | Additional CSS classes |
456
+
457
+ > **Note**: When used with `SpacemanThemeProvider`, `currentTheme` and `onThemeChange` are automatically handled by the context.
458
+
459
+ ### ThemeSelector
460
+
461
+ Dropdown selector for color themes.
462
+
463
+ ```tsx
464
+ <ThemeSelector
465
+ colorThemes={['default', 'blue', 'green', 'purple']}
466
+ currentColorTheme="blue"
467
+ onColorThemeChange={colorTheme => console.log(colorTheme)}
468
+ animationType={ThemeAnimationType.BLUR_CIRCLE}
469
+ duration={400}
470
+ />
471
+ ```
472
+
473
+ #### ThemeSelector Props
474
+
475
+ | Property | Type | Default | Description |
476
+ | -------------------- | ---------------------------------- | ----------------------------- | ----------------------------------------- |
477
+ | `themes` | `Theme[]` | `['light', 'dark', 'system']` | Available themes (for standalone hook) |
478
+ | `colorThemes` | `ColorTheme[]` | `['default']` | Available color themes |
479
+ | `currentColorTheme` | `ColorTheme` | - | Controlled current color theme (optional) |
480
+ | `onColorThemeChange` | `(colorTheme: ColorTheme) => void` | - | Color theme change callback (optional) |
481
+ | `animationType` | `ThemeAnimationType` | `ThemeAnimationType.CIRCLE` | Animation type |
482
+ | `duration` | `number` | `500` | Animation duration in ms |
483
+
484
+ > **Note**: When used with `SpacemanThemeProvider`, `currentColorTheme` and `onColorThemeChange` are automatically handled by the context.
485
+
486
+ ### ThemeAnimationType
487
+
488
+ Animation types for theme transitions.
489
+
490
+ ```tsx
491
+ enum ThemeAnimationType {
492
+ CIRCLE = 'circle',
493
+ BLUR_CIRCLE = 'blur-circle',
494
+ }
495
+ ```
496
+
497
+ ### Types
498
+
499
+ ```tsx
500
+ type Theme = 'light' | 'dark' | 'system';
501
+ type ColorTheme = string; // e.g., 'default', 'blue', 'green', etc.
502
+
503
+ interface SpacemanThemeProviderProps {
504
+ children: React.ReactNode;
505
+ defaultTheme?: Theme;
506
+ defaultColorTheme?: ColorTheme;
507
+ themes?: Theme[];
508
+ colorThemes?: ColorTheme[];
509
+ animationType?: ThemeAnimationType;
510
+ duration?: number;
511
+ blurAmount?: number;
512
+ onThemeChange?: (theme: Theme) => void;
513
+ onColorThemeChange?: (colorTheme: ColorTheme) => void;
514
+ }
515
+
516
+ interface UseThemeAnimationProps {
517
+ themes?: Theme[];
518
+ colorThemes?: ColorTheme[];
519
+ theme?: Theme;
520
+ colorTheme?: ColorTheme;
521
+ animationType?: ThemeAnimationType;
522
+ duration?: number;
523
+ blurAmount?: number;
524
+ onThemeChange?: (theme: Theme) => void;
525
+ onColorThemeChange?: (colorTheme: ColorTheme) => void;
526
+ }
527
+
528
+ interface UseThemeAnimationReturn {
529
+ theme: Theme;
530
+ colorTheme: ColorTheme;
531
+ switchTheme: (theme: Theme) => Promise<void>;
532
+ setColorTheme: (colorTheme: ColorTheme) => void;
533
+ toggleTheme: () => Promise<void>;
534
+ ref: RefObject<HTMLElement>;
535
+ }
536
+
537
+ interface ThemeSwitcherProps {
538
+ themes?: Theme[];
539
+ currentTheme?: Theme;
540
+ onThemeChange?: (theme: Theme) => void;
541
+ animationType?: ThemeAnimationType;
542
+ duration?: number;
543
+ className?: string;
544
+ }
545
+
546
+ interface ThemeSelectorProps {
547
+ themes?: Theme[];
548
+ colorThemes?: ColorTheme[];
549
+ currentColorTheme?: ColorTheme;
550
+ onColorThemeChange?: (colorTheme: ColorTheme) => void;
551
+ animationType?: ThemeAnimationType;
552
+ duration?: number;
553
+ }
554
+ ```
555
+
556
+ ---
557
+
558
+ ## CSS Variables
559
+
560
+ The library uses CSS custom properties for theming. Define these in your CSS:
561
+
562
+ ```css
563
+ /* Base theme variables */
564
+ :root {
565
+ --background: 0 0% 100%;
566
+ --foreground: 222.2 84% 4.9%;
567
+ }
568
+
569
+ /* Dark theme */
570
+ .dark {
571
+ --background: 222.2 84% 4.9%;
572
+ --foreground: 210 40% 98%;
573
+ }
574
+
575
+ /* Add other theme variants from design system or tweakcn */
576
+
577
+ .theme-supabase {
578
+ --background: oklch(0.9911 0 0);
579
+ --foreground: oklch(0.2046 0 0);
580
+ }
581
+
582
+ .theme-supabase.dark {
583
+ --background: oklch(0.1822 0 0);
584
+ --foreground: oklch(0.9288 0.0126 255.5078);
585
+ }
586
+
587
+ .theme-mono {
588
+ --background: oklch(1 0 0);
589
+ --foreground: oklch(0.1448 0 0);
590
+ }
591
+
592
+ .theme-mono.dark {
593
+ --background: oklch(0.1448 0 0);
594
+ --foreground: oklch(1 0 0);
595
+ }
596
+ ```
597
+
598
+ ---
599
+
600
+ ## Browser Support
601
+
602
+ - **View Transitions API**: Chrome 111+, Edge 111+
603
+ - **Fallback**: All modern browsers with CSS transitions
604
+ - **Reduced Motion**: Respects `prefers-reduced-motion` setting
605
+ - **Framework Support**: React 16.8+ (hooks required)
606
+
607
+ ---
608
+
609
+ ## Performance
610
+
611
+ - Animations use the View Transitions API when available
612
+ - Optimized for 60fps animations
613
+ - Respects `prefers-reduced-motion` setting
614
+
615
+ ---
616
+
617
+ ## Contributing
618
+
619
+ Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.
620
+
621
+ ## License
622
+
623
+ MIT
@@ -0,0 +1,51 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { Theme, ColorTheme, ThemeAnimationType } from '../types';
3
+ /**
4
+ * Context type for the Spaceman Theme Provider
5
+ */
6
+ interface SpacemanThemeContextType {
7
+ theme: Theme;
8
+ colorTheme: ColorTheme;
9
+ resolvedTheme: 'light' | 'dark';
10
+ setTheme: (theme: Theme) => void;
11
+ setColorTheme: (colorTheme: ColorTheme) => void;
12
+ toggleTheme: () => Promise<void>;
13
+ switchTheme: (theme: Theme) => Promise<void>;
14
+ switchThemeFromElement: (theme: Theme, element: HTMLButtonElement) => Promise<void>;
15
+ ref: React.RefObject<HTMLButtonElement | null>;
16
+ }
17
+ /**
18
+ * Props for the Spaceman Theme Provider
19
+ */
20
+ interface SpacemanThemeProviderProps {
21
+ children: ReactNode;
22
+ themes?: Theme[];
23
+ colorThemes?: ColorTheme[];
24
+ defaultTheme?: Theme;
25
+ defaultColorTheme?: ColorTheme;
26
+ animationType?: ThemeAnimationType;
27
+ duration?: number;
28
+ }
29
+ /**
30
+ * Spaceman Theme Provider - Provides centralized theme state management
31
+ *
32
+ * This provider creates a single source of truth for theme state using the useThemeAnimation hook.
33
+ * All theme-related components should consume from this context to ensure synchronization.
34
+ *
35
+ * @param children - React children to wrap with theme context
36
+ * @param themes - Available theme options (default: ['light', 'dark', 'system'])
37
+ * @param colorThemes - Available color theme options (default: ['default'])
38
+ * @param defaultTheme - Default theme to use (default: 'system')
39
+ * @param defaultColorTheme - Default color theme to use (default: 'default')
40
+ * @param animationType - Animation type for theme transitions (default: CIRCLE)
41
+ * @param duration - Animation duration in milliseconds (default: 750)
42
+ */
43
+ export declare const SpacemanThemeProvider: React.FC<SpacemanThemeProviderProps>;
44
+ /**
45
+ * Hook to consume the Spaceman Theme context
46
+ *
47
+ * @returns Theme context value with all theme state and methods
48
+ * @throws Error if used outside of SpacemanThemeProvider
49
+ */
50
+ export declare const useSpacemanTheme: () => SpacemanThemeContextType;
51
+ export {};