@space-man/react-theme-animation 2.1.0 → 3.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 (60) hide show
  1. package/README.md +115 -164
  2. package/dist/animations-CaaRrn3-.d.ts +208 -0
  3. package/dist/chunk-FNL7ZHF4.js +44 -0
  4. package/dist/chunk-I3T2QXRT.js +18 -0
  5. package/dist/chunk-QYUMCBTQ.js +1 -0
  6. package/dist/chunk-X6UEG7WG.js +12 -0
  7. package/dist/core/index.d.ts +9 -0
  8. package/dist/core/index.js +1 -0
  9. package/dist/index.d.ts +5 -0
  10. package/dist/index.js +1 -0
  11. package/dist/logo-DtwtRv4y.d.ts +4 -0
  12. package/dist/react/index.d.ts +228 -0
  13. package/dist/react/index.js +2 -0
  14. package/dist/tanstack/index.d.ts +20 -0
  15. package/dist/tanstack/index.js +1 -0
  16. package/package.json +82 -63
  17. package/dist/cjs/components/NextThemeProvider.d.ts +0 -81
  18. package/dist/cjs/components/NextThemeProvider.js +0 -223
  19. package/dist/cjs/components/SpacemanThemeProvider.d.ts +0 -57
  20. package/dist/cjs/components/SpacemanThemeProvider.js +0 -113
  21. package/dist/cjs/components/TanStackThemeProvider.d.ts +0 -68
  22. package/dist/cjs/components/TanStackThemeProvider.js +0 -183
  23. package/dist/cjs/components/ThemeSelector.d.ts +0 -3
  24. package/dist/cjs/components/ThemeSelector.js +0 -39
  25. package/dist/cjs/components/ThemeSwitcher.d.ts +0 -3
  26. package/dist/cjs/components/ThemeSwitcher.js +0 -81
  27. package/dist/cjs/components/ViteThemeProvider.d.ts +0 -61
  28. package/dist/cjs/components/ViteThemeProvider.js +0 -140
  29. package/dist/cjs/components/ui/select.d.ts +0 -15
  30. package/dist/cjs/components/ui/select.js +0 -83
  31. package/dist/cjs/hooks/use-theme-animation.d.ts +0 -2
  32. package/dist/cjs/hooks/use-theme-animation.js +0 -234
  33. package/dist/cjs/index.d.ts +0 -10
  34. package/dist/cjs/index.js +0 -30
  35. package/dist/cjs/types/index.d.ts +0 -78
  36. package/dist/cjs/types/index.js +0 -9
  37. package/dist/cjs/utils/animations.d.ts +0 -21
  38. package/dist/cjs/utils/animations.js +0 -189
  39. package/dist/esm/components/NextThemeProvider.d.ts +0 -81
  40. package/dist/esm/components/NextThemeProvider.js +0 -185
  41. package/dist/esm/components/SpacemanThemeProvider.d.ts +0 -57
  42. package/dist/esm/components/SpacemanThemeProvider.js +0 -108
  43. package/dist/esm/components/TanStackThemeProvider.d.ts +0 -68
  44. package/dist/esm/components/TanStackThemeProvider.js +0 -178
  45. package/dist/esm/components/ThemeSelector.d.ts +0 -3
  46. package/dist/esm/components/ThemeSelector.js +0 -35
  47. package/dist/esm/components/ThemeSwitcher.d.ts +0 -3
  48. package/dist/esm/components/ThemeSwitcher.js +0 -77
  49. package/dist/esm/components/ViteThemeProvider.d.ts +0 -61
  50. package/dist/esm/components/ViteThemeProvider.js +0 -135
  51. package/dist/esm/components/ui/select.d.ts +0 -15
  52. package/dist/esm/components/ui/select.js +0 -39
  53. package/dist/esm/hooks/use-theme-animation.d.ts +0 -2
  54. package/dist/esm/hooks/use-theme-animation.js +0 -230
  55. package/dist/esm/index.d.ts +0 -10
  56. package/dist/esm/index.js +0 -10
  57. package/dist/esm/types/index.d.ts +0 -78
  58. package/dist/esm/types/index.js +0 -6
  59. package/dist/esm/utils/animations.d.ts +0 -21
  60. package/dist/esm/utils/animations.js +0 -177
package/README.md CHANGED
@@ -1,32 +1,35 @@
1
1
  # @space-man/react-theme-animation
2
2
 
3
- https://github.com/user-attachments/assets/2819cf70-c474-478e-b821-6b26457c8d4a
4
-
5
3
  React theme switching with smooth view transition animations, multi-theme support, and synchronized state management.
6
4
 
7
- ## What's New in v2.1
5
+ ## Module support
6
+
7
+ This package ships ESM only. Use `import` or dynamic `import()` instead of
8
+ `require()`. TypeScript declarations are included. The package does not ship
9
+ source maps. Both built-in controls and their required dependencies remain
10
+ available through the existing exports.
11
+
12
+ ## Spaceman React Theme Animation v2 release
13
+
14
+ Version 2 moves the library into a workspace-friendly monorepo, keeps the published package name stable, and standardizes the public API around flat root imports.
8
15
 
9
- - **animationOff Parameter**: Instantly switch themes without animation via optional parameter on all toggle functions
10
- - **Universal SSR Support**: Pre-hydration script prevents flash in Next.js, Remix, and SSR frameworks
11
- - **Three Framework-Specific Providers**: NextThemeProvider (SSR/Next.js), TanStackThemeProvider (TanStack Start), ViteThemeProvider (Vite SPAs)
12
- - **Consistent Hook API**: All providers expose identical hook interface with 15+ methods
13
- - **Enhanced Theme Control**: Direct functions for toggleLightTheme(), toggleDarkTheme(), createColorThemeToggle()
16
+ Highlights in this release:
14
17
 
15
- ## Live Demo
18
+ - root-first public API via `@space-man/react-theme-animation`
19
+ - framework-specific providers for Next.js, TanStack Start, and Vite
20
+ - TanStack SSR helpers exposed from the root package
21
+ - workspace examples for Next.js, TanStack Start, and TanStack Start SSR
22
+ - build and packaging updates for ESM and declaration output
16
23
 
