@space-man/react-theme-animation 2.1.0 → 2.3.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 (68) hide show
  1. package/README.md +72 -142
  2. package/dist/core/index.cjs +74 -0
  3. package/dist/core/index.cjs.map +1 -0
  4. package/dist/{esm/types/index.d.ts → core/index.d.cts} +26 -8
  5. package/dist/{cjs/types → core}/index.d.ts +26 -8
  6. package/dist/core/index.js +66 -0
  7. package/dist/core/index.js.map +1 -0
  8. package/dist/index.cjs +1756 -0
  9. package/dist/index.cjs.map +1 -0
  10. package/dist/index.d.cts +4 -0
  11. package/dist/index.d.ts +4 -0
  12. package/dist/index.js +1706 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/react/index.cjs +1742 -0
  15. package/dist/react/index.cjs.map +1 -0
  16. package/dist/react/index.d.cts +224 -0
  17. package/dist/react/index.d.ts +224 -0
  18. package/dist/react/index.js +1697 -0
  19. package/dist/react/index.js.map +1 -0
  20. package/dist/tanstack/index.cjs +34 -0
  21. package/dist/tanstack/index.cjs.map +1 -0
  22. package/dist/tanstack/index.d.cts +20 -0
  23. package/dist/tanstack/index.d.ts +20 -0
  24. package/dist/tanstack/index.js +27 -0
  25. package/dist/tanstack/index.js.map +1 -0
  26. package/package.json +66 -37
  27. package/dist/cjs/components/NextThemeProvider.d.ts +0 -81
  28. package/dist/cjs/components/NextThemeProvider.js +0 -223
  29. package/dist/cjs/components/SpacemanThemeProvider.d.ts +0 -57
  30. package/dist/cjs/components/SpacemanThemeProvider.js +0 -113
  31. package/dist/cjs/components/TanStackThemeProvider.d.ts +0 -68
  32. package/dist/cjs/components/TanStackThemeProvider.js +0 -183
  33. package/dist/cjs/components/ThemeSelector.d.ts +0 -3
  34. package/dist/cjs/components/ThemeSelector.js +0 -39
  35. package/dist/cjs/components/ThemeSwitcher.d.ts +0 -3
  36. package/dist/cjs/components/ThemeSwitcher.js +0 -81
  37. package/dist/cjs/components/ViteThemeProvider.d.ts +0 -61
  38. package/dist/cjs/components/ViteThemeProvider.js +0 -140
  39. package/dist/cjs/components/ui/select.d.ts +0 -15
  40. package/dist/cjs/components/ui/select.js +0 -83
  41. package/dist/cjs/hooks/use-theme-animation.d.ts +0 -2
  42. package/dist/cjs/hooks/use-theme-animation.js +0 -234
  43. package/dist/cjs/index.d.ts +0 -10
  44. package/dist/cjs/index.js +0 -30
  45. package/dist/cjs/types/index.js +0 -9
  46. package/dist/cjs/utils/animations.d.ts +0 -21
  47. package/dist/cjs/utils/animations.js +0 -189
  48. package/dist/esm/components/NextThemeProvider.d.ts +0 -81
  49. package/dist/esm/components/NextThemeProvider.js +0 -185
  50. package/dist/esm/components/SpacemanThemeProvider.d.ts +0 -57
  51. package/dist/esm/components/SpacemanThemeProvider.js +0 -108
  52. package/dist/esm/components/TanStackThemeProvider.d.ts +0 -68
  53. package/dist/esm/components/TanStackThemeProvider.js +0 -178
  54. package/dist/esm/components/ThemeSelector.d.ts +0 -3
  55. package/dist/esm/components/ThemeSelector.js +0 -35
  56. package/dist/esm/components/ThemeSwitcher.d.ts +0 -3
  57. package/dist/esm/components/ThemeSwitcher.js +0 -77
  58. package/dist/esm/components/ViteThemeProvider.d.ts +0 -61
  59. package/dist/esm/components/ViteThemeProvider.js +0 -135
  60. package/dist/esm/components/ui/select.d.ts +0 -15
  61. package/dist/esm/components/ui/select.js +0 -39
  62. package/dist/esm/hooks/use-theme-animation.d.ts +0 -2
  63. package/dist/esm/hooks/use-theme-animation.js +0 -230
  64. package/dist/esm/index.d.ts +0 -10
  65. package/dist/esm/index.js +0 -10
  66. package/dist/esm/types/index.js +0 -6
  67. package/dist/esm/utils/animations.d.ts +0 -21
  68. package/dist/esm/utils/animations.js +0 -177
