@space-man/react-theme-animation 1.1.1 → 2.1.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.
- package/README.md +129 -380
- package/dist/cjs/components/NextThemeProvider.d.ts +81 -0
- package/dist/cjs/components/NextThemeProvider.js +223 -0
- package/dist/cjs/components/SpacemanThemeProvider.d.ts +8 -2
- package/dist/cjs/components/SpacemanThemeProvider.js +16 -4
- package/dist/cjs/components/TanStackThemeProvider.d.ts +68 -0
- package/dist/cjs/components/TanStackThemeProvider.js +183 -0
- package/dist/cjs/components/ViteThemeProvider.d.ts +49 -7
- package/dist/cjs/components/ViteThemeProvider.js +115 -60
- package/dist/cjs/hooks/use-theme-animation.js +51 -37
- package/dist/cjs/index.d.ts +2 -1
- package/dist/cjs/index.js +8 -1
- package/dist/cjs/types/index.d.ts +8 -2
- package/dist/esm/components/NextThemeProvider.d.ts +81 -0
- package/dist/esm/components/NextThemeProvider.js +185 -0
- package/dist/esm/components/SpacemanThemeProvider.d.ts +8 -2
- package/dist/esm/components/SpacemanThemeProvider.js +16 -4
- package/dist/esm/components/TanStackThemeProvider.d.ts +68 -0
- package/dist/esm/components/TanStackThemeProvider.js +178 -0
- package/dist/esm/components/ViteThemeProvider.d.ts +49 -7
- package/dist/esm/components/ViteThemeProvider.js +117 -62
- package/dist/esm/hooks/use-theme-animation.js +51 -37
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.js +3 -0
- package/dist/esm/types/index.d.ts +8 -2
- package/package.json +1 -1
|
@@ -1,19 +1,61 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
import { Theme, ColorTheme, ThemeAnimationType } from '../types';
|
|
3
|
+
interface ViteThemeContextType {
|
|
4
|
+
ref: React.RefObject<HTMLButtonElement | null>;
|
|
4
5
|
theme: Theme;
|
|
6
|
+
colorTheme: ColorTheme;
|
|
5
7
|
resolvedTheme: 'light' | 'dark';
|
|
6
|
-
setTheme: (theme: Theme) => void;
|
|
7
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>;
|
|
8
20
|
}
|
|
9
21
|
interface ViteThemeProviderProps {
|
|
10
|
-
children:
|
|
11
|
-
|
|
22
|
+
children: ReactNode;
|
|
23
|
+
themes?: Theme[];
|
|
24
|
+
colorThemes?: ColorTheme[];
|
|
12
25
|
defaultTheme?: Theme;
|
|
13
|
-
|
|
26
|
+
defaultColorTheme?: ColorTheme;
|
|
27
|
+
animationType?: ThemeAnimationType;
|
|
28
|
+
duration?: number;
|
|
29
|
+
attribute?: 'class' | 'data-theme';
|
|
14
30
|
disableTransitionOnChange?: boolean;
|
|
15
31
|
storageKey?: string;
|
|
32
|
+
colorStorageKey?: string;
|
|
33
|
+
globalClassName?: string;
|
|
34
|
+
colorThemePrefix?: string;
|
|
16
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
|
+
*/
|
|
17
59
|
export declare const ViteThemeProvider: React.FC<ViteThemeProviderProps>;
|
|
18
60
|
export declare const useViteTheme: () => ViteThemeContextType;
|
|
19
61
|
export {};
|
|
@@ -3,76 +3,131 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.useViteTheme = exports.ViteThemeProvider = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const react_1 = require("react");
|
|
6
|
+
const use_theme_animation_1 = require("../hooks/use-theme-animation");
|
|
7
|
+
const types_1 = require("../types");
|
|
6
8
|
const ViteThemeContext = (0, react_1.createContext)(undefined);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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,
|
|
22
44
|
});
|
|
23
|
-
(0, react_1.
|
|
24
|
-
if (!
|
|
25
|
-
return;
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
mediaQuery.addEventListener('change', updateSystemTheme);
|
|
32
|
-
return () => mediaQuery.removeEventListener('change', updateSystemTheme);
|
|
33
|
-
}, [enableSystem]);
|
|
34
|
-
const resolvedTheme = theme === 'system' ? systemTheme : theme;
|
|
35
|
-
(0, react_1.useEffect)(() => {
|
|
36
|
-
if (!mounted)
|
|
37
|
-
return;
|
|
38
|
-
const root = document.documentElement;
|
|
39
|
-
if (disableTransitionOnChange) {
|
|
40
|
-
const css = document.createElement('style');
|
|
41
|
-
css.textContent = `*,*::before,*::after{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}`;
|
|
42
|
-
document.head.appendChild(css);
|
|
43
|
-
window.getComputedStyle(document.body);
|
|
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 () => {
|
|
44
53
|
setTimeout(() => {
|
|
45
54
|
document.head.removeChild(css);
|
|
46
55
|
}, 1);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
+
});
|
|
51
98
|
}
|
|
52
99
|
else {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
100
|
+
Object.defineProperty(themeState.ref, 'current', {
|
|
101
|
+
value: element,
|
|
102
|
+
writable: true,
|
|
103
|
+
configurable: true,
|
|
104
|
+
});
|
|
105
|
+
await themeState.switchTheme(theme);
|
|
57
106
|
}
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
const value = {
|
|
70
|
-
theme,
|
|
71
|
-
resolvedTheme,
|
|
72
|
-
setTheme,
|
|
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,
|
|
73
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,
|
|
74
129
|
};
|
|
75
|
-
return (0, jsx_runtime_1.jsx)(ViteThemeContext.Provider, { value:
|
|
130
|
+
return (0, jsx_runtime_1.jsx)(ViteThemeContext.Provider, { value: contextValue, children: children });
|
|
76
131
|
};
|
|
77
132
|
exports.ViteThemeProvider = ViteThemeProvider;
|
|
78
133
|
const useViteTheme = () => {
|
|
@@ -13,34 +13,23 @@ const useThemeAnimation = (props = {}) => {
|
|
|
13
13
|
const isHighResolution = isBrowser && (window.innerWidth >= 3000 || window.innerHeight >= 2000);
|
|
14
14
|
const duration = isHighResolution ? Math.max(propsDuration * 0.8, 500) : propsDuration;
|
|
15
15
|
const [mounted, setMounted] = (0, react_1.useState)(false);
|
|
16
|
+
// Inject base styles once on mount
|
|
16
17
|
(0, react_1.useEffect)(() => {
|
|
17
18
|
(0, animations_1.injectBaseStyles)();
|
|
19
|
+
setMounted(true);
|
|
18
20
|
}, []);
|
|
19
21
|
const [internalTheme, setInternalTheme] = (0, react_1.useState)(() => {
|
|
20
22
|
if (!isBrowser)
|
|
21
23
|
return defaultTheme;
|
|
22
|
-
|
|
24
|
+
const saved = localStorage.getItem(storageKey);
|
|
25
|
+
return saved && themes.indexOf(saved) !== -1 ? saved : defaultTheme;
|
|
23
26
|
});
|
|
24
27
|
const [internalColorTheme, setInternalColorTheme] = (0, react_1.useState)(() => {
|
|
25
28
|
if (!isBrowser)
|
|
26
29
|
return defaultColorTheme;
|
|
27
|
-
|
|
30
|
+
const saved = localStorage.getItem(colorStorageKey);
|
|
31
|
+
return saved && colorThemes.indexOf(saved) !== -1 ? saved : defaultColorTheme;
|
|
28
32
|
});
|
|
29
|
-
(0, react_1.useEffect)(() => {
|
|
30
|
-
setMounted(true);
|
|
31
|
-
if (isBrowser && !externalTheme) {
|
|
32
|
-
const saved = localStorage.getItem(storageKey);
|
|
33
|
-
if (saved && themes.indexOf(saved) !== -1) {
|
|
34
|
-
setInternalTheme(saved);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
if (isBrowser && !externalColorTheme) {
|
|
38
|
-
const saved = localStorage.getItem(colorStorageKey);
|
|
39
|
-
if (saved && colorThemes.indexOf(saved) !== -1) {
|
|
40
|
-
setInternalColorTheme(saved);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}, []);
|
|
44
33
|
const currentTheme = externalTheme ?? internalTheme;
|
|
45
34
|
const currentColorTheme = externalColorTheme ?? internalColorTheme;
|
|
46
35
|
const [, setSystemTheme] = (0, react_1.useState)(() => (0, animations_1.getSystemTheme)());
|
|
@@ -97,8 +86,8 @@ const useThemeAnimation = (props = {}) => {
|
|
|
97
86
|
onColorThemeChange(newColorTheme);
|
|
98
87
|
}
|
|
99
88
|
}, [onColorThemeChange, externalColorTheme, colorStorageKey]);
|
|
100
|
-
const switchTheme = (0, react_1.useCallback)(async (newTheme) => {
|
|
101
|
-
if (!ref.current || !(0, animations_1.supportsViewTransitions)() || (0, animations_1.prefersReducedMotion)()) {
|
|
89
|
+
const switchTheme = (0, react_1.useCallback)(async (newTheme, animationOff = false) => {
|
|
90
|
+
if (!ref.current || !(0, animations_1.supportsViewTransitions)() || (0, animations_1.prefersReducedMotion)() || animationOff) {
|
|
102
91
|
setTheme(newTheme);
|
|
103
92
|
return;
|
|
104
93
|
}
|
|
@@ -186,26 +175,45 @@ const useThemeAnimation = (props = {}) => {
|
|
|
186
175
|
slideToX,
|
|
187
176
|
slideToY,
|
|
188
177
|
]);
|
|
189
|
-
const
|
|
178
|
+
const switchColorTheme = (0, react_1.useCallback)((newColorTheme) => {
|
|
179
|
+
if (colorThemes.indexOf(newColorTheme) === -1) {
|
|
180
|
+
console.warn(`Color theme "${newColorTheme}" not found in available themes`);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
setColorTheme(newColorTheme);
|
|
184
|
+
}, [colorThemes, setColorTheme]);
|
|
185
|
+
const toggleTheme = (0, react_1.useCallback)(async (animationOff = false) => {
|
|
190
186
|
const newTheme = resolvedTheme === 'dark' ? 'light' : 'dark';
|
|
191
|
-
await switchTheme(newTheme);
|
|
187
|
+
await switchTheme(newTheme, animationOff);
|
|
192
188
|
}, [resolvedTheme, switchTheme]);
|
|
193
|
-
(0, react_1.
|
|
194
|
-
if (
|
|
189
|
+
const toggleLightTheme = (0, react_1.useCallback)(async (animationOff = false) => {
|
|
190
|
+
if (resolvedTheme === 'light')
|
|
195
191
|
return;
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}, [
|
|
192
|
+
await switchTheme('light', animationOff);
|
|
193
|
+
}, [resolvedTheme, switchTheme]);
|
|
194
|
+
const toggleDarkTheme = (0, react_1.useCallback)(async (animationOff = false) => {
|
|
195
|
+
if (resolvedTheme === 'dark')
|
|
196
|
+
return;
|
|
197
|
+
await switchTheme('dark', animationOff);
|
|
198
|
+
}, [resolvedTheme, switchTheme]);
|
|
199
|
+
const toggleColorTheme = (0, react_1.useCallback)(() => {
|
|
200
|
+
const currentIndex = colorThemes.indexOf(currentColorTheme);
|
|
201
|
+
const nextIndex = (currentIndex + 1) % colorThemes.length;
|
|
202
|
+
const nextColorTheme = colorThemes[nextIndex];
|
|
203
|
+
setColorTheme(nextColorTheme);
|
|
204
|
+
}, [currentColorTheme, colorThemes, setColorTheme]);
|
|
205
|
+
const createColorThemeToggle = (0, react_1.useCallback)((targetColorTheme) => {
|
|
206
|
+
return () => {
|
|
207
|
+
if (colorThemes.indexOf(targetColorTheme) === -1) {
|
|
208
|
+
console.warn(`Color theme "${targetColorTheme}" not found in available themes`);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
setColorTheme(targetColorTheme);
|
|
212
|
+
};
|
|
213
|
+
}, [colorThemes, setColorTheme]);
|
|
214
|
+
const isColorThemeActive = (0, react_1.useCallback)((targetColorTheme) => {
|
|
215
|
+
return currentColorTheme === targetColorTheme;
|
|
216
|
+
}, [currentColorTheme]);
|
|
209
217
|
return {
|
|
210
218
|
ref,
|
|
211
219
|
theme: currentTheme,
|
|
@@ -213,8 +221,14 @@ const useThemeAnimation = (props = {}) => {
|
|
|
213
221
|
resolvedTheme,
|
|
214
222
|
setTheme,
|
|
215
223
|
setColorTheme,
|
|
216
|
-
toggleTheme,
|
|
217
224
|
switchTheme,
|
|
225
|
+
switchColorTheme,
|
|
226
|
+
toggleTheme,
|
|
227
|
+
toggleLightTheme,
|
|
228
|
+
toggleDarkTheme,
|
|
229
|
+
toggleColorTheme,
|
|
230
|
+
createColorThemeToggle,
|
|
231
|
+
isColorThemeActive,
|
|
218
232
|
};
|
|
219
233
|
};
|
|
220
234
|
exports.useThemeAnimation = useThemeAnimation;
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -2,8 +2,9 @@ export { useThemeAnimation } from './hooks/use-theme-animation';
|
|
|
2
2
|
export { ThemeSwitcher } from './components/ThemeSwitcher';
|
|
3
3
|
export { ThemeSelector } from './components/ThemeSelector';
|
|
4
4
|
export { SpacemanThemeProvider, useSpacemanTheme } from './components/SpacemanThemeProvider';
|
|
5
|
+
export { NextThemeProvider, useNextTheme } from './components/NextThemeProvider';
|
|
6
|
+
export { TanStackThemeProvider, useTanStackTheme } from './components/TanStackThemeProvider';
|
|
5
7
|
export { ViteThemeProvider, useViteTheme } from './components/ViteThemeProvider';
|
|
6
8
|
export type { UseThemeAnimationProps, UseThemeAnimationReturn, ThemeSwitcherProps, ThemeSelectorProps, Theme, ColorTheme, SlideDirection, } from './types';
|
|
7
|
-
export type { ViteThemeContextType } from './components/ViteThemeProvider';
|
|
8
9
|
export { ThemeAnimationType } from './types';
|
|
9
10
|
export { injectBaseStyles, getSystemTheme, resolveTheme, supportsViewTransitions, prefersReducedMotion, } from './utils/animations';
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.prefersReducedMotion = exports.supportsViewTransitions = exports.resolveTheme = exports.getSystemTheme = exports.injectBaseStyles = exports.ThemeAnimationType = exports.useViteTheme = exports.ViteThemeProvider = exports.useSpacemanTheme = exports.SpacemanThemeProvider = exports.ThemeSelector = exports.ThemeSwitcher = exports.useThemeAnimation = void 0;
|
|
3
|
+
exports.prefersReducedMotion = exports.supportsViewTransitions = exports.resolveTheme = exports.getSystemTheme = exports.injectBaseStyles = exports.ThemeAnimationType = exports.useViteTheme = exports.ViteThemeProvider = exports.useTanStackTheme = exports.TanStackThemeProvider = exports.useNextTheme = exports.NextThemeProvider = exports.useSpacemanTheme = exports.SpacemanThemeProvider = exports.ThemeSelector = exports.ThemeSwitcher = exports.useThemeAnimation = void 0;
|
|
4
4
|
var use_theme_animation_1 = require("./hooks/use-theme-animation");
|
|
5
5
|
Object.defineProperty(exports, "useThemeAnimation", { enumerable: true, get: function () { return use_theme_animation_1.useThemeAnimation; } });
|
|
6
6
|
var ThemeSwitcher_1 = require("./components/ThemeSwitcher");
|
|
@@ -10,6 +10,13 @@ Object.defineProperty(exports, "ThemeSelector", { enumerable: true, get: functio
|
|
|
10
10
|
var SpacemanThemeProvider_1 = require("./components/SpacemanThemeProvider");
|
|
11
11
|
Object.defineProperty(exports, "SpacemanThemeProvider", { enumerable: true, get: function () { return SpacemanThemeProvider_1.SpacemanThemeProvider; } });
|
|
12
12
|
Object.defineProperty(exports, "useSpacemanTheme", { enumerable: true, get: function () { return SpacemanThemeProvider_1.useSpacemanTheme; } });
|
|
13
|
+
// Framework-specific optimized providers
|
|
14
|
+
var NextThemeProvider_1 = require("./components/NextThemeProvider");
|
|
15
|
+
Object.defineProperty(exports, "NextThemeProvider", { enumerable: true, get: function () { return NextThemeProvider_1.NextThemeProvider; } });
|
|
16
|
+
Object.defineProperty(exports, "useNextTheme", { enumerable: true, get: function () { return NextThemeProvider_1.useNextTheme; } });
|
|
17
|
+
var TanStackThemeProvider_1 = require("./components/TanStackThemeProvider");
|
|
18
|
+
Object.defineProperty(exports, "TanStackThemeProvider", { enumerable: true, get: function () { return TanStackThemeProvider_1.TanStackThemeProvider; } });
|
|
19
|
+
Object.defineProperty(exports, "useTanStackTheme", { enumerable: true, get: function () { return TanStackThemeProvider_1.useTanStackTheme; } });
|
|
13
20
|
var ViteThemeProvider_1 = require("./components/ViteThemeProvider");
|
|
14
21
|
Object.defineProperty(exports, "ViteThemeProvider", { enumerable: true, get: function () { return ViteThemeProvider_1.ViteThemeProvider; } });
|
|
15
22
|
Object.defineProperty(exports, "useViteTheme", { enumerable: true, get: function () { return ViteThemeProvider_1.useViteTheme; } });
|
|
@@ -38,8 +38,14 @@ export interface UseThemeAnimationReturn {
|
|
|
38
38
|
resolvedTheme: 'light' | 'dark';
|
|
39
39
|
setTheme: (theme: Theme) => void;
|
|
40
40
|
setColorTheme: (colorTheme: ColorTheme) => void;
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
switchTheme: (theme: Theme, animationOff?: boolean) => Promise<void>;
|
|
42
|
+
switchColorTheme: (colorTheme: string) => void;
|
|
43
|
+
toggleTheme: (animationOff?: boolean) => Promise<void>;
|
|
44
|
+
toggleLightTheme: (animationOff?: boolean) => Promise<void>;
|
|
45
|
+
toggleDarkTheme: (animationOff?: boolean) => Promise<void>;
|
|
46
|
+
toggleColorTheme: () => void;
|
|
47
|
+
createColorThemeToggle: (targetColorTheme: string) => () => void;
|
|
48
|
+
isColorThemeActive: (targetColorTheme: string) => boolean;
|
|
43
49
|
}
|
|
44
50
|
export interface ThemeSwitcherProps {
|
|
45
51
|
themes?: Theme[];
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
import { Theme, ColorTheme, ThemeAnimationType } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Context type for the Next Theme Provider
|
|
5
|
+
*/
|
|
6
|
+
interface NextThemeContextType {
|
|
7
|
+
ref: React.RefObject<HTMLButtonElement | null>;
|
|
8
|
+
theme: Theme;
|
|
9
|
+
colorTheme: ColorTheme;
|
|
10
|
+
resolvedTheme: 'light' | 'dark';
|
|
11
|
+
systemTheme: 'light' | 'dark';
|
|
12
|
+
setTheme: (theme: Theme) => void;
|
|
13
|
+
setColorTheme: (colorTheme: ColorTheme) => void;
|
|
14
|
+
switchTheme: (theme: Theme, animationOff?: boolean) => Promise<void>;
|
|
15
|
+
switchColorTheme: (colorTheme: string) => void;
|
|
16
|
+
toggleTheme: (animationOff?: boolean) => Promise<void>;
|
|
17
|
+
toggleLightTheme: (animationOff?: boolean) => Promise<void>;
|
|
18
|
+
toggleDarkTheme: (animationOff?: boolean) => Promise<void>;
|
|
19
|
+
toggleColorTheme: () => void;
|
|
20
|
+
createColorThemeToggle: (targetColorTheme: string) => () => void;
|
|
21
|
+
isColorThemeActive: (targetColorTheme: string) => boolean;
|
|
22
|
+
switchThemeFromElement: (theme: Theme, element: HTMLButtonElement) => Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Props for the Next Theme Provider
|
|
26
|
+
*/
|
|
27
|
+
interface NextThemeProviderProps {
|
|
28
|
+
children: ReactNode;
|
|
29
|
+
themes?: Theme[];
|
|
30
|
+
colorThemes?: ColorTheme[];
|
|
31
|
+
defaultTheme?: Theme;
|
|
32
|
+
defaultColorTheme?: ColorTheme;
|
|
33
|
+
animationType?: ThemeAnimationType;
|
|
34
|
+
duration?: number;
|
|
35
|
+
storageKey?: string;
|
|
36
|
+
colorStorageKey?: string;
|
|
37
|
+
attribute?: 'class' | 'data-theme';
|
|
38
|
+
globalClassName?: string;
|
|
39
|
+
colorThemePrefix?: string;
|
|
40
|
+
nonce?: string;
|
|
41
|
+
disableAnimationOnInit?: boolean;
|
|
42
|
+
disablePreHydrationScript?: boolean;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Next Theme Provider - Next.js optimized theme management with animations
|
|
46
|
+
*
|
|
47
|
+
* This provider is specifically optimized for Next.js and SSR frameworks with
|
|
48
|
+
* pre-hydration script injection to prevent flash of wrong theme.
|
|
49
|
+
*
|
|
50
|
+
* Features:
|
|
51
|
+
* - Pre-hydration script for flash prevention (SSR apps)
|
|
52
|
+
* - Animated theme transitions via View Transitions API
|
|
53
|
+
* - Multi-dimensional theming (theme + colorTheme)
|
|
54
|
+
* - System theme detection
|
|
55
|
+
* - CSP support via nonce prop
|
|
56
|
+
*
|
|
57
|
+
* @param children - React children to wrap with theme context
|
|
58
|
+
* @param themes - Available theme options
|
|
59
|
+
* @param colorThemes - Available color theme options
|
|
60
|
+
* @param defaultTheme - Default theme to use
|
|
61
|
+
* @param defaultColorTheme - Default color theme to use
|
|
62
|
+
* @param animationType - Animation type for theme transitions
|
|
63
|
+
* @param duration - Animation duration in milliseconds
|
|
64
|
+
* @param storageKey - LocalStorage key for theme preference
|
|
65
|
+
* @param colorStorageKey - LocalStorage key for color theme preference
|
|
66
|
+
* @param attribute - HTML attribute to use for theme ('class' or 'data-theme')
|
|
67
|
+
* @param globalClassName - Class name for dark theme (when using 'class' attribute)
|
|
68
|
+
* @param colorThemePrefix - Prefix for color theme classes
|
|
69
|
+
* @param nonce - CSP nonce for inline script (SSR apps)
|
|
70
|
+
* @param disableAnimationOnInit - Skip animation during initial hydration
|
|
71
|
+
* @param disablePreHydrationScript - Disable flash prevention script (for SPAs without SSR)
|
|
72
|
+
*/
|
|
73
|
+
export declare const NextThemeProvider: React.FC<NextThemeProviderProps>;
|
|
74
|
+
/**
|
|
75
|
+
* Hook to consume the Next Theme context
|
|
76
|
+
*
|
|
77
|
+
* @returns Theme context value with all theme state and methods
|
|
78
|
+
* @throws Error if used outside of NextThemeProvider
|
|
79
|
+
*/
|
|
80
|
+
export declare const useNextTheme: () => NextThemeContextType;
|
|
81
|
+
export {};
|