17
- [View Live Demo](https://spaceman-rta-vite.netlify.app/)
24
+ ## Required dependencies
18
25
 
19
- ## Features
26
+ Radix Select, Motion, React, and React DOM remain required peer dependencies. `clsx` remains a direct dependency. Keep compatible peers installed even when the application uses only hooks. The controls remain included in this package.
20
27
 
21
- - Smooth view transition animations with customizable origins
22
- - Multi-theme support (light, dark, system)
23
- - Color theme variants (brand colors, custom themes)
24
- - Three framework-optimized providers
25
- - Powerful useThemeAnimation hook for custom implementations
26
- - Ready-to-use ThemeSwitcher and ThemeSelector components
27
- - State synchronization across components
28
- - Full TypeScript support
29
- - Performance optimized with reduced motion support
28
+ The planned v3 release requires React and React DOM 18 or newer, Motion 12 or newer, and Radix Select 2 or newer. React 17 is no longer supported. Extracted-package checks cover React 18.0, Motion 12.0, and Radix 2.0 together, plus the current development versions. See the [readiness audit](https://github.com/tonyedgal/spaceman-react-theme-animation/blob/main/docs/release-readiness.md) for release evidence.
29
+
30
+ Storage is optional persistence. Blocked reads use the configured defaults. Failed writes still update the theme for the current page. Saved preferences become visible after hydration, so the first client render matches the server HTML.
31
+
32
+ `ThemeSelector` applies `className`, `placeholder`, and `colorThemeLabel`. The label is linked to the dropdown trigger. Its `onColorThemeChange` callback also runs inside a provider. `themeLabel` is deprecated because this control selects palettes; use `ThemeSwitcher` for light, dark, and system modes.
30
33
 
31
34
  ## Installation
32
35
 
@@ -34,26 +37,70 @@ React theme switching with smooth view transition animations, multi-theme suppor
34
37
  npm install @space-man/react-theme-animation
35
38
  ```
36
39
 
40
+ ```bash
41
+ pnpm add @space-man/react-theme-animation
42
+ ```
43
+
44
+ ```bash
45
+ yarn add @space-man/react-theme-animation
46
+ ```
47
+
48
+ ## Imports
49
+
50
+ Import everything from the package root:
51
+
52
+ ```tsx
53
+ import {
54
+ NextThemeProvider,
55
+ TanStackThemeProvider,
56
+ ViteThemeProvider,
57
+ ThemeSwitcher,
58
+ ThemeSelector,
59
+ useThemeAnimation,
60
+ } from '@space-man/react-theme-animation'
61
+ ```
62
+
63
+ The root is the documented client API. Existing subpath exports remain. Use `/tanstack` for server cookie helpers and `/core` for server utilities. The root entry also imports the React controls and Motion; it is not a server-only entry.
64
+
65
+ For Next.js App Router, import providers/hooks from the package root inside client components. A
66
+ typical setup is a local `app/providers.tsx` file with `'use client'`, rendered by the server
67
+ `app/layout.tsx`.
68
+
69
+ ## Tailwind Setup For Prebuilt Components
70
+
71
+ `ThemeSwitcher`, `ThemeSelector`, and the bundled select primitives use Tailwind utility classes. The package does not ship a compiled stylesheet for those components, so the consuming app must include the installed package in Tailwind's source scan.
72
+
73
+ For Tailwind v4, add an `@source` directive next to your Tailwind import:
74
+
75
+ ```css
76
+ @import 'tailwindcss';
77
+ @source '../node_modules/@space-man/react-theme-animation/dist';
78
+ ```
79
+
80
+ Adjust the relative path to match your app structure.
81
+
37
82
  ## Provider Selection
38
83
 
39
84
  Choose the right provider for your framework:
40
85
 
41
- | Provider | Best For | Key Features |
42
- | --------------------- | ------------------------------ | ------------------------------------------------ |
43
- | NextThemeProvider | Next.js, Remix, SSR frameworks | Pre-hydration script, CSP support, animations |
44
- | TanStackThemeProvider | TanStack Start apps | Isomorphic rendering, useHydrated() integration |
45
- | ViteThemeProvider | Vite React SPAs | Lightweight, transition control, no SSR overhead |
86
+ | Provider | Best For | Key Features |
87
+ | --------------------- | ------------------------------ | ------------------------------------------------- |
88
+ | SpacemanThemeProvider | General React apps | Universal provider with synchronized theme state |
89
+ | NextThemeProvider | Next.js, Remix, SSR frameworks | Pre-hydration script, CSP support, animations |
90
+ | TanStackThemeProvider | TanStack Start apps | Cookie SSR, pre-hydration script, system CSS mode |
91
+ | ViteThemeProvider | Vite React SPAs | Lightweight, transition control, no SSR overhead |
46
92
 
47
93
  ## Quick Start
48
94
 
49
- Basic pattern that works across all providers:
50
-
51
95
  ```tsx
52
- import { SpacemanThemeProvider, useSpacemanTheme } from '@space-man/react-theme-animation'
96
+ import {
97
+ SpacemanThemeProvider,
98
+ useSpacemanTheme,
99
+ } from '@space-man/react-theme-animation'
53
100
 
54
101
  function App() {
55
102
  return (
56
- <SpacemanThemeProvider defaultTheme="system" defaultColorTheme="default">
103
+ <SpacemanThemeProvider defaultTheme='system' defaultColorTheme='default'>
57
104
  <YourApp />
58
105
  </SpacemanThemeProvider>
59
106
  )
@@ -70,149 +117,53 @@ function ThemeToggle() {
70
117
  }
71
118
  ```
72
119
 
73
- **Choose your framework setup guide:**
120
+ ## Documentation
74
121
 
75
- - **[Next.js / SSR Setup Guide](./docs/nextjs-setup.md)** - Complete guide with App Router, Pages Router, CSP support
76
- - **[TanStack Start Setup Guide](./docs/tanstack-start-setup.md)** - Isomorphic rendering, hydration-safe patterns
77
- - **[Vite React SPA Setup Guide](./docs/vite-setup.md)** - Client-side setup, flash prevention, routing
122
+ Repository documentation, framework guides, migration notes, and examples are linked from the GitHub docs hub:
78
123
 
79
- **[View Complete Examples](./example/)** - Next.js implementation with both hook and provider patterns
124
+ - https://github.com/tonyedgal/spaceman-react-theme-animation#documentation
80
125
 
81
126
  ## API Reference
82
127
 
83
128
  ### Shared Hook Return (All Providers)
84
129
 
85
- All providers expose the same hook interface:
86
-
87
- | Property | Type | Description |
88
- | ---------------------- | ------------------------------------------------------- | ---------------------------------- |
89
- | theme | Theme | Current theme |
90
- | colorTheme | ColorTheme | Current color theme |
91
- | resolvedTheme | 'light' \| 'dark' | Resolved theme (system → actual) |
92
- | systemTheme | 'light' \| 'dark' | OS theme preference |
93
- | ref | RefObject<HTMLElement> | Ref for animation origin |
94
- | setTheme | (theme: Theme) => void | Set theme instantly |
95
- | setColorTheme | (colorTheme: ColorTheme) => void | Set color theme |
96
- | switchTheme | (theme: Theme, animationOff?: boolean) => Promise<void> | Switch with animation |
97
- | switchColorTheme | (colorTheme: string) => void | Switch color theme with animation |
98
- | toggleTheme | (animationOff?: boolean) => Promise<void> | Toggle light/dark |
99
- | toggleLightTheme | (animationOff?: boolean) => Promise<void> | Toggle to light |
100
- | toggleDarkTheme | (animationOff?: boolean) => Promise<void> | Toggle to dark |
101
- | toggleColorTheme | () => void | Toggle between color themes |
102
- | createColorThemeToggle | (colorTheme: string) => () => void | Create color theme toggle |
103
- | isColorThemeActive | (colorTheme: string) => boolean | Check if color theme active |
104
- | switchThemeFromElement | (theme: Theme, element: HTMLElement) => Promise<void> | Switch with animation from element |
105
-
106
- ### Provider Props
107
-
108
- | Prop | Spaceman | NextTheme | TanStack | Vite | Type | Default |
109
- | ------------------------- | -------- | --------- | -------- | ---- | ------------------ | --------------------------- |
110
- | defaultTheme | ✓ | ✓ | ✓ | ✓ | Theme | 'system' |
111
- | defaultColorTheme | ✓ | ✓ | ✓ | ✓ | ColorTheme | 'default' |
112
- | themes | ✓ | ✓ | ✓ | ✓ | Theme[] | ['light', 'dark', 'system'] |
113
- | colorThemes | ✓ | ✓ | ✓ | ✓ | ColorTheme[] | ['default'] |
114
- | animationType | ✓ | ✓ | ✓ | ✓ | ThemeAnimationType | CIRCLE |
115
- | duration | ✓ | ✓ | ✓ | ✓ | number | 500 |
116
- | storageKey | ✓ | ✓ | ✓ | ✓ | string | varies |
117
- | colorStorageKey | ✓ | ✓ | ✓ | ✓ | string | varies |
118
- | nonce | ✗ | ✓ | ✗ | ✗ | string | - |
119
- | disablePreHydrationScript | ✗ | ✓ | ✗ | ✗ | boolean | false |
120
- | disableTransitionOnChange | ✗ | ✗ | ✗ | ✓ | boolean | false |
121
- | onThemeChange | ✓ | ✓ | ✓ | ✓ | function | - |
122
- | onColorThemeChange | ✓ | ✓ | ✓ | ✓ | function | - |
123
-
124
- ### Components
125
-
126
- **ThemeSwitcher**: Pre-built theme toggle buttons with animations
127
- **ThemeSelector**: Dropdown selector for color themes
128
-
129
- See framework-specific guides for component usage examples.
130
-
131
- ---
132
-
133
- <details>
134
- <summary>CSS Variables Setup</summary>
135
-
136
- Define theme variables in your global CSS file:
137
-
138
- ```css
139
- :root {
140
- --background: 0 0% 100%;
141
- --foreground: 222.2 84% 4.9%;
142
- --primary: 221.2 83.2% 53.3%;
143
- }
144
-
145
- .dark {
146
- --background: 222.2 84% 4.9%;
147
- --foreground: 210 40% 98%;
148
- --primary: 217.2 91.2% 59.8%;
149
- }
150
-
151
- /* Color theme variants */
152
- .theme-blue {
153
- --primary: 221.2 83.2% 53.3%;
154
- }
155
-
156
- .theme-blue.dark {
157
- --primary: 217.2 91.2% 59.8%;
158
- }
159
-
160
- .theme-green {
161
- --primary: 142.1 76.2% 36.3%;
162
- }
163
-
164
- .theme-green.dark {
165
- --primary: 142.1 70.6% 45.3%;
166
- }
167
- ```
168
-
169
- </details>
170
-
171
- <details>
172
- <summary>Browser Support</summary>
173
-
174
- - View Transitions API: Chrome 111+, Edge 111+
175
- - Fallback: All modern browsers with CSS transitions
176
- - Reduced Motion: Respects prefers-reduced-motion
177
- - Framework Support: React 16.8+ (hooks required)
178
-
179
- </details>
180
-
181
- <details>
182
- <summary>Advanced Configuration</summary>
183
-
184
- ### Animation Control
185
-
186
- ```tsx
187
- const { switchTheme, toggleTheme } = useSpacemanTheme()
188
-
189
- // With animation (default)
190
- await switchTheme('dark')
191
-
192
- // Without animation
193
- await switchTheme('dark', true)
194
- await toggleTheme(true)
195
- ```
196
-
197
- ### Custom Hook Usage
198
-
199
- ```tsx
200
- import { useThemeAnimation } from '@space-man/react-theme-animation'
201
-
202
- const { theme, toggleTheme, ref } = useThemeAnimation({
203
- animationType: ThemeAnimationType.BLUR_CIRCLE,
204
- duration: 750,
205
- colorThemes: ['default', 'blue', 'green'],
206
- onThemeChange: theme => console.log('Theme:', theme),
207
- })
208
- ```
209
-
210
- </details>
211
-
212
- ## Contributing
213
-
214
- Fork the repository, make your changes, and submit a merge request for review.
130
+ All providers expose the same core hook interface:
131
+
132
+ | Property | Type | Description |
133
+ | ---------------------- | --------------------------------------------------------------------- | ---------------------------------- |
134
+ | theme | Theme | Current theme |
135
+ | colorTheme | ColorTheme | Current color theme |
136
+ | resolvedTheme | 'light' \| 'dark' | Resolved theme (system → actual) |
137
+ | systemTheme | 'light' \| 'dark' | OS theme preference |
138
+ | ref | RefObject<HTMLButtonElement \| null> | Ref for animation origin |
139
+ | setTheme | (theme: Theme) => void | Set theme instantly |
140
+ | setColorTheme | (colorTheme: ColorTheme) => void | Set color theme |
141
+ | switchTheme | (theme: Theme, options?: ThemeTransitionInput) => Promise<void> | Switch with animation |
142
+ | switchColorTheme | (colorTheme: string, options?: ThemeTransitionInput) => Promise<void> | Switch color theme with animation |
143
+ | toggleTheme | (options?: ThemeTransitionInput) => Promise<void> | Toggle light/dark |
144
+ | toggleLightTheme | (options?: ThemeTransitionInput) => Promise<void> | Toggle to light |
145
+ | toggleDarkTheme | (options?: ThemeTransitionInput) => Promise<void> | Toggle to dark |
146
+ | toggleColorTheme | ColorThemeToggle | Toggle between color themes |
147
+ | createColorThemeToggle | (colorTheme: string) => ColorThemeToggle | Create color theme toggle |
148
+ | isColorThemeActive | (colorTheme: string) => boolean | Check if color theme active |
149
+ | switchThemeFromElement | (theme: Theme, element: HTMLButtonElement) => Promise<void> | Switch with animation from element |
150
+
151
+ ### Root Exports
152
+
153
+ The root package exports:
154
+
155
+ - providers and framework hooks
156
+ - prebuilt `ThemeSwitcher` and `ThemeSelector`
157
+ - `useThemeAnimation`
158
+ - shared types and animation utilities
159
+ - TanStack server helpers such as `buildServerThemeData`, `STORAGE_KEY`, and `COLOR_STORAGE_KEY`
160
+
161
+ See the repository docs hub for provider-specific setup guides and examples.
215
162
 
216
163
  ## License
217
164
 
218
165
  MIT
166
+
167
+ ## Additional transition effects
168
+
169
+ See [Theme transitions](https://github.com/tonyedgal/spaceman-react-theme-animation/blob/main/packages/react-theme-animation/docs/theme-transitions.md) for animated palettes, explicit origins, directional polygon wipes, triangles, and stationary SVG logos with destination assets and automatic sizing.
@@ -0,0 +1,208 @@
1
+ import { RefObject } from 'react';
2
+
3
+ declare enum ThemeAnimationType {
4
+ CIRCLE = "circle",
5
+ BLUR_CIRCLE = "blur-circle",
6
+ SLIDE = "slide",
7
+ CLIP_PATH = "clip-path",
8
+ POLYGON_GRADIENT = "polygon-gradient",
9
+ TRIANGLE = "triangle",
10
+ SVG_LOGO = "svg-logo"
11
+ }
12
+ type SlideDirection = 'left' | 'right' | 'top' | 'bottom' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
13
+ /** Clockwise from the top-left corner. */
14
+ declare const TRANSITION_DIRECTIONS: readonly ["top-left", "top", "top-right", "right", "bottom-right", "bottom", "bottom-left", "left"];
15
+ type TransitionDirection = (typeof TRANSITION_DIRECTIONS)[number];
16
+ type AnimationPosition = TransitionDirection | 'center' | 'trigger';
17
+ interface ThemeAnimationSettings {
18
+ /** Starting edge/corner for polygon wipes. Defaults to top-left. */
19
+ readonly clipPathDirection?: TransitionDirection;
20
+ /** Fixed circle/triangle origin; SVG_LOGO always uses the viewport center. */
21
+ readonly animationPosition?: AnimationPosition;
22
+ /** Stationary logo width in CSS pixels or auto; default is 96 when both are omitted. */
23
+ readonly logoWidth?: number | 'auto';
24
+ /** Logo height in CSS pixels or auto; omitted dimensions preserve the SVG aspect ratio. */
25
+ readonly logoHeight?: number | 'auto';
26
+ /** Gradient wipe feather in CSS pixels; defaults to 80. */
27
+ readonly gradientWidth?: number;
28
+ }
29
+ /** Choose one shared asset, or both destination-specific assets. */
30
+ type ThemeLogoOptions = {
31
+ readonly logo?: string;
32
+ readonly logoLight?: never;
33
+ readonly logoDark?: never;
34
+ } | {
35
+ readonly logo?: never;
36
+ readonly logoLight: string;
37
+ readonly logoDark: string;
38
+ };
39
+ type ThemeAnimationOptions = ThemeAnimationSettings & ThemeLogoOptions;
40
+ interface AnimationConfig extends ThemeAnimationSettings {
41
+ /** Asset already selected for the destination theme before capture. */
42
+ readonly logo?: string;
43
+ readonly a?: number;
44
+ readonly b?: number;
45
+ readonly x: number;
46
+ readonly y: number;
47
+ readonly duration: number;
48
+ readonly easing: string;
49
+ readonly animationType: ThemeAnimationType;
50
+ readonly blurAmount: number;
51
+ readonly styleId: string;
52
+ }
53
+ type Theme = 'light' | 'dark' | 'system';
54
+ type ColorTheme = string;
55
+ type SystemThemeMode = 'css' | 'js';
56
+ type UseThemeAnimationProps = ThemeAnimationOptions & {
57
+ readonly duration?: number;
58
+ readonly easing?: string;
59
+ readonly animationType?: ThemeAnimationType;
60
+ readonly blurAmount?: number;
61
+ readonly styleId?: string;
62
+ readonly themes?: readonly Theme[];
63
+ readonly colorThemes?: readonly ColorTheme[];
64
+ readonly defaultTheme?: Theme;
65
+ readonly defaultColorTheme?: ColorTheme;
66
+ readonly globalClassName?: string;
67
+ readonly colorThemePrefix?: string;
68
+ readonly attribute?: 'class' | 'data-theme';
69
+ readonly value?: Record<string, string>;
70
+ readonly enableColorScheme?: boolean;
71
+ readonly storageKey?: string;
72
+ readonly colorStorageKey?: string;
73
+ readonly theme?: Theme;
74
+ readonly colorTheme?: ColorTheme;
75
+ readonly onThemeChange?: (theme: Theme) => void;
76
+ readonly onColorThemeChange?: (colorTheme: ColorTheme) => void;
77
+ readonly initialTheme?: Theme;
78
+ readonly initialColorTheme?: ColorTheme;
79
+ readonly systemThemeMode?: SystemThemeMode;
80
+ readonly slideDirection?: SlideDirection;
81
+ readonly slideFromX?: number;
82
+ readonly slideFromY?: number;
83
+ readonly slideToX?: number;
84
+ readonly slideToY?: number;
85
+ };
86
+ /** Per-call animation controls shared by all providers. */
87
+ interface ThemeTransitionOptions {
88
+ /** Skip the view transition (also automatically skipped for reduced motion). */
89
+ readonly animationOff?: boolean;
90
+ /** Trigger element; its viewport rectangle is read synchronously. */
91
+ readonly element?: Element | null;
92
+ /** Viewport-relative CSS pixels. Never multiply these coordinates by DPR. */
93
+ readonly origin?: {
94
+ readonly x: number;
95
+ readonly y: number;
96
+ };
97
+ }
98
+ /** Boolean arguments remain supported for backward compatibility. */
99
+ type ThemeTransitionInput = boolean | ThemeTransitionOptions;
100
+ type ColorThemeToggle = (options?: ThemeTransitionInput | Pick<React.MouseEvent<HTMLElement>, 'currentTarget' | 'detail'>) => Promise<void>;
101
+ interface UseThemeAnimationReturn {
102
+ readonly ref: RefObject<HTMLButtonElement | null>;
103
+ readonly theme: Theme;
104
+ readonly colorTheme: ColorTheme;
105
+ readonly resolvedTheme: 'light' | 'dark';
106
+ readonly systemTheme: 'light' | 'dark';
107
+ readonly setTheme: (theme: Theme) => void;
108
+ readonly setColorTheme: (colorTheme: ColorTheme) => void;
109
+ readonly switchTheme: (theme: Theme, options?: ThemeTransitionInput) => Promise<void>;
110
+ readonly switchColorTheme: (colorTheme: string, options?: ThemeTransitionInput) => Promise<void>;
111
+ readonly toggleTheme: (options?: ThemeTransitionInput) => Promise<void>;
112
+ readonly toggleLightTheme: (options?: ThemeTransitionInput) => Promise<void>;
113
+ readonly toggleDarkTheme: (options?: ThemeTransitionInput) => Promise<void>;
114
+ readonly toggleColorTheme: ColorThemeToggle;
115
+ readonly createColorThemeToggle: (targetColorTheme: string) => ColorThemeToggle;
116
+ readonly isColorThemeActive: (targetColorTheme: string) => boolean;
117
+ }
118
+ type ThemeSwitcherProps = ThemeAnimationOptions & {
119
+ readonly themes?: readonly Theme[];
120
+ readonly currentTheme?: Theme;
121
+ readonly onThemeChange?: (theme: Theme) => void;
122
+ readonly animationType?: ThemeAnimationType;
123
+ readonly duration?: number;
124
+ readonly className?: string;
125
+ readonly size?: 'sm' | 'md' | 'lg';
126
+ readonly variant?: 'default' | 'outline' | 'ghost';
127
+ readonly icons?: {
128
+ readonly light?: React.ReactNode;
129
+ readonly dark?: React.ReactNode;
130
+ readonly system?: React.ReactNode;
131
+ };
132
+ };
133
+ type ThemeSelectorProps = ThemeAnimationOptions & {
134
+ readonly themes?: readonly Theme[];
135
+ readonly colorThemes?: readonly ColorTheme[];
136
+ readonly currentTheme?: Theme;
137
+ readonly currentColorTheme?: ColorTheme;
138
+ readonly onThemeChange?: (theme: Theme) => void;
139
+ readonly onColorThemeChange?: (colorTheme: ColorTheme) => void;
140
+ readonly animationType?: ThemeAnimationType;
141
+ readonly duration?: number;
142
+ readonly className?: string;
143
+ readonly placeholder?: string;
144
+ /** @deprecated This selector changes palettes only. Use ThemeSwitcher for mode controls. */
145
+ readonly themeLabel?: string;
146
+ readonly colorThemeLabel?: string;
147
+ };
148
+
149
+ /** Injects styles scoped to transitions owned by this library. */
150
+ declare const injectBaseStyles: () => void;
151
+ /**
152
+ * Gets the system theme preference
153
+ * @returns 'light' or 'dark' based on system preference
154
+ */
155
+ declare const getSystemTheme: () => "light" | "dark";
156
+ /**
157
+ * Resolves a theme value to its actual light/dark value
158
+ * @param theme - Theme to resolve ('light', 'dark', or 'system')
159
+ * @returns Resolved theme ('light' or 'dark')
160
+ */
161
+ declare const resolveTheme: (theme: string) => "light" | "dark";
162
+ /**
163
+ * Resolves a stored theme to the server-side class to apply on <html>.
164
+ * CSS mode uses the 'system' class so media queries can respond before hydration.
165
+ */
166
+ declare const resolveThemeForServer: (theme: string) => "light" | "dark" | "system";
167
+ /**
168
+ * Checks if the browser supports View Transitions API
169
+ * @returns true if view transitions are supported
170
+ */
171
+ declare const supportsViewTransitions: () => boolean;
172
+ /**
173
+ * Checks if user prefers reduced motion
174
+ * @returns true if user prefers reduced motion
175
+ */
176
+ declare const prefersReducedMotion: () => boolean;
177
+ /**
178
+ * Converts a slide direction to from coordinates
179
+ * @param direction - Slide direction
180
+ * @returns Object with a (x) and b (y) coordinates
181
+ */
182
+ interface SlideCoordinates {
183
+ readonly a: number;
184
+ readonly b: number;
185
+ }
186
+ declare const getSlideFromCoords: (direction: SlideDirection) => SlideCoordinates;
187
+ /** Viewport CSS coordinates for fixed origins; button origins stay in the hook. */
188
+ declare const getAnimationPosition: (position: Exclude<AnimationPosition, "trigger">) => NonNullable<ThemeTransitionOptions["origin"]>;
189
+ /** A half-plane wipe, including diagonals, with compatible four-point polygons. */
190
+ declare const createClipPathAnimation: (config: AnimationConfig) => Animation;
191
+ /** Feathered polygon/edge mask, without Gaussian filtering or scaling content. */
192
+ declare const createPolygonGradientAnimation: (config: AnimationConfig) => Animation;
193
+ /** Upright triangle; its final incircle contains all four snapshot corners. */
194
+ declare const createTriangleAnimation: (config: AnimationConfig) => Animation;
195
+ /** The fixed logo has its own snapshot; only the page reveal grows beneath it. */
196
+ declare const createSvgLogoAnimation: (config: AnimationConfig) => Animation;
197
+ /** Native circular clip; browser compositor support varies by engine. */
198
+ declare const createCircleAnimation: (config: AnimationConfig) => Animation;
199
+ /** Predetermined translation uses WAAPI rather than a timer-owned stylesheet. */
200
+ declare const createSlideAnimation: (config: AnimationConfig) => Animation;
201
+ /**
202
+ * A bounded radial gradient feathers only the reveal edge. Unlike the old SVG
203
+ * Gaussian mask, it needs no huge filtered surface or animation on the old view.
204
+ * Mask animation can still paint; this is not a compositor-only guarantee.
205
+ */
206
+ declare const createBlurCircleAnimation: (config: AnimationConfig) => Animation;
207
+
208
+ export { type AnimationPosition as A, getAnimationPosition as B, type ColorTheme as C, getSlideFromCoords as D, type SlideDirection as S, TRANSITION_DIRECTIONS as T, type UseThemeAnimationProps as U, type ColorThemeToggle as a, type SystemThemeMode as b, type Theme as c, type ThemeAnimationOptions as d, ThemeAnimationType as e, type ThemeLogoOptions as f, type ThemeSelectorProps as g, type ThemeSwitcherProps as h, type ThemeTransitionInput as i, type ThemeTransitionOptions as j, type TransitionDirection as k, type UseThemeAnimationReturn as l, getSystemTheme as m, injectBaseStyles as n, resolveThemeForServer as o, prefersReducedMotion as p, type AnimationConfig as q, resolveTheme as r, supportsViewTransitions as s, createBlurCircleAnimation as t, createCircleAnimation as u, createClipPathAnimation as v, createPolygonGradientAnimation as w, createSlideAnimation as x, createSvgLogoAnimation as y, createTriangleAnimation as z };
@@ -0,0 +1,44 @@
1
+ import {a as a$1,b as b$1,e}from'./chunk-X6UEG7WG.js';import {a,b,c,d}from'./chunk-QYUMCBTQ.js';import {a as a$2,b as b$2,c as c$1,g,h}from'./chunk-I3T2QXRT.js';import*as Je from'react';import Je__default,{createContext,useSyncExternalStore,useEffect,useState,useRef,useCallback,useMemo,useContext,useId}from'react';import {flushSync}from'react-dom';import {jsxs,jsx}from'react/jsx-runtime';import {clsx}from'clsx';import {motion}from'motion/react';import*as ie from'@radix-ui/react-select';function Zt(){return ()=>{}}function jt(){return true}function eo(){return false}function q(){return useSyncExternalStore(Zt,jt,eo)}function De(e){try{return "window"in globalThis?window.localStorage.getItem(e):null}catch{return null}}function re(e,o){try{"window"in globalThis&&window.localStorage.setItem(e,o);}catch{return}}function he(e){return e===void 0||e===true||e===false?e:"currentTarget"in e?{element:e.currentTarget,animationOff:e.detail===0}:e}var ne="window"in globalThis,ro=["light","dark","system"],no=["default"],O=(e$1={})=>{let{duration:o=400,easing:r="cubic-bezier(0.32, 0.72, 0, 1)",animationType:n="circle",blurAmount:i=2,styleId:l="spaceman-theme-style",clipPathDirection:T="top-left",animationPosition:a,logo:s,logoLight:m,logoDark:h$1,logoWidth:f,logoHeight:P,gradientWidth:A,themes:p=ro,colorThemes:g$1=no,defaultTheme:J="system",defaultColorTheme:x="default",globalClassName:D="dark",colorThemePrefix:E="theme-",attribute:V="class",value:H,enableColorScheme:c=true,storageKey:y="theme",colorStorageKey:v="color-theme",theme:k,colorTheme:b,onThemeChange:u,onColorThemeChange:R,initialTheme:N,initialColorTheme:$,systemThemeMode:X="js",slideDirection:U="left",slideFromX:C,slideFromY:L,slideToX:z=0,slideToY:d=0}=e$1;a$1({logo:s,logoLight:m,logoDark:h$1});let I=o;useEffect(()=>{if(n==="svg-logo")for(let t of [s,m,h$1])t!==void 0&&t!==""&&b$1(t);},[n,s,m,h$1]);let ae=q();useEffect(()=>{a$2();},[]);let[Kt,Ut]=useState(()=>{if(N!==void 0)return N;if(!ne)return J;let t=De(y);return t!==null&&(t==="light"||t==="dark"||t==="system")&&p.includes(t)?t:J}),[Gt,Yt]=useState(()=>{if($!==void 0)return $;if(!ne)return x;let t=De(v);return t!==null&&t!==""&&g$1.includes(t)?t:x}),_=k??(ae?Kt:N??J),F=b??(ae?Gt:$??x),[,qt]=useState(()=>b$2()),Oe=ae?b$2():"light",j=_==="system"?Oe:c$1(_);useEffect(()=>{if(!ne)return;let t=window.matchMedia("(prefers-color-scheme: dark)"),S=()=>{qt(b$2());};return t.addEventListener("change",S),()=>{t.removeEventListener("change",S);}},[]),useEffect(()=>{if(!ne||!ae)return;let t=document.documentElement,S=H?.light,W=H?.dark??D,Q=H?.system??"system";V==="data-theme"?X==="css"&&_==="system"?t.setAttribute("data-theme",Q):t.setAttribute("data-theme",j==="dark"?W:S??"light"):(S!==void 0&&S!==""&&t.classList.remove(S),t.classList.remove(W,Q,"auto"),X==="css"&&_==="system"?t.classList.add(Q):j==="dark"?t.classList.add(W):S!==void 0&&S!==""?t.classList.add(S):t.classList.remove(W)),c?t.style.colorScheme=X==="css"&&_==="system"?"":j:t.style.removeProperty("color-scheme"),g$1.forEach(te=>{t.classList.remove(`${E}${te}`);}),t.classList.add(`${E}${F}`);},[j,_,F,D,E,g$1,V,H,c,ae,X]);let Be=useRef(null),G=useRef(_),le=useRef(F),Te=useRef(0);useEffect(()=>{Te.current===0&&(G.current=_,le.current=F);},[_,F]);let ue=useCallback(t=>{ne&&re(y,t),k===void 0&&Ut(t),u&&u(t);},[u,k,y]),pe=useCallback(t=>{ne&&re(v,t),b===void 0&&Yt(t),R&&R(t);},[R,b,v]),qe=useCallback(t=>{G.current=t,ue(t);},[ue]),Qe=useCallback(t=>{le.current=t,pe(t);},[pe]),ge=useCallback(async(t,S=false)=>{let W=S===true||S===false?{animationOff:S}:S,Q=null;if(W.animationOff!==true&&I>0)if(n==="slide")Q={...C!==void 0&&L!==void 0?{a:C,b:L}:g(U),x:z,y:d,duration:I,easing:r,animationType:n,blurAmount:i,styleId:l};else {let te=W.element??Be.current,se=W.origin?null:te?.getBoundingClientRect(),ye=(n==="svg-logo"?h("center"):null)??W.origin??(a&&a!=="trigger"?h(a):null)??(se?{x:se.left+se.width/2,y:se.top+se.height/2}:n==="circle"||n==="blur-circle"?null:h("center"));ye&&Number.isFinite(ye.x)&&Number.isFinite(ye.y)&&(Q={...ye,duration:I,easing:r,animationType:n,blurAmount:i,styleId:l,clipPathDirection:T,animationPosition:a,logo:m!==void 0?c$1(G.current)==="light"?m:h$1:s,logoWidth:f,logoHeight:P,gradientWidth:A});}Te.current++;try{await e(()=>{flushSync(t);},Q),Te.current--;}catch(te){throw Te.current--,te}},[I,r,n,i,l,U,C,L,z,d,T,a,s,m,h$1,f,P,A]),Y=useCallback(async(t,S)=>{t!==G.current&&(G.current=t,await ge(()=>{ue(t);},S));},[ge,ue]),ee=useCallback(async(t,S)=>{if(!g$1.includes(t)){console.warn(`Color theme "${t}" not found in available themes`);return}t!==le.current&&(le.current=t,await ge(()=>{pe(t);},S));},[g$1,ge,pe]),Ze=useCallback(async t=>{await Y(c$1(G.current)==="dark"?"light":"dark",t);},[Y]),je=useCallback(async t=>{c$1(G.current)!=="light"&&await Y("light",t);},[Y]),et=useCallback(async t=>{c$1(G.current)!=="dark"&&await Y("dark",t);},[Y]),tt=useCallback(async t=>{if(g$1.length===0)return;let S=g$1.indexOf(le.current);await ee(g$1[(S+1)%g$1.length],he(t));},[g$1,ee]),ot=useCallback(t=>async S=>ee(t,he(S)),[ee]),rt=useCallback(t=>F===t,[F]);return useMemo(()=>({ref:Be,theme:_,colorTheme:F,resolvedTheme:j,systemTheme:Oe,setTheme:qe,setColorTheme:Qe,switchTheme:Y,switchColorTheme:ee,toggleTheme:Ze,toggleLightTheme:je,toggleDarkTheme:et,toggleColorTheme:tt,createColorThemeToggle:ot,isColorThemeActive:rt}),[Be,_,F,j,Oe,qe,Qe,Y,ee,Ze,je,et,tt,ot,rt])};var K=createContext(null),ke=()=>useContext(K);function st(){return jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsx("rect",{width:"20",height:"14",x:"2",y:"3",rx:"2"}),jsx("line",{x1:"8",x2:"16",y1:"21",y2:"21"}),jsx("line",{x1:"12",x2:"12",y1:"17",y2:"21"})]})}function ct(){return jsx("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsx("path",{d:"M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"})})}function Tt(){return jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[jsx("circle",{cx:"12",cy:"12",r:"5"}),jsx("path",{d:"M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"})]})}var Re=["light","dark","system"],ut=[{icon:Je__default.createElement(st),value:"system"},{icon:Je__default.createElement(Tt),value:"light"},{icon:Je__default.createElement(ct),value:"dark"}];function pt({icon:e,value:o,isActive:r,isHovered:n,onClick:i,onMouseEnter:l,onMouseLeave:T,buttonRef:a}){return jsxs("button",{type:"button",ref:r===true?a:void 0,className:clsx("relative flex h-9 w-12 cursor-pointer items-center justify-center","text-muted-foreground hover:text-foreground",r===true&&"text-foreground font-medium"),"aria-pressed":r===true,"aria-label":`Switch to ${o} theme`,onClick:s=>{i(o,s);},onMouseEnter:l,onMouseLeave:T,style:{borderRadius:"var(--radius)"},children:[n===true&&jsx(motion.div,{layoutId:"theme-hover",className:"bg-muted absolute inset-0",style:{borderRadius:"var(--radius)"},transition:{type:"spring",bounce:0,stiffness:100,damping:10,duration:.3}}),jsx("div",{className:"relative z-10 flex items-center justify-center",children:jsx("div",{className:"[&_svg]:size-4",children:e})}),r===true&&jsx("div",{className:"absolute bottom-0 left-1/2 h-0.5 w-6 -translate-x-1/2 rounded-full",style:{backgroundColor:"hsl(var(--primary))"}})]})}function Ee({className:e,onSwitchTheme:o,theme:r,themes:n,themeRef:i}){let l=q(),[T,a]=useState(null),s=async(h,f)=>{await o(h,f);},m=ut.filter(h=>n.includes(h.value));return jsx("fieldset",{className:clsx("bg-background border-border m-0 inline-flex h-9 min-w-0 items-center overflow-hidden border p-0 shadow-sm",l?"opacity-100":"opacity-0",e),style:{borderRadius:"var(--radius)",backgroundColor:"hsl(var(--background))"},"aria-label":"Theme",children:m.map(h=>jsx(pt,{icon:h.icon,value:h.value,isActive:r===h.value,isHovered:T===h.value,onClick:(f,P)=>{s(f,P).catch(console.error);},onMouseEnter:()=>{a(h.value);},onMouseLeave:()=>{a(null);},buttonRef:r===h.value?i:void 0},h.value))})}function yt({themes:e=Re,currentTheme:o,onThemeChange:r,animationType:n,duration:i,className:l,...T}){let a=O({...T,animationType:n,duration:i,themes:e,...o!==void 0&&{theme:o},onThemeChange:r});return jsx(Ee,{className:l,onSwitchTheme:async(m,h)=>{await a.switchTheme(m,{element:h?.currentTarget,animationOff:h?.detail===0});},theme:a.theme,themes:e,themeRef:a.ref})}function ft({className:e,contextTheme:o,themes:r=Re}){return jsx(Ee,{className:e,onSwitchTheme:async(i,l)=>{if(l?.detail===0){await o.switchTheme(i,true);return}if(o.switchThemeFromElement&&l){await o.switchThemeFromElement(i,l.currentTarget);return}await o.switchTheme(i);},theme:o.theme,themes:r,themeRef:o.ref})}function on(e){let o=ke();return o?jsx(ft,{...e,contextTheme:o}):jsx(yt,{...e})}var Le=["default"],Ct=["light","dark","system"];function $e({...e}){return jsx(ie.Root,{"data-slot":"select",...e})}function Fe({className:e,children:o,position:r="popper",...n}){return jsx(ie.Portal,{children:jsx(ie.Content,{"data-slot":"select-content",className:clsx("bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",r==="popper"&&"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",e),position:r,...n,children:jsx(ie.Viewport,{className:clsx("p-1",r==="popper"&&"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"),children:o})})})}function xt(){return jsx("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsx("path",{d:"M20 6 9 17l-5-5"})})}function We({className:e,children:o,...r}){return jsxs(ie.Item,{"data-slot":"select-item",className:clsx("focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",e),...r,children:[jsx("span",{className:"absolute left-2 flex h-3.5 w-3.5 items-center justify-center",children:jsx(ie.ItemIndicator,{children:jsx(xt,{})})}),jsx(ie.ItemText,{children:o})]})}function Rt(){return jsx("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:jsx("path",{d:"m6 9 6 6 6-6"})})}var Ae=Je.forwardRef(function({className:e,size:o="default",children:r,...n},i){return jsxs(ie.Trigger,{ref:i,"data-slot":"select-trigger","data-size":o,className:clsx("border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",e),...n,children:[r,jsx(ie.Icon,{asChild:true,children:jsx(Rt,{})})]})});Ae.displayName="SelectTrigger";function Ke({...e}){return jsx(ie.Value,{"data-slot":"select-value",...e})}function Ve({className:e,placeholder:o="Choose a color theme",colorThemeLabel:r,colorTheme:n,colorThemes:i,onSelectColorTheme:l}){let T=useId(),a=useRef(null),s=useRef("keyboard");return i.length>1?jsxs("div",{className:["flex flex-col gap-2",e].filter(Boolean).join(" "),children:[r!==void 0&&r!==""?jsx("label",{htmlFor:T,children:r}):null,jsxs($e,{value:n,onValueChange:m=>{l(m,{element:a.current,animationOff:s.current==="keyboard"}).catch(console.error);},children:[jsx(Ae,{id:T,ref:a,onPointerDownCapture:()=>{s.current="pointer";},onKeyDownCapture:()=>{s.current="keyboard";},className:"capitalize",children:jsx(Ke,{placeholder:o})}),jsx(Fe,{onPointerDownCapture:()=>{s.current="pointer";},onKeyDownCapture:()=>{s.current="keyboard";},children:i.map(m=>jsx(We,{className:"capitalize",value:m,children:m},m))})]})]}):null}function At({className:e,placeholder:o,colorThemeLabel:r,themes:n=Ct,colorThemes:i=Le,currentColorTheme:l,onColorThemeChange:T,animationType:a,duration:s,...m}){let h=O({...m,animationType:a,duration:s,themes:n,colorThemes:i,...l!==void 0&&{colorTheme:l},onColorThemeChange:T}),f=h.switchColorTheme;return jsx(Ve,{className:e,placeholder:o,colorThemeLabel:r,colorTheme:h.colorTheme,colorThemes:i,onSelectColorTheme:f})}function Vt({className:e,placeholder:o,colorThemeLabel:r,onColorThemeChange:n,colorThemes:i=Le,contextTheme:l}){let T=async(a,s)=>{a!==l.colorTheme&&(await l.switchColorTheme(a,s),n?.(a));};return jsx(Ve,{className:e,placeholder:o,colorThemeLabel:r,colorTheme:l.colorTheme,colorThemes:i,onSelectColorTheme:T})}function Yn(e){let o=ke();return o?jsx(Vt,{...e,contextTheme:o}):jsx(At,{...e})}var Io=["light","dark","system"],Mo=["default"],Ot=createContext(void 0);function ri({children:e,themes:o=Io,colorThemes:r=Mo,defaultTheme:n="system",defaultColorTheme:i="default",animationType:l="circle",duration:T=400,...a}){let s=q(),m=O({...a,themes:o,colorThemes:r,defaultTheme:n,defaultColorTheme:i,animationType:l,duration:T}),h=useCallback(async(P,A)=>{await m.switchTheme(P,{element:A});},[m]),f=useMemo(()=>s?{ref:m.ref,theme:m.theme,colorTheme:m.colorTheme,resolvedTheme:m.resolvedTheme,setTheme:m.setTheme,setColorTheme:m.setColorTheme,switchTheme:m.switchTheme,switchThemeFromElement:h,switchColorTheme:m.switchColorTheme,toggleTheme:m.toggleTheme,toggleLightTheme:m.toggleLightTheme,toggleDarkTheme:m.toggleDarkTheme,toggleColorTheme:m.toggleColorTheme,createColorThemeToggle:m.createColorThemeToggle,isColorThemeActive:m.isColorThemeActive}:{ref:{current:null},theme:n,colorTheme:i,resolvedTheme:n==="dark"?"dark":"light",setTheme:()=>{},setColorTheme:()=>{},switchTheme:async()=>Promise.resolve(),switchThemeFromElement:async()=>Promise.resolve(),switchColorTheme:async()=>Promise.resolve(),toggleTheme:async()=>Promise.resolve(),toggleLightTheme:async()=>Promise.resolve(),toggleDarkTheme:async()=>Promise.resolve(),toggleColorTheme:async()=>Promise.resolve(),createColorThemeToggle:()=>async()=>Promise.resolve(),isColorThemeActive:()=>false},[s,n,i,m,h]);return jsx(Ot.Provider,{value:f,children:jsx(K.Provider,{value:f,children:e})})}var ni=()=>{let e=useContext(Ot);if(e===void 0)throw new Error("useSpacemanTheme must be used within a SpacemanThemeProvider");return e};function w(e){return JSON.stringify(e).replaceAll("<","\\u003c").replaceAll(">","\\u003e").replaceAll("&","\\u0026").replaceAll("\u2028","\\u2028").replaceAll("\u2029","\\u2029")}var Vo=({attribute:e,colorStorageKey:o,colorThemePrefix:r,defaultColorTheme:n,defaultTheme:i,enableColorScheme:l,enableSystem:T,globalClassName:a,storageKey:s,value:m})=>{let h=m?.light??"light",f=m?.dark??a,P=m?.system??"system";return `(function(){try{var d=document.documentElement;var theme=localStorage.getItem(${w(s)})||${w(i)};var colorTheme=localStorage.getItem(${w(o)})||${w(n)};if(!${JSON.stringify(T)}&&theme==='system'){theme=${w(i==="system"?"light":i)};}var resolved=theme==='system'?(window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'):theme;var attr=${w(e)};var lightValue=${w(h)};var darkValue=${w(f)};var systemValue=${w(P)};if(attr==='data-theme'){d.setAttribute('data-theme',theme==='system'?systemValue:(resolved==='dark'?darkValue:lightValue));}else{d.classList.remove(lightValue,darkValue,systemValue,'auto');d.classList.add(theme==='system'?systemValue:(resolved==='dark'?darkValue:lightValue));}if(${JSON.stringify(l)}){d.style.colorScheme=theme==='system'?'':resolved;}else{d.style.removeProperty('color-scheme');}d.classList.add(${w(r)}+colorTheme);}catch(e){console.warn('Theme pre-hydration script failed:',e);}})();`},Ue=Je__default.memo(function({attribute:e,colorStorageKey:o,colorThemePrefix:r,defaultColorTheme:n,defaultTheme:i,enableColorScheme:l,enableSystem:T,globalClassName:a,nonce:s,scriptProps:m,storageKey:h,value:f}){return jsx("script",{...m,nonce:s,suppressHydrationWarning:true,dangerouslySetInnerHTML:{__html:Vo({attribute:e,colorStorageKey:o,colorThemePrefix:r,defaultColorTheme:n,defaultTheme:i,enableColorScheme:l,enableSystem:T,globalClassName:a,storageKey:h,value:f})}})});Ue.displayName="ThemePreHydrationScript";var Bo=["default"],Dt=createContext(void 0),Do=()=>{let e=document.createElement("style");return e.textContent="*,*::before,*::after{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}",document.head.appendChild(e),window.getComputedStyle(document.body),()=>{setTimeout(()=>{e.parentNode&&e.parentNode.removeChild(e);},1);}};function Xo({attribute:e="class",children:o,colorStorageKey:r="color-theme",colorThemePrefix:n="theme-",colorThemes:i=Bo,defaultColorTheme:l="default",defaultTheme:T="system",disableAnimationOnInit:a=true,disablePreHydrationScript:s=false,disableTransitionOnChange:m=false,duration:h=400,enableColorScheme:f=true,enableSystem:P=true,forcedTheme:A,globalClassName:p="dark",nonce:g,onColorThemeChange:J,onThemeChange:x,scriptProps:D,storageKey:E="theme",themes:V,value:H,animationType:c="circle",...y}){let v=useMemo(()=>V&&V.length>0?V:P?["light","dark","system"]:["light","dark"],[P,V]),k=useMemo(()=>T==="system"&&!P?"light":T,[T,P]),b=q(),u=O({...y,animationType:c,attribute:e,colorStorageKey:r,colorTheme:void 0,colorThemePrefix:n,colorThemes:i,defaultColorTheme:l,defaultTheme:k,duration:h,enableColorScheme:f,globalClassName:p,onColorThemeChange:J,onThemeChange:x,storageKey:E,theme:A,themes:v,value:H}),R=useCallback(async C=>{let L=m?Do():void 0;try{let z=await C();return L?.(),z}catch(z){throw L?.(),z}},[m]),N=useCallback(C=>{R(()=>{u.setTheme(C);});},[u,R]),$=useCallback(async(C,L=false)=>{await R(async()=>{if(!b&&a){u.setTheme(C);return}await u.switchTheme(C,L);});},[a,b,u,R]),X=useCallback(async(C,L)=>{await R(async()=>{if(!b&&a){u.setTheme(C);return}await u.switchTheme(C,{element:L});});},[a,b,u,R]),U=useMemo(()=>({ref:u.ref,theme:u.theme,colorTheme:u.colorTheme,resolvedTheme:u.resolvedTheme,systemTheme:u.systemTheme,setTheme:N,setColorTheme:u.setColorTheme,switchTheme:$,switchColorTheme:u.switchColorTheme,toggleTheme:async(C=false)=>R(async()=>u.toggleTheme(C)),toggleLightTheme:async(C=false)=>R(async()=>u.toggleLightTheme(C)),toggleDarkTheme:async(C=false)=>R(async()=>u.toggleDarkTheme(C)),toggleColorTheme:u.toggleColorTheme,createColorThemeToggle:u.createColorThemeToggle,isColorThemeActive:u.isColorThemeActive,switchThemeFromElement:X}),[N,$,X,u,R]);return jsx(Dt.Provider,{value:U,children:jsxs(K.Provider,{value:U,children:[!s&&!A?jsx(Ue,{attribute:e,colorStorageKey:r,colorThemePrefix:n,defaultColorTheme:l,defaultTheme:k,enableColorScheme:f,enableSystem:P,globalClassName:p,nonce:g,scriptProps:D,storageKey:E,value:H}):null,o]})})}var fi=Xo,_o=()=>{let e=useContext(Dt);if(e===void 0)throw new Error("useNextTheme must be used within a NextThemeProvider");return e},vi=_o;var zo=(e,o,r,n,i,l,T)=>`
2
+ (function() {
3
+ try {
4
+ var theme = localStorage.getItem(${w(e)}) || ${w(r)};
5
+ var colorTheme = localStorage.getItem(${w(o)}) || ${w(n)};
6
+ var el = document.documentElement;
7
+ var resolved;
8
+ if (theme === 'system') {
9
+ if (${w(T)} === 'css') {
10
+ el.classList.remove(${w(i)});
11
+ el.classList.remove('auto');
12
+ el.classList.remove('system');
13
+ el.classList.add('system');
14
+ el.style.colorScheme = '';
15
+ } else {
16
+ resolved = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
17
+ if (resolved === 'dark') {
18
+ el.classList.add(${w(i)});
19
+ } else {
20
+ el.classList.remove(${w(i)});
21
+ }
22
+ el.classList.remove('system');
23
+ el.classList.remove('auto');
24
+ el.style.colorScheme = resolved;
25
+ }
26
+ } else {
27
+ resolved = theme;
28
+ el.classList.remove('system');
29
+ el.classList.remove('auto');
30
+ if (resolved === 'dark') {
31
+ el.classList.add(${w(i)});
32
+ } else {
33
+ el.classList.remove(${w(i)});
34
+ }
35
+ el.style.colorScheme = resolved;
36
+ }
37
+ if (colorTheme && colorTheme !== 'default') {
38
+ el.classList.add(${w(l)} + colorTheme);
39
+ }
40
+ } catch (e) {
41
+ console.warn('Theme pre-hydration script failed:', e);
42
+ }
43
+ })();
44
+ `,Xt=Je__default.memo(function({storageKey:e=a,colorStorageKey:o=b,defaultTheme:r="system",defaultColorTheme:n="default",globalClassName:i=c,colorThemePrefix:l=d,nonce:T,systemThemeMode:a$1="js"}){let s=zo(e,o,r,n,i,l,a$1);return jsx("script",{nonce:T,suppressHydrationWarning:true,dangerouslySetInnerHTML:{__html:s}})});Xt.displayName="TanStackStartThemeScript";var Ko="window"in globalThis,_t=({enabled:e,theme:o,colorTheme:r,storageKey:n,colorStorageKey:i})=>{useEffect(()=>{!e||!Ko||(o&&re(n,o),r!==void 0&&r!==""&&re(i,r));},[e,o,r,n,i]);};var Ne=()=>"window"in globalThis&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light",Jt=e=>e==="dark"?"light":"dark";function Ye(e,o){let r=e?.(o);r instanceof Promise&&r.catch(console.error);}var Qo=["light","dark","system"],Zo=["default"],zt=createContext(void 0),jo=()=>useSyncExternalStore(()=>()=>{},()=>true,()=>false);function Ji({children:e,themes:o=Qo,colorThemes:r=Zo,defaultTheme:n="system",defaultColorTheme:i="default",animationType:l="circle",duration:T=400,storageKey:a$1=a,colorStorageKey:s=b,globalClassName:m=c,colorThemePrefix:h=d,serverTheme:f,serverColorTheme:P,systemThemeMode:A="css",onServerThemeChange:p,onServerColorThemeChange:g,...J}){let x=jo(),D=f!==void 0,E=D?f:void 0,V=useCallback(d=>{Ye(p,d);},[p]),H=useCallback(d=>{Ye(g,d);},[g]),c=O({...J,onThemeChange:V,onColorThemeChange:H,themes:o,colorThemes:r,defaultTheme:n,defaultColorTheme:i,animationType:l,duration:T,storageKey:a$1,colorStorageKey:s,globalClassName:m,colorThemePrefix:h,initialTheme:E,initialColorTheme:P,systemThemeMode:A});_t({enabled:D,theme:E,colorTheme:P,storageKey:a$1,colorStorageKey:s});let y=useCallback(d=>{c.setTheme(d);},[c]),v=useCallback(d=>{c.setColorTheme(d);},[c]),k=useCallback(async(d,I=false)=>{if(!x){y(d);return}await c.switchTheme(d,I);},[x,c,y]),b=useCallback(async(d=false)=>{let I=Jt(c.resolvedTheme);if(!x){y(I);return}await c.toggleTheme(d);},[x,c,y]),u=useCallback(async(d=false)=>{if(!x){y("light");return}await c.toggleLightTheme(d);},[x,c,y]),R=useCallback(async(d=false)=>{if(!x){y("dark");return}await c.toggleDarkTheme(d);},[x,c,y]),N=useCallback(async(d,I)=>{r.includes(d)&&await c.switchColorTheme(d,I);},[r,c]),$=useCallback(async d=>{await c.toggleColorTheme(d);},[c]),X=useCallback(d=>async I=>N(d,he(I)),[N]),U=useCallback(async(d,I)=>{if(!x){y(d);return}await c.switchTheme(d,{element:I});},[x,c,y]),C=Ne(),L=D?f==="dark"?"dark":f==="system"?C:"light":n==="dark"?"dark":"light",z=useMemo(()=>x?{ref:c.ref,theme:c.theme,colorTheme:c.colorTheme,resolvedTheme:c.resolvedTheme,systemTheme:C,isHydrated:true,setTheme:y,setColorTheme:v,switchTheme:k,switchThemeFromElement:U,switchColorTheme:N,toggleTheme:b,toggleLightTheme:u,toggleDarkTheme:R,toggleColorTheme:$,createColorThemeToggle:X,isColorThemeActive:c.isColorThemeActive}:{ref:{current:null},theme:E??n,colorTheme:P??i,resolvedTheme:L,systemTheme:"light",isHydrated:false,setTheme:y,setColorTheme:v,switchTheme:async d=>(y(d),Promise.resolve()),switchThemeFromElement:async d=>(y(d),Promise.resolve()),switchColorTheme:N,toggleTheme:async()=>(y(L==="dark"?"light":"dark"),Promise.resolve()),toggleLightTheme:async()=>(y("light"),Promise.resolve()),toggleDarkTheme:async()=>(y("dark"),Promise.resolve()),toggleColorTheme:$,createColorThemeToggle:X,isColorThemeActive:c.isColorThemeActive},[x,E,n,P,i,L,y,v,N,$,X,c,C,k,U,b,u,R]);return jsx(zt.Provider,{value:z,children:jsx(K.Provider,{value:z,children:e})})}var $i=()=>{let e=useContext(zt);if(e===void 0)throw new Error("useTanStackTheme must be used within a TanStackThemeProvider");return e};var rr=["light","dark","system"],nr=["default"],Wt=createContext(void 0);function Qi({children:e,themes:o=rr,colorThemes:r=nr,defaultTheme:n="system",defaultColorTheme:i="default",animationType:l="circle",duration:T=400,attribute:a="class",disableTransitionOnChange:s=false,storageKey:m="vite-theme",colorStorageKey:h="vite-color-theme",globalClassName:f="dark",colorThemePrefix:P="theme-",...A}){let p=O({...A,themes:o,colorThemes:r,defaultTheme:n,defaultColorTheme:i,animationType:l,duration:T,storageKey:m,colorStorageKey:h,globalClassName:a==="class"?f:void 0,colorThemePrefix:P}),g=useCallback(()=>{if(!s)return ()=>{};let v=document.createElement("style");return v.textContent="*,*::before,*::after{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}",document.head.appendChild(v),window.getComputedStyle(document.body),()=>{setTimeout(()=>{document.head.removeChild(v);},1);}},[s]),J=useCallback(v=>{let k=g();p.setTheme(v),k();},[p,g]),x=useCallback(async(v,k=false)=>{let b=g();await p.switchTheme(v,k),b();},[p,g]),D=useCallback(async(v=false)=>{let k=g();await p.toggleTheme(v),k();},[p,g]),E=useCallback(async(v=false)=>{let k=g();await p.toggleLightTheme(v),k();},[p,g]),V=useCallback(async(v=false)=>{let k=g();await p.toggleDarkTheme(v),k();},[p,g]),H=useCallback(async(v,k)=>{let b=g();try{await p.switchTheme(v,{element:k}),b();}catch(u){throw b(),u}},[p,g]),c=Ne(),y=useMemo(()=>({ref:p.ref,theme:p.theme,colorTheme:p.colorTheme,resolvedTheme:p.resolvedTheme,systemTheme:c,setTheme:J,setColorTheme:p.setColorTheme,switchTheme:x,switchThemeFromElement:H,switchColorTheme:p.switchColorTheme,toggleTheme:D,toggleLightTheme:E,toggleDarkTheme:V,toggleColorTheme:p.toggleColorTheme,createColorThemeToggle:p.createColorThemeToggle,isColorThemeActive:p.isColorThemeActive}),[p,c,J,x,H,D,E,V]);return jsx(Wt.Provider,{value:y,children:jsx(K.Provider,{value:y,children:e})})}var Zi=()=>{let e=useContext(Wt);if(e===void 0)throw new Error("useViteTheme must be used within a ViteThemeProvider");return e};export{q as a,O as b,on as c,Yn as d,ri as e,ni as f,Xo as g,fi as h,_o as i,vi as j,Xt as k,Ji as l,$i as m,Qi as n,Zi as o};