@@ -1,183 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useTanStackTheme = exports.TanStackThemeProvider = void 0;
4
- const jsx_runtime_1 = require("react/jsx-runtime");
5
- const react_1 = require("react");
6
- const use_theme_animation_1 = require("../hooks/use-theme-animation");
7
- const types_1 = require("../types");
8
- const TanStackThemeContext = (0, react_1.createContext)(undefined);
9
- /**
10
- * Custom hook to detect hydration state
11
- * This is a simplified version compatible with TanStack Start's isomorphic model
12
- *
13
- * In TanStack Start, you can also use the built-in `useHydrated()` hook
14
- * from `@tanstack/start` if available
15
- */
16
- const useHydrated = () => {
17
- return (0, react_1.useSyncExternalStore)(
18
- // Subscribe function (no-op for hydration state)
19
- () => () => { },
20
- // Client snapshot: always true after hydration
21
- () => true,
22
- // Server snapshot: always false during SSR
23
- () => false);
24
- };
25
- /**
26
- * TanStack Start Theme Provider - Optimized for TanStack Start Framework
27
- *
28
- * @param children - React children to wrap with theme context
29
- * @param themes - Available theme options
30
- * @param colorThemes - Available color theme options
31
- * @param defaultTheme - Default theme to use
32
- * @param defaultColorTheme - Default color theme to use
33
- * @param animationType - Animation type for theme transitions
34
- * @param duration - Animation duration in milliseconds
35
- * @param storageKey - LocalStorage key for theme preference
36
- * @param colorStorageKey - LocalStorage key for color theme preference
37
- * @param globalClassName - Class name for dark theme
38
- * @param colorThemePrefix - Prefix for color theme classes
39
- */
40
- const TanStackThemeProvider = ({ children, themes = ['light', 'dark', 'system'], colorThemes = ['default'], defaultTheme = 'system', defaultColorTheme = 'default', animationType = types_1.ThemeAnimationType.CIRCLE, duration = 750, storageKey = 'theme', colorStorageKey = 'color-theme', globalClassName = 'dark', colorThemePrefix = 'theme-', }) => {
41
- const isHydrated = useHydrated();
42
- const themeState = (0, use_theme_animation_1.useThemeAnimation)({
43
- themes,
44
- colorThemes,
45
- defaultTheme,
46
- defaultColorTheme,
47
- animationType,
48
- duration,
49
- storageKey,
50
- colorStorageKey,
51
- globalClassName,
52
- colorThemePrefix,
53
- });
54
- // Hydration-aware theme switch: instant during hydration, animated after
55
- const switchThemeWithHydrationAwareness = (0, react_1.useCallback)(async (theme, animationOff = false) => {
56
- if (!isHydrated) {
57
- // During hydration: instant switch, no animation
58
- themeState.setTheme(theme);
59
- }
60
- else {
61
- // After hydration: animated switch
62
- await themeState.switchTheme(theme, animationOff);
63
- }
64
- }, [isHydrated, themeState]);
65
- const toggleThemeWithHydrationAwareness = (0, react_1.useCallback)(async (animationOff = false) => {
66
- if (!isHydrated) {
67
- const nextTheme = themeState.resolvedTheme === 'dark' ? 'light' : 'dark';
68
- themeState.setTheme(nextTheme);
69
- }
70
- else {
71
- await themeState.toggleTheme(animationOff);
72
- }
73
- }, [isHydrated, themeState]);
74
- const toggleLightThemeWithHydrationAwareness = (0, react_1.useCallback)(async (animationOff = false) => {
75
- if (!isHydrated) {
76
- themeState.setTheme('light');
77
- }
78
- else {
79
- await themeState.toggleLightTheme(animationOff);
80
- }
81
- }, [isHydrated, themeState]);
82
- const toggleDarkThemeWithHydrationAwareness = (0, react_1.useCallback)(async (animationOff = false) => {
83
- if (!isHydrated) {
84
- themeState.setTheme('dark');
85
- }
86
- else {
87
- await themeState.toggleDarkTheme(animationOff);
88
- }
89
- }, [isHydrated, themeState]);
90
- const switchThemeFromElement = (0, react_1.useCallback)(async (theme, element) => {
91
- if (!isHydrated) {
92
- themeState.setTheme(theme);
93
- return;
94
- }
95
- if (themeState.ref.current) {
96
- const originalRef = themeState.ref.current;
97
- Object.defineProperty(themeState.ref, 'current', {
98
- value: element,
99
- writable: true,
100
- configurable: true,
101
- });
102
- await themeState.switchTheme(theme);
103
- Object.defineProperty(themeState.ref, 'current', {
104
- value: originalRef,
105
- writable: true,
106
- configurable: true,
107
- });
108
- }
109
- else {
110
- Object.defineProperty(themeState.ref, 'current', {
111
- value: element,
112
- writable: true,
113
- configurable: true,
114
- });
115
- await themeState.switchTheme(theme);
116
- }
117
- }, [isHydrated, themeState]);
118
- const systemTheme = typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches
119
- ? 'dark'
120
- : 'light';
121
- // During SSR/hydration: provide safe context without animations
122
- if (!isHydrated) {
123
- const loadingContextValue = {
124
- ref: { current: null },
125
- theme: defaultTheme,
126
- colorTheme: defaultColorTheme,
127
- resolvedTheme: defaultTheme === 'dark' ? 'dark' : 'light',
128
- systemTheme: 'light',
129
- isHydrated: false,
130
- setTheme: themeState.setTheme,
131
- setColorTheme: themeState.setColorTheme,
132
- switchTheme: async (theme, animationOff = false) => themeState.setTheme(theme),
133
- switchThemeFromElement: async (theme) => themeState.setTheme(theme),
134
- switchColorTheme: themeState.switchColorTheme,
135
- toggleTheme: async (animationOff = false) => {
136
- const nextTheme = themeState.resolvedTheme === 'dark' ? 'light' : 'dark';
137
- themeState.setTheme(nextTheme);
138
- },
139
- toggleLightTheme: async (animationOff = false) => themeState.setTheme('light'),
140
- toggleDarkTheme: async (animationOff = false) => themeState.setTheme('dark'),
141
- toggleColorTheme: themeState.toggleColorTheme,
142
- createColorThemeToggle: themeState.createColorThemeToggle,
143
- isColorThemeActive: themeState.isColorThemeActive,
144
- };
145
- return ((0, jsx_runtime_1.jsx)(TanStackThemeContext.Provider, { value: loadingContextValue, children: children }));
146
- }
147
- // After hydration: full context with animations enabled
148
- const contextValue = {
149
- ref: themeState.ref,
150
- theme: themeState.theme,
151
- colorTheme: themeState.colorTheme,
152
- resolvedTheme: themeState.resolvedTheme,
153
- systemTheme,
154
- isHydrated: true,
155
- setTheme: themeState.setTheme,
156
- setColorTheme: themeState.setColorTheme,
157
- switchTheme: switchThemeWithHydrationAwareness,
158
- switchThemeFromElement,
159
- switchColorTheme: themeState.switchColorTheme,
160
- toggleTheme: toggleThemeWithHydrationAwareness,
161
- toggleLightTheme: toggleLightThemeWithHydrationAwareness,
162
- toggleDarkTheme: toggleDarkThemeWithHydrationAwareness,
163
- toggleColorTheme: themeState.toggleColorTheme,
164
- createColorThemeToggle: themeState.createColorThemeToggle,
165
- isColorThemeActive: themeState.isColorThemeActive,
166
- };
167
- return ((0, jsx_runtime_1.jsx)(TanStackThemeContext.Provider, { value: contextValue, children: children }));
168
- };
169
- exports.TanStackThemeProvider = TanStackThemeProvider;
170
- /**
171
- * Hook to consume the TanStack Theme context
172
- *
173
- * @returns Theme context value with all theme state and methods
174
- * @throws Error if used outside of TanStackThemeProvider
175
- */
176
- const useTanStackTheme = () => {
177
- const context = (0, react_1.useContext)(TanStackThemeContext);
178
- if (context === undefined) {
179
- throw new Error('useTanStackTheme must be used within a TanStackThemeProvider');
180
- }
181
- return context;
182
- };
183
- exports.useTanStackTheme = useTanStackTheme;
@@ -1,3 +0,0 @@
1
- import React from 'react';
2
- import { ThemeSelectorProps } from '../types';
3
- export declare const ThemeSelector: React.FC<ThemeSelectorProps>;
@@ -1,39 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ThemeSelector = void 0;
4
- const jsx_runtime_1 = require("react/jsx-runtime");
5
- const use_theme_animation_1 = require("../hooks/use-theme-animation");
6
- const SpacemanThemeProvider_1 = require("./SpacemanThemeProvider");
7
- const select_1 = require("./ui/select");
8
- const ThemeSelector = ({ themes = ['light', 'dark', 'system'], colorThemes = ['default'], currentColorTheme, onColorThemeChange, animationType, duration, }) => {
9
- // Try to use SpacemanTheme context if available (controlled mode)
10
- let contextTheme = null;
11
- try {
12
- contextTheme = (0, SpacemanThemeProvider_1.useSpacemanTheme)();
13
- }
14
- catch {
15
- // Context not available, use standalone mode
16
- }
17
- // Use context if available, otherwise fall back to standalone hook
18
- const standaloneHook = (0, use_theme_animation_1.useThemeAnimation)({
19
- animationType,
20
- duration,
21
- themes,
22
- colorThemes,
23
- ...(currentColorTheme !== undefined && { colorTheme: currentColorTheme }),
24
- onColorThemeChange,
25
- });
26
- const isControlled = contextTheme !== null;
27
- const { colorTheme, setColorTheme } = isControlled
28
- ? { colorTheme: contextTheme.colorTheme, setColorTheme: contextTheme.setColorTheme }
29
- : standaloneHook;
30
- const handleColorThemeChange = (newColorTheme) => {
31
- setColorTheme(newColorTheme);
32
- // Also call the callback if provided
33
- if (onColorThemeChange) {
34
- onColorThemeChange(newColorTheme);
35
- }
36
- };
37
- return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: colorThemes.length > 1 && ((0, jsx_runtime_1.jsx)("div", { className: "flex flex-col gap-2", children: (0, jsx_runtime_1.jsxs)(select_1.Select, { value: colorTheme, onValueChange: (v) => handleColorThemeChange(v), children: [(0, jsx_runtime_1.jsx)(select_1.SelectTrigger, { className: "capitalize", children: (0, jsx_runtime_1.jsx)(select_1.SelectValue, { placeholder: "Choose a color theme" }) }), (0, jsx_runtime_1.jsx)(select_1.SelectContent, { children: colorThemes.map(theme => ((0, jsx_runtime_1.jsx)(select_1.SelectItem, { className: "capitalize", value: theme, children: theme }, theme))) })] }) })) }));
38
- };
39
- exports.ThemeSelector = ThemeSelector;
@@ -1,3 +0,0 @@
1
- import React from 'react';
2
- import { ThemeSwitcherProps } from '../types';
3
- export declare const ThemeSwitcher: React.FC<ThemeSwitcherProps>;
@@ -1,81 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ThemeSwitcher = void 0;
4
- const jsx_runtime_1 = require("react/jsx-runtime");
5
- const react_1 = require("react");
6
- const react_2 = require("motion/react");
7
- const clsx_1 = require("clsx");
8
- const use_theme_animation_1 = require("../hooks/use-theme-animation");
9
- const SpacemanThemeProvider_1 = require("./SpacemanThemeProvider");
10
- const SunIcon = () => ((0, jsx_runtime_1.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "12", r: "5" }), (0, jsx_runtime_1.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" })] }));
11
- const MoonIcon = () => ((0, jsx_runtime_1.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: (0, jsx_runtime_1.jsx)("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" }) }));
12
- const MonitorIcon = () => ((0, jsx_runtime_1.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("rect", { width: "20", height: "14", x: "2", y: "3", rx: "2" }), (0, jsx_runtime_1.jsx)("line", { x1: "8", x2: "16", y1: "21", y2: "21" }), (0, jsx_runtime_1.jsx)("line", { x1: "12", x2: "12", y1: "17", y2: "21" })] }));
13
- const ThemeOption = ({ icon, value, isActive, isHovered, onClick, onMouseEnter, onMouseLeave, buttonRef, }) => {
14
- return ((0, jsx_runtime_1.jsxs)("button", { ref: isActive ? buttonRef : undefined, className: (0, clsx_1.clsx)('relative flex h-9 w-12 cursor-pointer items-center justify-center', 'text-muted-foreground hover:text-foreground', isActive && 'text-foreground font-medium'), role: "radio", "aria-checked": isActive, "aria-label": `Switch to ${value} theme`, onClick: event => onClick(value, event), onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, style: {
15
- borderRadius: 'var(--radius)',
16
- }, children: [isHovered && ((0, jsx_runtime_1.jsx)(react_2.motion.div, { layoutId: "theme-hover", className: "absolute inset-0 bg-muted", style: {
17
- borderRadius: 'var(--radius)',
18
- }, transition: {
19
- type: 'spring',
20
- bounce: 0,
21
- stiffness: 100,
22
- damping: 10,
23
- duration: 0.3,
24
- } })), (0, jsx_runtime_1.jsx)("div", { className: "relative z-10 flex items-center justify-center", children: (0, jsx_runtime_1.jsx)("div", { className: "[&_svg]:size-4", children: icon }) }), isActive && ((0, jsx_runtime_1.jsx)("div", { className: "absolute bottom-0 left-1/2 h-0.5 w-6 -translate-x-1/2 rounded-full", style: {
25
- backgroundColor: 'hsl(var(--primary))',
26
- } }))] }));
27
- };
28
- const THEME_OPTIONS = [
29
- {
30
- icon: (0, jsx_runtime_1.jsx)(MonitorIcon, {}),
31
- value: 'system',
32
- },
33
- {
34
- icon: (0, jsx_runtime_1.jsx)(SunIcon, {}),
35
- value: 'light',
36
- },
37
- {
38
- icon: (0, jsx_runtime_1.jsx)(MoonIcon, {}),
39
- value: 'dark',
40
- },
41
- ];
42
- const ThemeSwitcher = ({ themes = ['light', 'dark', 'system'], currentTheme, onThemeChange, animationType, duration, className, }) => {
43
- let contextTheme = null;
44
- try {
45
- contextTheme = (0, SpacemanThemeProvider_1.useSpacemanTheme)();
46
- }
47
- catch { }
48
- const standaloneHook = (0, use_theme_animation_1.useThemeAnimation)({
49
- animationType,
50
- duration,
51
- themes,
52
- ...(currentTheme !== undefined && { theme: currentTheme }),
53
- onThemeChange,
54
- });
55
- const isControlled = contextTheme !== null;
56
- const { ref, theme, switchTheme } = isControlled
57
- ? { ref: contextTheme.ref, theme: contextTheme.theme, switchTheme: contextTheme.switchTheme }
58
- : standaloneHook;
59
- const [isMounted, setIsMounted] = (0, react_1.useState)(false);
60
- const [hoveredTheme, setHoveredTheme] = (0, react_1.useState)(null);
61
- (0, react_1.useEffect)(() => {
62
- setIsMounted(true);
63
- }, []);
64
- const handleThemeChange = async (newTheme, event) => {
65
- if (isControlled && contextTheme.switchThemeFromElement && event) {
66
- await contextTheme.switchThemeFromElement(newTheme, event.currentTarget);
67
- if (onThemeChange) {
68
- onThemeChange(newTheme);
69
- }
70
- }
71
- else {
72
- await switchTheme(newTheme);
73
- }
74
- };
75
- const filteredOptions = THEME_OPTIONS.filter(option => themes.includes(option.value));
76
- return ((0, jsx_runtime_1.jsx)("div", { className: (0, clsx_1.clsx)('inline-flex h-9 items-center overflow-hidden bg-background shadow-sm border border-border', isMounted ? 'opacity-100' : 'opacity-0', className), style: {
77
- borderRadius: 'var(--radius)',
78
- backgroundColor: 'hsl(var(--background))',
79
- }, role: "radiogroup", onMouseLeave: () => setHoveredTheme(null), children: filteredOptions.map(option => ((0, jsx_runtime_1.jsx)(ThemeOption, { icon: option.icon, value: option.value, isActive: theme === option.value, isHovered: hoveredTheme === option.value, onClick: handleThemeChange, onMouseEnter: () => setHoveredTheme(option.value), onMouseLeave: () => { }, buttonRef: theme === option.value ? ref : undefined }, option.value))) }));
80
- };
81
- exports.ThemeSwitcher = ThemeSwitcher;
@@ -1,61 +0,0 @@
1
- import React, { ReactNode } from 'react';
2
- import { Theme, ColorTheme, ThemeAnimationType } from '../types';
3
- interface ViteThemeContextType {
4
- ref: React.RefObject<HTMLButtonElement | null>;
5
- theme: Theme;
6
- colorTheme: ColorTheme;
7
- resolvedTheme: 'light' | 'dark';
8
- systemTheme: 'light' | 'dark';
9
- setTheme: (theme: Theme) => void;
10
- setColorTheme: (colorTheme: ColorTheme) => void;
11
- switchTheme: (theme: Theme, animationOff?: boolean) => Promise<void>;
12
- switchColorTheme: (colorTheme: string) => void;
13
- toggleTheme: (animationOff?: boolean) => Promise<void>;
14
- toggleLightTheme: (animationOff?: boolean) => Promise<void>;
15
- toggleDarkTheme: (animationOff?: boolean) => Promise<void>;
16
- toggleColorTheme: () => void;
17
- createColorThemeToggle: (targetColorTheme: string) => () => void;
18
- isColorThemeActive: (targetColorTheme: string) => boolean;
19
- switchThemeFromElement: (theme: Theme, element: HTMLButtonElement) => Promise<void>;
20
- }
21
- interface ViteThemeProviderProps {
22
- children: ReactNode;
23
- themes?: Theme[];
24
- colorThemes?: ColorTheme[];
25
- defaultTheme?: Theme;
26
- defaultColorTheme?: ColorTheme;
27
- animationType?: ThemeAnimationType;
28
- duration?: number;
29
- attribute?: 'class' | 'data-theme';
30
- disableTransitionOnChange?: boolean;
31
- storageKey?: string;
32
- colorStorageKey?: string;
33
- globalClassName?: string;
34
- colorThemePrefix?: string;
35
- }
36
- /**
37
- * Vite Theme Provider - Optimized for Vite SPA applications
38
- *
39
- * This provider is designed for Vite-based single-page applications with optional
40
- * transition disabling to prevent flash during theme switches.
41
- *
42
- * Note: For flash prevention on initial load, add a script to your index.html
43
- * or inject it via Vite plugin to apply theme before React loads.
44
- *
45
- * @param children - React children to wrap with theme context
46
- * @param themes - Available theme options
47
- * @param colorThemes - Available color theme options
48
- * @param defaultTheme - Default theme to use
49
- * @param defaultColorTheme - Default color theme to use
50
- * @param animationType - Animation type for theme transitions
51
- * @param duration - Animation duration in milliseconds
52
- * @param attribute - HTML attribute to use for theme ('class' or 'data-theme')
53
- * @param disableTransitionOnChange - Temporarily disable CSS transitions during theme switch
54
- * @param storageKey - LocalStorage key for theme preference
55
- * @param colorStorageKey - LocalStorage key for color theme preference
56
- * @param globalClassName - Class name for dark theme (when using 'class' attribute)
57
- * @param colorThemePrefix - Prefix for color theme classes
58
- */
59
- export declare const ViteThemeProvider: React.FC<ViteThemeProviderProps>;
60
- export declare const useViteTheme: () => ViteThemeContextType;
61
- export {};
@@ -1,140 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useViteTheme = exports.ViteThemeProvider = void 0;
4
- const jsx_runtime_1 = require("react/jsx-runtime");
5
- const react_1 = require("react");
6
- const use_theme_animation_1 = require("../hooks/use-theme-animation");
7
- const types_1 = require("../types");
8
- const ViteThemeContext = (0, react_1.createContext)(undefined);
9
- /**
10
- * Vite Theme Provider - Optimized for Vite SPA applications
11
- *
12
- * This provider is designed for Vite-based single-page applications with optional
13
- * transition disabling to prevent flash during theme switches.
14
- *
15
- * Note: For flash prevention on initial load, add a script to your index.html
16
- * or inject it via Vite plugin to apply theme before React loads.
17
- *
18
- * @param children - React children to wrap with theme context
19
- * @param themes - Available theme options
20
- * @param colorThemes - Available color theme options
21
- * @param defaultTheme - Default theme to use
22
- * @param defaultColorTheme - Default color theme to use
23
- * @param animationType - Animation type for theme transitions
24
- * @param duration - Animation duration in milliseconds
25
- * @param attribute - HTML attribute to use for theme ('class' or 'data-theme')
26
- * @param disableTransitionOnChange - Temporarily disable CSS transitions during theme switch
27
- * @param storageKey - LocalStorage key for theme preference
28
- * @param colorStorageKey - LocalStorage key for color theme preference
29
- * @param globalClassName - Class name for dark theme (when using 'class' attribute)
30
- * @param colorThemePrefix - Prefix for color theme classes
31
- */
32
- const ViteThemeProvider = ({ children, themes = ['light', 'dark', 'system'], colorThemes = ['default'], defaultTheme = 'system', defaultColorTheme = 'default', animationType = types_1.ThemeAnimationType.CIRCLE, duration = 750, attribute = 'class', disableTransitionOnChange = false, storageKey = 'vite-theme', colorStorageKey = 'vite-color-theme', globalClassName = 'dark', colorThemePrefix = 'theme-', }) => {
33
- const themeState = (0, use_theme_animation_1.useThemeAnimation)({
34
- themes,
35
- colorThemes,
36
- defaultTheme,
37
- defaultColorTheme,
38
- animationType,
39
- duration,
40
- storageKey,
41
- colorStorageKey,
42
- globalClassName: attribute === 'class' ? globalClassName : undefined,
43
- colorThemePrefix,
44
- });
45
- const applyTransitionDisable = (0, react_1.useCallback)(() => {
46
- if (!disableTransitionOnChange)
47
- return () => { };
48
- const css = document.createElement('style');
49
- css.textContent = `*,*::before,*::after{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}`;
50
- document.head.appendChild(css);
51
- window.getComputedStyle(document.body);
52
- return () => {
53
- setTimeout(() => {
54
- document.head.removeChild(css);
55
- }, 1);
56
- };
57
- }, [disableTransitionOnChange]);
58
- const wrappedSetTheme = (0, react_1.useCallback)((theme) => {
59
- const cleanup = applyTransitionDisable();
60
- themeState.setTheme(theme);
61
- cleanup();
62
- }, [themeState.setTheme, applyTransitionDisable]);
63
- const wrappedSwitchTheme = (0, react_1.useCallback)(async (theme, animationOff = false) => {
64
- const cleanup = applyTransitionDisable();
65
- await themeState.switchTheme(theme, animationOff);
66
- cleanup();
67
- }, [themeState.switchTheme, applyTransitionDisable]);
68
- const wrappedToggleTheme = (0, react_1.useCallback)(async (animationOff = false) => {
69
- const cleanup = applyTransitionDisable();
70
- await themeState.toggleTheme(animationOff);
71
- cleanup();
72
- }, [themeState.toggleTheme, applyTransitionDisable]);
73
- const wrappedToggleLightTheme = (0, react_1.useCallback)(async (animationOff = false) => {
74
- const cleanup = applyTransitionDisable();
75
- await themeState.toggleLightTheme(animationOff);
76
- cleanup();
77
- }, [themeState.toggleLightTheme, applyTransitionDisable]);
78
- const wrappedToggleDarkTheme = (0, react_1.useCallback)(async (animationOff = false) => {
79
- const cleanup = applyTransitionDisable();
80
- await themeState.toggleDarkTheme(animationOff);
81
- cleanup();
82
- }, [themeState.toggleDarkTheme, applyTransitionDisable]);
83
- const switchThemeFromElement = async (theme, element) => {
84
- const cleanup = applyTransitionDisable();
85
- if (themeState.ref.current) {
86
- const originalRef = themeState.ref.current;
87
- Object.defineProperty(themeState.ref, 'current', {
88
- value: element,
89
- writable: true,
90
- configurable: true,
91
- });
92
- await themeState.switchTheme(theme);
93
- Object.defineProperty(themeState.ref, 'current', {
94
- value: originalRef,
95
- writable: true,
96
- configurable: true,
97
- });
98
- }
99
- else {
100
- Object.defineProperty(themeState.ref, 'current', {
101
- value: element,
102
- writable: true,
103
- configurable: true,
104
- });
105
- await themeState.switchTheme(theme);
106
- }
107
- cleanup();
108
- };
109
- const systemTheme = typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches
110
- ? 'dark'
111
- : 'light';
112
- const contextValue = {
113
- ref: themeState.ref,
114
- theme: themeState.theme,
115
- colorTheme: themeState.colorTheme,
116
- resolvedTheme: themeState.resolvedTheme,
117
- systemTheme,
118
- setTheme: wrappedSetTheme,
119
- setColorTheme: themeState.setColorTheme,
120
- switchTheme: wrappedSwitchTheme,
121
- switchThemeFromElement,
122
- switchColorTheme: themeState.switchColorTheme,
123
- toggleTheme: wrappedToggleTheme,
124
- toggleLightTheme: wrappedToggleLightTheme,
125
- toggleDarkTheme: wrappedToggleDarkTheme,
126
- toggleColorTheme: themeState.toggleColorTheme,
127
- createColorThemeToggle: themeState.createColorThemeToggle,
128
- isColorThemeActive: themeState.isColorThemeActive,
129
- };
130
- return (0, jsx_runtime_1.jsx)(ViteThemeContext.Provider, { value: contextValue, children: children });
131
- };
132
- exports.ViteThemeProvider = ViteThemeProvider;
133
- const useViteTheme = () => {
134
- const context = (0, react_1.useContext)(ViteThemeContext);
135
- if (context === undefined) {
136
- throw new Error('useViteTheme must be used within a ViteThemeProvider');
137
- }
138
- return context;
139
- };
140
- exports.useViteTheme = useViteTheme;
@@ -1,15 +0,0 @@
1
- import * as React from 'react';
2
- import * as SelectPrimitive from '@radix-ui/react-select';
3
- declare function Select({ ...props }: React.ComponentProps<typeof SelectPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
4
- declare function SelectGroup({ ...props }: React.ComponentProps<typeof SelectPrimitive.Group>): import("react/jsx-runtime").JSX.Element;
5
- declare function SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.Value>): import("react/jsx-runtime").JSX.Element;
6
- declare function SelectTrigger({ className, size, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
7
- size?: 'sm' | 'default';
8
- }): import("react/jsx-runtime").JSX.Element;
9
- declare function SelectContent({ className, children, position, ...props }: React.ComponentProps<typeof SelectPrimitive.Content>): import("react/jsx-runtime").JSX.Element;
10
- declare function SelectLabel({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Label>): import("react/jsx-runtime").JSX.Element;
11
- declare function SelectItem({ className, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Item>): import("react/jsx-runtime").JSX.Element;
12
- declare function SelectSeparator({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Separator>): import("react/jsx-runtime").JSX.Element;
13
- declare function SelectScrollUpButton({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>): import("react/jsx-runtime").JSX.Element;
14
- declare function SelectScrollDownButton({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>): import("react/jsx-runtime").JSX.Element;
15
- export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, };
@@ -1,83 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.Select = Select;
37
- exports.SelectContent = SelectContent;
38
- exports.SelectGroup = SelectGroup;
39
- exports.SelectItem = SelectItem;
40
- exports.SelectLabel = SelectLabel;
41
- exports.SelectScrollDownButton = SelectScrollDownButton;
42
- exports.SelectScrollUpButton = SelectScrollUpButton;
43
- exports.SelectSeparator = SelectSeparator;
44
- exports.SelectTrigger = SelectTrigger;
45
- exports.SelectValue = SelectValue;
46
- const jsx_runtime_1 = require("react/jsx-runtime");
47
- const SelectPrimitive = __importStar(require("@radix-ui/react-select"));
48
- const clsx_1 = require("clsx");
49
- function Select({ ...props }) {
50
- return (0, jsx_runtime_1.jsx)(SelectPrimitive.Root, { "data-slot": "select", ...props });
51
- }
52
- function SelectGroup({ ...props }) {
53
- return (0, jsx_runtime_1.jsx)(SelectPrimitive.Group, { "data-slot": "select-group", ...props });
54
- }
55
- function SelectValue({ ...props }) {
56
- return (0, jsx_runtime_1.jsx)(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
57
- }
58
- const ChevronDownIcon = () => ((0, jsx_runtime_1.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: (0, jsx_runtime_1.jsx)("path", { d: "m6 9 6 6 6-6" }) }));
59
- const ChevronUpIcon = () => ((0, jsx_runtime_1.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: (0, jsx_runtime_1.jsx)("path", { d: "m18 15-6-6-6 6" }) }));
60
- const CheckIcon = () => ((0, jsx_runtime_1.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: (0, jsx_runtime_1.jsx)("path", { d: "M20 6 9 17l-5-5" }) }));
61
- function SelectTrigger({ className, size = 'default', children, ...props }) {
62
- return ((0, jsx_runtime_1.jsxs)(SelectPrimitive.Trigger, { "data-slot": "select-trigger", "data-size": size, className: (0, clsx_1.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", className), ...props, children: [children, (0, jsx_runtime_1.jsx)(SelectPrimitive.Icon, { asChild: true, children: (0, jsx_runtime_1.jsx)(ChevronDownIcon, {}) })] }));
63
- }
64
- function SelectContent({ className, children, position = 'popper', ...props }) {
65
- return ((0, jsx_runtime_1.jsx)(SelectPrimitive.Portal, { children: (0, jsx_runtime_1.jsx)(SelectPrimitive.Content, { "data-slot": "select-content", className: (0, clsx_1.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', position === 'popper' &&
66
- 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1', className), position: position, ...props, children: (0, jsx_runtime_1.jsx)(SelectPrimitive.Viewport, { className: (0, clsx_1.clsx)('p-1', position === 'popper' &&
67
- 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]'), children: children }) }) }));
68
- }
69
- function SelectLabel({ className, ...props }) {
70
- return ((0, jsx_runtime_1.jsx)(SelectPrimitive.Label, { "data-slot": "select-label", className: (0, clsx_1.clsx)('py-1.5 pl-8 pr-2 text-sm font-semibold', className), ...props }));
71
- }
72
- function SelectItem({ className, children, ...props }) {
73
- return ((0, jsx_runtime_1.jsxs)(SelectPrimitive.Item, { "data-slot": "select-item", className: (0, clsx_1.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", className), ...props, children: [(0, jsx_runtime_1.jsx)("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: (0, jsx_runtime_1.jsx)(SelectPrimitive.ItemIndicator, { children: (0, jsx_runtime_1.jsx)(CheckIcon, {}) }) }), (0, jsx_runtime_1.jsx)(SelectPrimitive.ItemText, { children: children })] }));
74
- }
75
- function SelectSeparator({ className, ...props }) {
76
- return ((0, jsx_runtime_1.jsx)(SelectPrimitive.Separator, { "data-slot": "select-separator", className: (0, clsx_1.clsx)('-mx-1 my-1 h-px bg-muted', className), ...props }));
77
- }
78
- function SelectScrollUpButton({ className, ...props }) {
79
- return ((0, jsx_runtime_1.jsx)(SelectPrimitive.ScrollUpButton, { "data-slot": "select-scroll-up-button", className: (0, clsx_1.clsx)('flex cursor-default items-center justify-center py-1', className), ...props, children: (0, jsx_runtime_1.jsx)(ChevronUpIcon, {}) }));
80
- }
81
- function SelectScrollDownButton({ className, ...props }) {
82
- return ((0, jsx_runtime_1.jsx)(SelectPrimitive.ScrollDownButton, { "data-slot": "select-scroll-down-button", className: (0, clsx_1.clsx)('flex cursor-default items-center justify-center py-1', className), ...props, children: (0, jsx_runtime_1.jsx)(ChevronDownIcon, {}) }));
83
- }
@@ -1,2 +0,0 @@
1
- import { UseThemeAnimationProps, UseThemeAnimationReturn } from '../types';
2
- export declare const useThemeAnimation: (props?: UseThemeAnimationProps) => UseThemeAnimationReturn;