@asafarim/react-themes 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ali SAFARI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,291 @@
1
+ # @asafarim/react-themes
2
+
3
+ A comprehensive theme management system for React applications with automatic dark/light mode detection, custom theme creation, and smooth transitions.
4
+
5
+ ![npm version](https://img.shields.io/npm/v/@asafarim/react-themes)
6
+ ![license](https://img.shields.io/npm/l/@asafarim/react-themes)
7
+ ![typescript](https://img.shields.io/badge/TypeScript-Ready-blue)
8
+
9
+ ## ✨ Features
10
+
11
+ - 🌓 **Auto Dark/Light Mode**: Automatic system preference detection
12
+ - 🎨 **Custom Themes**: Create and apply custom themes easily
13
+ - ⚡ **TypeScript Ready**: Full TypeScript support with type definitions
14
+ - 🔄 **Smooth Transitions**: Beautiful transitions between theme changes
15
+ - 💾 **Persistence**: Automatically save user preferences to localStorage
16
+ - 🎯 **CSS Variables**: Automatic CSS variable injection for styling
17
+ - 🔧 **Flexible API**: Easy to integrate with existing projects
18
+ - ♿ **Accessible**: Built with accessibility in mind
19
+
20
+ ## 📦 Installation
21
+
22
+ ```bash
23
+ npm install @asafarim/react-themes
24
+ # or
25
+ yarn add @asafarim/react-themes
26
+ # or
27
+ pnpm add @asafarim/react-themes
28
+ ```
29
+
30
+ ## 🚀 Quick Start
31
+
32
+ ### 1. Wrap your app with ThemeProvider
33
+
34
+ ```tsx
35
+ import React from 'react';
36
+ import { ThemeProvider } from '@asafarim/react-themes';
37
+ import '@asafarim/react-themes/styles.css'; // Optional base styles
38
+
39
+ function App() {
40
+ return (
41
+ <ThemeProvider defaultMode="auto" persistMode={true}>
42
+ <YourAppContent />
43
+ </ThemeProvider>
44
+ );
45
+ }
46
+ ```
47
+
48
+ ### 2. Use the theme in your components
49
+
50
+ ```tsx
51
+ import React from 'react';
52
+ import { useTheme, ThemeToggle } from '@asafarim/react-themes';
53
+
54
+ function MyComponent() {
55
+ const { mode, currentTheme, toggleMode } = useTheme();
56
+
57
+ return (
58
+ <div>
59
+ <h1>Current mode: {mode}</h1>
60
+ <ThemeToggle />
61
+ {/* Your component content */}
62
+ </div>
63
+ );
64
+ }
65
+ ```
66
+
67
+ ## 📖 API Reference
68
+
69
+ ### ThemeProvider
70
+
71
+ The main provider component that manages theme state and applies CSS variables.
72
+
73
+ ```tsx
74
+ interface ThemeProviderProps {
75
+ children: ReactNode;
76
+ defaultMode?: 'light' | 'dark' | 'auto';
77
+ defaultTheme?: string;
78
+ persistMode?: boolean;
79
+ storageKey?: string;
80
+ customThemes?: Record<string, Theme>;
81
+ }
82
+ ```
83
+
84
+ **Props:**
85
+ - `defaultMode`: Initial theme mode (default: 'auto')
86
+ - `defaultTheme`: Default theme name (default: 'default')
87
+ - `persistMode`: Save theme preference to localStorage (default: true)
88
+ - `storageKey`: localStorage key for persistence (default: 'asafarim-theme-mode')
89
+ - `customThemes`: Additional custom themes
90
+
91
+ ### useTheme Hook
92
+
93
+ Access theme state and controls.
94
+
95
+ ```tsx
96
+ const {
97
+ currentTheme, // Current active theme object
98
+ mode, // Current mode: 'light' | 'dark' | 'auto'
99
+ setMode, // Function to change mode
100
+ setTheme, // Function to change theme
101
+ themes, // Available themes
102
+ toggleMode // Function to cycle through modes
103
+ } = useTheme();
104
+ ```
105
+
106
+ ### useThemeToggle Hook
107
+
108
+ Simplified hook for theme toggling functionality.
109
+
110
+ ```tsx
111
+ const {
112
+ mode, // Current mode
113
+ setMode, // Set specific mode
114
+ toggleMode, // Toggle between modes
115
+ isDark, // Boolean: is dark mode
116
+ isLight, // Boolean: is light mode
117
+ isAuto // Boolean: is auto mode
118
+ } = useThemeToggle();
119
+ ```
120
+
121
+ ### Components
122
+
123
+ #### ThemeToggle
124
+
125
+ A pre-built theme toggle button.
126
+
127
+ ```tsx
128
+ <ThemeToggle
129
+ size="md" // 'sm' | 'md' | 'lg'
130
+ showLabels={false} // Show text labels
131
+ className="custom-class"
132
+ style={{ margin: '10px' }}
133
+ />
134
+ ```
135
+
136
+ #### ThemeSelector
137
+
138
+ A dropdown selector for theme modes.
139
+
140
+ ```tsx
141
+ <ThemeSelector
142
+ showLabels={true}
143
+ className="custom-class"
144
+ options={[
145
+ { mode: 'light', label: 'Light', icon: '☀️' },
146
+ { mode: 'dark', label: 'Dark', icon: '🌙' },
147
+ { mode: 'auto', label: 'Auto', icon: '🌓' }
148
+ ]}
149
+ />
150
+ ```
151
+
152
+ ## 🎨 Custom Themes
153
+
154
+ ### Creating Custom Themes
155
+
156
+ ```tsx
157
+ import { createTheme, lightTheme } from '@asafarim/react-themes';
158
+
159
+ const myCustomTheme = createTheme(lightTheme, {
160
+ name: 'my-theme',
161
+ colors: {
162
+ primary: '#ff6b6b',
163
+ primaryHover: '#ff5252',
164
+ background: '#f8f9fa',
165
+ text: '#212529'
166
+ }
167
+ });
168
+
169
+ // Use with provider
170
+ <ThemeProvider customThemes={{ 'my-theme': myCustomTheme }}>
171
+ <App />
172
+ </ThemeProvider>
173
+ ```
174
+
175
+ ### Using CSS Variables
176
+
177
+ The package automatically injects CSS variables that you can use in your styles:
178
+
179
+ ```css
180
+ .my-component {
181
+ background-color: var(--theme-color-background);
182
+ color: var(--theme-color-text);
183
+ border: 1px solid var(--theme-color-border);
184
+ border-radius: var(--theme-radius-md);
185
+ padding: var(--theme-spacing-md);
186
+ transition: all var(--theme-transition-normal);
187
+ }
188
+
189
+ .my-button {
190
+ background-color: var(--theme-color-primary);
191
+ color: white;
192
+ font-size: var(--theme-font-size-sm);
193
+ }
194
+
195
+ .my-button:hover {
196
+ background-color: var(--theme-color-primary-hover);
197
+ }
198
+ ```
199
+
200
+ ## 🎯 Integration with @asafarim/dd-menu
201
+
202
+ This package works seamlessly with `@asafarim/dd-menu`:
203
+
204
+ ```tsx
205
+ import { DDMenu } from '@asafarim/dd-menu';
206
+ import { useTheme } from '@asafarim/react-themes';
207
+
208
+ function NavMenu() {
209
+ const { mode } = useTheme();
210
+
211
+ return (
212
+ <DDMenu
213
+ items={menuItems}
214
+ theme={mode} // Pass current theme mode
215
+ variant="navbar"
216
+ />
217
+ );
218
+ }
219
+ ```
220
+
221
+ ## 🔧 Advanced Usage
222
+
223
+ ### Custom Theme Structure
224
+
225
+ ```tsx
226
+ interface Theme {
227
+ name: string;
228
+ mode: 'light' | 'dark' | 'auto';
229
+ colors: {
230
+ background: string;
231
+ backgroundSecondary: string;
232
+ text: string;
233
+ textSecondary: string;
234
+ primary: string;
235
+ primaryHover: string;
236
+ border: string;
237
+ // ... more colors
238
+ };
239
+ spacing: {
240
+ xs: string;
241
+ sm: string;
242
+ md: string;
243
+ lg: string;
244
+ // ... more spacing
245
+ };
246
+ // ... typography, radius, transitions, zIndex
247
+ }
248
+ ```
249
+
250
+ ### Programmatic Theme Application
251
+
252
+ ```tsx
253
+ import { applyTheme } from '@asafarim/react-themes';
254
+
255
+ // Apply theme manually
256
+ applyTheme(customTheme, 'dark');
257
+ ```
258
+
259
+ ## 🌍 Browser Support
260
+
261
+ - Modern browsers with CSS custom properties support
262
+ - Chrome 49+
263
+ - Firefox 31+
264
+ - Safari 9.1+
265
+ - Edge 16+
266
+
267
+ ## 🤝 Contributing
268
+
269
+ Contributions are welcome! Please read our contributing guidelines and submit a pull request.
270
+
271
+ ## 📄 License
272
+
273
+ MIT License - see the [LICENSE](LICENSE) file for details.
274
+
275
+ ## 🔗 Related Packages
276
+
277
+ - [`@asafarim/dd-menu`](https://www.npmjs.com/package/@asafarim/dd-menu) - Elegant dropdown menu component
278
+
279
+ ## 📝 Changelog
280
+
281
+ ### 1.0.0
282
+ - Initial release
283
+ - Theme provider with auto mode detection
284
+ - CSS variable injection
285
+ - Built-in components (ThemeToggle, ThemeSelector)
286
+ - TypeScript support
287
+ - localStorage persistence
288
+
289
+ ---
290
+
291
+ Made with ❤️ by [ASafariM](https://github.com/AliSafari-IT)
@@ -0,0 +1,241 @@
1
+ import * as React$1 from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ type ThemeMode = 'light' | 'dark' | 'auto';
5
+ interface ThemeColors {
6
+ background: string;
7
+ backgroundSecondary: string;
8
+ backgroundTertiary: string;
9
+ text: string;
10
+ textSecondary: string;
11
+ textMuted: string;
12
+ border: string;
13
+ borderLight: string;
14
+ borderHover: string;
15
+ primary: string;
16
+ primaryHover: string;
17
+ primaryActive: string;
18
+ success: string;
19
+ warning: string;
20
+ error: string;
21
+ info: string;
22
+ hover: string;
23
+ active: string;
24
+ focus: string;
25
+ shadow: string;
26
+ shadowMd: string;
27
+ shadowLg: string;
28
+ }
29
+ interface ThemeSpacing {
30
+ xs: string;
31
+ sm: string;
32
+ md: string;
33
+ lg: string;
34
+ xl: string;
35
+ '2xl': string;
36
+ '3xl': string;
37
+ '4xl': string;
38
+ }
39
+ interface ThemeRadius {
40
+ none: string;
41
+ sm: string;
42
+ md: string;
43
+ lg: string;
44
+ xl: string;
45
+ '2xl': string;
46
+ full: string;
47
+ }
48
+ interface ThemeTypography {
49
+ fontFamily: {
50
+ sans: string;
51
+ serif: string;
52
+ mono: string;
53
+ };
54
+ fontSize: {
55
+ xs: string;
56
+ sm: string;
57
+ base: string;
58
+ lg: string;
59
+ xl: string;
60
+ '2xl': string;
61
+ '3xl': string;
62
+ '4xl': string;
63
+ '5xl': string;
64
+ };
65
+ fontWeight: {
66
+ light: string;
67
+ normal: string;
68
+ medium: string;
69
+ semibold: string;
70
+ bold: string;
71
+ };
72
+ lineHeight: {
73
+ tight: string;
74
+ normal: string;
75
+ relaxed: string;
76
+ };
77
+ }
78
+ interface ThemeTransitions {
79
+ fast: string;
80
+ normal: string;
81
+ slow: string;
82
+ bounce: string;
83
+ }
84
+ interface Theme {
85
+ name: string;
86
+ mode: ThemeMode;
87
+ colors: ThemeColors;
88
+ spacing: ThemeSpacing;
89
+ radius: ThemeRadius;
90
+ typography: ThemeTypography;
91
+ transitions: ThemeTransitions;
92
+ zIndex: {
93
+ dropdown: number;
94
+ modal: number;
95
+ tooltip: number;
96
+ overlay: number;
97
+ };
98
+ }
99
+ interface ThemeContextValue {
100
+ theme: Theme;
101
+ mode: ThemeMode;
102
+ setMode: (mode: ThemeMode) => void;
103
+ toggleMode: () => void;
104
+ isDark: boolean;
105
+ isLight: boolean;
106
+ isAuto: boolean;
107
+ systemPrefersDark: boolean;
108
+ applyTheme: (customTheme: Partial<Theme>) => void;
109
+ resetTheme: () => void;
110
+ }
111
+ interface ThemeProviderProps$1 {
112
+ children: React.ReactNode;
113
+ defaultMode?: ThemeMode;
114
+ customTheme?: Partial<Theme>;
115
+ storageKey?: string;
116
+ enableTransitions?: boolean;
117
+ className?: string;
118
+ style?: React.CSSProperties;
119
+ }
120
+ interface UseThemeOptions {
121
+ defaultMode?: ThemeMode;
122
+ storageKey?: string;
123
+ }
124
+ interface ThemeConfig {
125
+ defaultMode?: ThemeMode;
126
+ defaultTheme?: string;
127
+ persistMode?: boolean;
128
+ storageKey?: string;
129
+ enableTransitions?: boolean;
130
+ customThemes?: Record<string, Theme>;
131
+ }
132
+ interface ThemeVariables {
133
+ colors: Record<keyof ThemeColors, string>;
134
+ spacing: Record<keyof ThemeSpacing, string>;
135
+ radius: Record<keyof ThemeRadius, string>;
136
+ typography: {
137
+ fontFamily: Record<keyof ThemeTypography['fontFamily'], string>;
138
+ fontSize: Record<keyof ThemeTypography['fontSize'], string>;
139
+ fontWeight: Record<keyof ThemeTypography['fontWeight'], string>;
140
+ lineHeight: Record<keyof ThemeTypography['lineHeight'], string>;
141
+ };
142
+ transitions: Record<keyof ThemeTransitions, string>;
143
+ zIndex: Record<keyof Theme['zIndex'], string>;
144
+ }
145
+
146
+ declare const lightTheme: Theme;
147
+ declare const darkTheme: Theme;
148
+ declare const defaultTheme: Theme;
149
+ declare const themes: {
150
+ light: Theme;
151
+ dark: Theme;
152
+ };
153
+ declare const defaultThemes: {
154
+ default: Theme;
155
+ light: Theme;
156
+ dark: Theme;
157
+ };
158
+ declare function mergeTheme(baseTheme: Theme, customTheme: Partial<Theme>): Theme;
159
+
160
+ interface ThemeContextType {
161
+ currentTheme: Theme;
162
+ mode: ThemeMode;
163
+ setMode: (mode: ThemeMode) => void;
164
+ setTheme: (theme: Theme) => void;
165
+ themes: Record<string, Theme>;
166
+ toggleMode: () => void;
167
+ }
168
+ interface ThemeProviderProps {
169
+ children: ReactNode;
170
+ config?: ThemeConfig;
171
+ defaultMode?: ThemeMode;
172
+ defaultTheme?: string;
173
+ persistMode?: boolean;
174
+ storageKey?: string;
175
+ customThemes?: Record<string, Theme>;
176
+ }
177
+ declare const ThemeProvider: React$1.FC<ThemeProviderProps>;
178
+
179
+ /**
180
+ * Hook to access theme context
181
+ */
182
+ declare function useTheme(): ThemeContextType;
183
+
184
+ /**
185
+ * Hook that provides theme toggle functionality
186
+ */
187
+ declare function useThemeToggle(): {
188
+ mode: ThemeMode;
189
+ setMode: (mode: ThemeMode) => void;
190
+ toggleMode: () => void;
191
+ isDark: boolean;
192
+ isLight: boolean;
193
+ isAuto: boolean;
194
+ effectiveMode: "light" | "dark";
195
+ };
196
+
197
+ interface ThemeToggleProps {
198
+ className?: string;
199
+ style?: React$1.CSSProperties;
200
+ showLabels?: boolean;
201
+ size?: 'sm' | 'md' | 'lg';
202
+ }
203
+ declare const ThemeToggle: React$1.FC<ThemeToggleProps>;
204
+
205
+ interface ThemeSelectorProps {
206
+ className?: string;
207
+ style?: React$1.CSSProperties;
208
+ showLabels?: boolean;
209
+ options?: Array<{
210
+ mode: ThemeMode;
211
+ label: string;
212
+ icon?: string;
213
+ }>;
214
+ }
215
+ declare const ThemeSelector: React$1.FC<ThemeSelectorProps>;
216
+
217
+ /**
218
+ * Creates a new theme by merging a base theme with custom properties
219
+ */
220
+ declare function createTheme(baseTheme: Theme, customTheme: Partial<Theme>): Theme;
221
+
222
+ /**
223
+ * Applies theme CSS variables to the document root
224
+ */
225
+ declare function applyTheme(theme: Theme, mode: ThemeMode): void;
226
+
227
+ /**
228
+ * Merges multiple themes into a single theme
229
+ * Later themes in the array take precedence over earlier ones
230
+ */
231
+ declare function mergeThemes(...themes: Array<Theme | Partial<Theme>>): Theme;
232
+ /**
233
+ * Merges theme colors only
234
+ */
235
+ declare function mergeThemeColors(baseColors: Theme['colors'], ...colorSets: Array<Partial<Theme['colors']>>): Theme['colors'];
236
+ /**
237
+ * Deep merge utility for complex theme objects
238
+ */
239
+ declare function deepMergeThemes(target: Theme, ...sources: Array<Partial<Theme>>): Theme;
240
+
241
+ export { type Theme, type ThemeColors, type ThemeConfig, type ThemeContextType, type ThemeContextValue, type ThemeMode, ThemeProvider, type ThemeProviderProps$1 as ThemeProviderProps, type ThemeRadius, ThemeSelector, type ThemeSpacing, ThemeToggle, type ThemeTransitions, type ThemeTypography, type ThemeVariables, type UseThemeOptions, applyTheme, createTheme, darkTheme, deepMergeThemes, ThemeProvider as default, defaultTheme, defaultThemes, lightTheme, mergeTheme, mergeThemeColors, mergeThemes, themes, useTheme, useThemeToggle };
@@ -0,0 +1,241 @@
1
+ import * as React$1 from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ type ThemeMode = 'light' | 'dark' | 'auto';
5
+ interface ThemeColors {
6
+ background: string;
7
+ backgroundSecondary: string;
8
+ backgroundTertiary: string;
9
+ text: string;
10
+ textSecondary: string;
11
+ textMuted: string;
12
+ border: string;
13
+ borderLight: string;
14
+ borderHover: string;
15
+ primary: string;
16
+ primaryHover: string;
17
+ primaryActive: string;
18
+ success: string;
19
+ warning: string;
20
+ error: string;
21
+ info: string;
22
+ hover: string;
23
+ active: string;
24
+ focus: string;
25
+ shadow: string;
26
+ shadowMd: string;
27
+ shadowLg: string;
28
+ }
29
+ interface ThemeSpacing {
30
+ xs: string;
31
+ sm: string;
32
+ md: string;
33
+ lg: string;
34
+ xl: string;
35
+ '2xl': string;
36
+ '3xl': string;
37
+ '4xl': string;
38
+ }
39
+ interface ThemeRadius {
40
+ none: string;
41
+ sm: string;
42
+ md: string;
43
+ lg: string;
44
+ xl: string;
45
+ '2xl': string;
46
+ full: string;
47
+ }
48
+ interface ThemeTypography {
49
+ fontFamily: {
50
+ sans: string;
51
+ serif: string;
52
+ mono: string;
53
+ };
54
+ fontSize: {
55
+ xs: string;
56
+ sm: string;
57
+ base: string;
58
+ lg: string;
59
+ xl: string;
60
+ '2xl': string;
61
+ '3xl': string;
62
+ '4xl': string;
63
+ '5xl': string;
64
+ };
65
+ fontWeight: {
66
+ light: string;
67
+ normal: string;
68
+ medium: string;
69
+ semibold: string;
70
+ bold: string;
71
+ };
72
+ lineHeight: {
73
+ tight: string;
74
+ normal: string;
75
+ relaxed: string;
76
+ };
77
+ }
78
+ interface ThemeTransitions {
79
+ fast: string;
80
+ normal: string;
81
+ slow: string;
82
+ bounce: string;
83
+ }
84
+ interface Theme {
85
+ name: string;
86
+ mode: ThemeMode;
87
+ colors: ThemeColors;
88
+ spacing: ThemeSpacing;
89
+ radius: ThemeRadius;
90
+ typography: ThemeTypography;
91
+ transitions: ThemeTransitions;
92
+ zIndex: {
93
+ dropdown: number;
94
+ modal: number;
95
+ tooltip: number;
96
+ overlay: number;
97
+ };
98
+ }
99
+ interface ThemeContextValue {
100
+ theme: Theme;
101
+ mode: ThemeMode;
102
+ setMode: (mode: ThemeMode) => void;
103
+ toggleMode: () => void;
104
+ isDark: boolean;
105
+ isLight: boolean;
106
+ isAuto: boolean;
107
+ systemPrefersDark: boolean;
108
+ applyTheme: (customTheme: Partial<Theme>) => void;
109
+ resetTheme: () => void;
110
+ }
111
+ interface ThemeProviderProps$1 {
112
+ children: React.ReactNode;
113
+ defaultMode?: ThemeMode;
114
+ customTheme?: Partial<Theme>;
115
+ storageKey?: string;
116
+ enableTransitions?: boolean;
117
+ className?: string;
118
+ style?: React.CSSProperties;
119
+ }
120
+ interface UseThemeOptions {
121
+ defaultMode?: ThemeMode;
122
+ storageKey?: string;
123
+ }
124
+ interface ThemeConfig {
125
+ defaultMode?: ThemeMode;
126
+ defaultTheme?: string;
127
+ persistMode?: boolean;
128
+ storageKey?: string;
129
+ enableTransitions?: boolean;
130
+ customThemes?: Record<string, Theme>;
131
+ }
132
+ interface ThemeVariables {
133
+ colors: Record<keyof ThemeColors, string>;
134
+ spacing: Record<keyof ThemeSpacing, string>;
135
+ radius: Record<keyof ThemeRadius, string>;
136
+ typography: {
137
+ fontFamily: Record<keyof ThemeTypography['fontFamily'], string>;
138
+ fontSize: Record<keyof ThemeTypography['fontSize'], string>;
139
+ fontWeight: Record<keyof ThemeTypography['fontWeight'], string>;
140
+ lineHeight: Record<keyof ThemeTypography['lineHeight'], string>;
141
+ };
142
+ transitions: Record<keyof ThemeTransitions, string>;
143
+ zIndex: Record<keyof Theme['zIndex'], string>;
144
+ }
145
+
146
+ declare const lightTheme: Theme;
147
+ declare const darkTheme: Theme;
148
+ declare const defaultTheme: Theme;
149
+ declare const themes: {
150
+ light: Theme;
151
+ dark: Theme;
152
+ };
153
+ declare const defaultThemes: {
154
+ default: Theme;
155
+ light: Theme;
156
+ dark: Theme;
157
+ };
158
+ declare function mergeTheme(baseTheme: Theme, customTheme: Partial<Theme>): Theme;
159
+
160
+ interface ThemeContextType {
161
+ currentTheme: Theme;
162
+ mode: ThemeMode;
163
+ setMode: (mode: ThemeMode) => void;
164
+ setTheme: (theme: Theme) => void;
165
+ themes: Record<string, Theme>;
166
+ toggleMode: () => void;
167
+ }
168
+ interface ThemeProviderProps {
169
+ children: ReactNode;
170
+ config?: ThemeConfig;
171
+ defaultMode?: ThemeMode;
172
+ defaultTheme?: string;
173
+ persistMode?: boolean;
174
+ storageKey?: string;
175
+ customThemes?: Record<string, Theme>;
176
+ }
177
+ declare const ThemeProvider: React$1.FC<ThemeProviderProps>;
178
+
179
+ /**
180
+ * Hook to access theme context
181
+ */
182
+ declare function useTheme(): ThemeContextType;
183
+
184
+ /**
185
+ * Hook that provides theme toggle functionality
186
+ */
187
+ declare function useThemeToggle(): {
188
+ mode: ThemeMode;
189
+ setMode: (mode: ThemeMode) => void;
190
+ toggleMode: () => void;
191
+ isDark: boolean;
192
+ isLight: boolean;
193
+ isAuto: boolean;
194
+ effectiveMode: "light" | "dark";
195
+ };
196
+
197
+ interface ThemeToggleProps {
198
+ className?: string;
199
+ style?: React$1.CSSProperties;
200
+ showLabels?: boolean;
201
+ size?: 'sm' | 'md' | 'lg';
202
+ }
203
+ declare const ThemeToggle: React$1.FC<ThemeToggleProps>;
204
+
205
+ interface ThemeSelectorProps {
206
+ className?: string;
207
+ style?: React$1.CSSProperties;
208
+ showLabels?: boolean;
209
+ options?: Array<{
210
+ mode: ThemeMode;
211
+ label: string;
212
+ icon?: string;
213
+ }>;
214
+ }
215
+ declare const ThemeSelector: React$1.FC<ThemeSelectorProps>;
216
+
217
+ /**
218
+ * Creates a new theme by merging a base theme with custom properties
219
+ */
220
+ declare function createTheme(baseTheme: Theme, customTheme: Partial<Theme>): Theme;
221
+
222
+ /**
223
+ * Applies theme CSS variables to the document root
224
+ */
225
+ declare function applyTheme(theme: Theme, mode: ThemeMode): void;
226
+
227
+ /**
228
+ * Merges multiple themes into a single theme
229
+ * Later themes in the array take precedence over earlier ones
230
+ */
231
+ declare function mergeThemes(...themes: Array<Theme | Partial<Theme>>): Theme;
232
+ /**
233
+ * Merges theme colors only
234
+ */
235
+ declare function mergeThemeColors(baseColors: Theme['colors'], ...colorSets: Array<Partial<Theme['colors']>>): Theme['colors'];
236
+ /**
237
+ * Deep merge utility for complex theme objects
238
+ */
239
+ declare function deepMergeThemes(target: Theme, ...sources: Array<Partial<Theme>>): Theme;
240
+
241
+ export { type Theme, type ThemeColors, type ThemeConfig, type ThemeContextType, type ThemeContextValue, type ThemeMode, ThemeProvider, type ThemeProviderProps$1 as ThemeProviderProps, type ThemeRadius, ThemeSelector, type ThemeSpacing, ThemeToggle, type ThemeTransitions, type ThemeTypography, type ThemeVariables, type UseThemeOptions, applyTheme, createTheme, darkTheme, deepMergeThemes, ThemeProvider as default, defaultTheme, defaultThemes, lightTheme, mergeTheme, mergeThemeColors, mergeThemes, themes, useTheme, useThemeToggle };
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ "use strict";var b=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var Q=Object.prototype.hasOwnProperty;var U=(e,t)=>{for(var a in t)b(e,a,{get:t[a],enumerable:!0})},Z=(e,t,a,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of G(t))!Q.call(e,o)&&o!==a&&b(e,o,{get:()=>t[o],enumerable:!(r=B(t,o))||r.enumerable});return e};var q=e=>Z(b({},"__esModule",{value:!0}),e);var te={};U(te,{ThemeProvider:()=>v,ThemeSelector:()=>I,ThemeToggle:()=>A,applyTheme:()=>f,createTheme:()=>H,darkTheme:()=>k,deepMergeThemes:()=>R,default:()=>v,defaultTheme:()=>X,defaultThemes:()=>w,lightTheme:()=>h,mergeTheme:()=>_,mergeThemeColors:()=>L,mergeThemes:()=>N,themes:()=>Y,useTheme:()=>c,useThemeToggle:()=>E});module.exports=q(te);var J={background:"#ffffff",backgroundSecondary:"#f8fafc",backgroundTertiary:"#f1f5f9",text:"#0f172a",textSecondary:"#475569",textMuted:"#64748b",border:"#e2e8f0",borderLight:"#f1f5f9",borderHover:"#cbd5e1",primary:"#3b82f6",primaryHover:"#2563eb",primaryActive:"#1d4ed8",success:"#10b981",warning:"#f59e0b",error:"#ef4444",info:"#06b6d4",hover:"#f8fafc",active:"#f1f5f9",focus:"rgba(59, 130, 246, 0.1)",shadow:"0 1px 2px 0 rgba(0, 0, 0, 0.05)",shadowMd:"0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",shadowLg:"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)"},K={background:"#0f172a",backgroundSecondary:"#1e293b",backgroundTertiary:"#334155",text:"#f8fafc",textSecondary:"#cbd5e1",textMuted:"#94a3b8",border:"#334155",borderLight:"#475569",borderHover:"#64748b",primary:"#60a5fa",primaryHover:"#3b82f6",primaryActive:"#2563eb",success:"#34d399",warning:"#fbbf24",error:"#f87171",info:"#22d3ee",hover:"#1e293b",active:"#334155",focus:"rgba(96, 165, 250, 0.1)",shadow:"0 1px 2px 0 rgba(0, 0, 0, 0.3)",shadowMd:"0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3)",shadowLg:"0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3)"},S={spacing:{xs:"0.25rem",sm:"0.5rem",md:"0.75rem",lg:"1rem",xl:"1.25rem","2xl":"1.5rem","3xl":"2rem","4xl":"3rem"},radius:{none:"0",sm:"0.25rem",md:"0.375rem",lg:"0.5rem",xl:"0.75rem","2xl":"1rem",full:"9999px"},typography:{fontFamily:{sans:'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif',serif:'ui-serif, Georgia, Cambria, "Times New Roman", Times, serif',mono:'ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace'},fontSize:{xs:"0.75rem",sm:"0.875rem",base:"1rem",lg:"1.125rem",xl:"1.25rem","2xl":"1.5rem","3xl":"1.875rem","4xl":"2.25rem","5xl":"3rem"},fontWeight:{light:"300",normal:"400",medium:"500",semibold:"600",bold:"700"},lineHeight:{tight:"1.25",normal:"1.5",relaxed:"1.75"}},transitions:{fast:"all 0.1s ease",normal:"all 0.2s ease",slow:"all 0.3s ease",bounce:"all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)"},zIndex:{dropdown:1e3,modal:1050,tooltip:1100,overlay:1200}},h={name:"light",mode:"light",colors:J,...S},k={name:"dark",mode:"dark",colors:K,...S},X=h,Y={light:h,dark:k},w={default:h,light:h,dark:k};function _(e,t){return{...e,...t,colors:{...e.colors,...t.colors},spacing:{...e.spacing,...t.spacing},radius:{...e.radius,...t.radius},typography:{...e.typography,...t.typography,fontFamily:{...e.typography.fontFamily,...t.typography?.fontFamily},fontSize:{...e.typography.fontSize,...t.typography?.fontSize},fontWeight:{...e.typography.fontWeight,...t.typography?.fontWeight},lineHeight:{...e.typography.lineHeight,...t.typography?.lineHeight}},transitions:{...e.transitions,...t.transitions},zIndex:{...e.zIndex,...t.zIndex}}}var d=require("react");function f(e,t){if(typeof document>"u")return;let a=document.documentElement,r=t;t==="auto"&&(r=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),a.setAttribute("data-theme",e.name),a.setAttribute("data-theme-mode",r),Object.entries(e.colors).forEach(([o,n])=>{a.style.setProperty(`--theme-color-${P(o)}`,n)}),Object.entries(e.spacing).forEach(([o,n])=>{a.style.setProperty(`--theme-spacing-${o}`,n)}),Object.entries(e.radius).forEach(([o,n])=>{a.style.setProperty(`--theme-radius-${o}`,n)}),Object.entries(e.typography.fontFamily).forEach(([o,n])=>{a.style.setProperty(`--theme-font-family-${o}`,n)}),Object.entries(e.typography.fontSize).forEach(([o,n])=>{a.style.setProperty(`--theme-font-size-${o}`,n)}),Object.entries(e.typography.fontWeight).forEach(([o,n])=>{a.style.setProperty(`--theme-font-weight-${o}`,n)}),Object.entries(e.typography.lineHeight).forEach(([o,n])=>{a.style.setProperty(`--theme-line-height-${o}`,n)}),Object.entries(e.transitions).forEach(([o,n])=>{a.style.setProperty(`--theme-transition-${o}`,n)}),Object.entries(e.zIndex).forEach(([o,n])=>{a.style.setProperty(`--theme-z-index-${P(o)}`,n.toString())}),document.body.className=document.body.className.replace(/theme-\w+/g,""),document.body.classList.add(`theme-${e.name}`,`theme-${r}`)}function P(e){return e.replace(/[A-Z]/g,t=>`-${t.toLowerCase()}`)}var $=require("react/jsx-runtime"),z=(0,d.createContext)(void 0),v=({children:e,defaultMode:t="auto",defaultTheme:a="default",persistMode:r=!0,storageKey:o="asafarim-theme-mode",customThemes:n={}})=>{let l={...w,...n},i=()=>{if(!r||typeof window>"u")return t;try{let s=localStorage.getItem(o);if(s&&["light","dark","auto"].includes(s))return s}catch(s){console.warn("Failed to read theme mode from localStorage:",s)}return t},[m,p]=(0,d.useState)(i),[y,W]=(0,d.useState)(a),j=()=>m==="auto"?typeof window<"u"&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":m,C=()=>{let s=j();return y!=="default"&&y in l?l[y]:s==="dark"?l.dark:l.light},x=C(),T=s=>{if(p(s),r&&typeof window<"u")try{localStorage.setItem(o,s)}catch(u){console.warn("Failed to save theme mode to localStorage:",u)}},O=()=>{if(m==="auto"){let s=window.matchMedia("(prefers-color-scheme: dark)").matches;T(s?"light":"dark")}else T(m==="light"?"dark":"light")},D=s=>{W(s.name)};(0,d.useEffect)(()=>{f(x,m)},[x,m,y]),(0,d.useEffect)(()=>{if(m!=="auto")return;let s=window.matchMedia("(prefers-color-scheme: dark)"),u=()=>{f(C(),m)};return s.addEventListener("change",u),()=>s.removeEventListener("change",u)},[m]);let V={currentTheme:x,mode:m,setMode:T,setTheme:D,themes:l,toggleMode:O};return(0,$.jsx)(z.Provider,{value:V,children:e})},F=()=>{let e=(0,d.useContext)(z);if(e===void 0)throw new Error("useThemeContext must be used within a ThemeProvider");return e};function c(){return F()}function E(){let{mode:e,setMode:t,toggleMode:a}=c(),o=e==="auto"?typeof window<"u"&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":e;return{mode:e,setMode:t,toggleMode:a,isDark:o==="dark",isLight:o==="light",isAuto:e==="auto",effectiveMode:o}}var g=require("react/jsx-runtime"),A=({className:e="",style:t={},showLabels:a=!1,size:r="md"})=>{let{mode:o,toggleMode:n}=c(),i=`
2
+ ${{sm:"w-8 h-8 text-sm",md:"w-10 h-10 text-base",lg:"w-12 h-12 text-lg"}[r]}
3
+ inline-flex items-center justify-center
4
+ rounded-md border border-gray-300
5
+ bg-white hover:bg-gray-50
6
+ dark:bg-gray-800 dark:border-gray-600 dark:hover:bg-gray-700
7
+ focus:outline-none focus:ring-2 focus:ring-blue-500
8
+ transition-all duration-200
9
+ ${e}
10
+ `.trim(),m=()=>{switch(o){case"light":return"\u2600\uFE0F";case"dark":return"\u{1F319}";case"auto":default:return"\u{1F313}"}},p=()=>{switch(o){case"light":return"Light";case"dark":return"Dark";case"auto":default:return"Auto"}};return(0,g.jsxs)("button",{onClick:n,className:i,style:t,title:`Current theme: ${p()}. Click to toggle.`,"aria-label":`Switch theme. Current: ${p()}`,children:[(0,g.jsx)("span",{role:"img","aria-hidden":"true",children:m()}),a&&(0,g.jsx)("span",{className:"ml-2 text-sm font-medium",children:p()})]})};var M=require("react/jsx-runtime"),I=({className:e="",style:t={},showLabels:a=!0,options:r=[{mode:"light",label:"Light",icon:"\u2600\uFE0F"},{mode:"dark",label:"Dark",icon:"\u{1F319}"},{mode:"auto",label:"Auto",icon:"\u{1F313}"}]})=>{let{mode:o,setMode:n}=c(),l=`
11
+ px-3 py-2 border border-gray-300 rounded-md
12
+ bg-white dark:bg-gray-800 dark:border-gray-600
13
+ text-gray-900 dark:text-gray-100
14
+ focus:outline-none focus:ring-2 focus:ring-blue-500
15
+ transition-all duration-200
16
+ ${e}
17
+ `.trim();return(0,M.jsx)("select",{value:o,onChange:i=>n(i.target.value),className:l,style:t,"aria-label":"Select theme mode",children:r.map(i=>(0,M.jsx)("option",{value:i.mode,children:a?`${i.icon?i.icon+" ":""}${i.label}`:i.icon||i.label},i.mode))})};function H(e,t){return{...e,...t,name:t.name||`${e.name}-custom`,colors:{...e.colors,...t.colors},spacing:{...e.spacing,...t.spacing},radius:{...e.radius,...t.radius},typography:{...e.typography,...t.typography,fontFamily:{...e.typography.fontFamily,...t.typography?.fontFamily},fontSize:{...e.typography.fontSize,...t.typography?.fontSize},fontWeight:{...e.typography.fontWeight,...t.typography?.fontWeight},lineHeight:{...e.typography.lineHeight,...t.typography?.lineHeight}},transitions:{...e.transitions,...t.transitions},zIndex:{...e.zIndex,...t.zIndex}}}function N(...e){if(e.length===0)throw new Error("At least one theme must be provided to mergeThemes");let[t,...a]=e;if(!ee(t))throw new Error("First theme must be a complete theme object");return a.reduce((r,o)=>({...r,...o,name:o.name||r.name,mode:o.mode||r.mode,colors:{...r.colors,...o.colors},spacing:{...r.spacing,...o.spacing},radius:{...r.radius,...o.radius},typography:{...r.typography,...o.typography,fontFamily:{...r.typography.fontFamily,...o.typography?.fontFamily},fontSize:{...r.typography.fontSize,...o.typography?.fontSize},fontWeight:{...r.typography.fontWeight,...o.typography?.fontWeight},lineHeight:{...r.typography.lineHeight,...o.typography?.lineHeight}},transitions:{...r.transitions,...o.transitions},zIndex:{...r.zIndex,...o.zIndex}}),t)}function ee(e){return!!(e&&typeof e=="object"&&"name"in e&&"mode"in e&&"colors"in e&&"spacing"in e&&"radius"in e&&"typography"in e&&"transitions"in e&&"zIndex"in e)}function L(e,...t){return t.reduce((a,r)=>({...a,...r}),e)}function R(e,...t){return t.reduce((a,r)=>{let o={...a};for(let n in r){let l=r[n],i=a[n];l&&typeof l=="object"&&!Array.isArray(l)&&i&&typeof i=="object"?o[n]={...i,...l}:l!==void 0&&(o[n]=l)}return o},e)}0&&(module.exports={ThemeProvider,ThemeSelector,ThemeToggle,applyTheme,createTheme,darkTheme,deepMergeThemes,defaultTheme,defaultThemes,lightTheme,mergeTheme,mergeThemeColors,mergeThemes,themes,useTheme,useThemeToggle});
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/themes.ts","../src/components/ThemeProvider.tsx","../src/utils/applyTheme.ts","../src/hooks/useTheme.ts","../src/hooks/useThemeToggle.ts","../src/components/ThemeToggle.tsx","../src/components/ThemeSelector.tsx","../src/utils/createTheme.ts","../src/utils/mergeThemes.ts"],"sourcesContent":["// @asafarim/react-themes - A comprehensive theme management system for React apps\r\n// Export all types and interfaces\r\nexport * from './types';\r\n\r\n// Export all themes and utilities\r\nexport * from './themes';\r\n\r\n// Export main components and hooks\r\nexport { ThemeProvider } from './components/ThemeProvider';\r\nexport type { ThemeContextType } from './components/ThemeProvider';\r\nexport { useTheme } from './hooks/useTheme';\r\nexport { useThemeToggle } from './hooks/useThemeToggle';\r\nexport { ThemeToggle } from './components/ThemeToggle';\r\nexport { ThemeSelector } from './components/ThemeSelector';\r\n\r\n// Export theme utilities\r\nexport { createTheme } from './utils/createTheme';\r\nexport { applyTheme } from './utils/applyTheme';\r\nexport { mergeThemes, mergeThemeColors, deepMergeThemes } from './utils/mergeThemes';\r\n\r\n// Default export for convenience\r\nexport { ThemeProvider as default } from './components/ThemeProvider';\r\n","import type { Theme, ThemeColors } from './types';\r\n\r\n// Light theme colors\r\nconst lightColors: ThemeColors = {\r\n // Background colors\r\n background: '#ffffff',\r\n backgroundSecondary: '#f8fafc',\r\n backgroundTertiary: '#f1f5f9',\r\n \r\n // Text colors\r\n text: '#0f172a',\r\n textSecondary: '#475569',\r\n textMuted: '#64748b',\r\n \r\n // Border colors\r\n border: '#e2e8f0',\r\n borderLight: '#f1f5f9',\r\n borderHover: '#cbd5e1',\r\n \r\n // Accent colors\r\n primary: '#3b82f6',\r\n primaryHover: '#2563eb',\r\n primaryActive: '#1d4ed8',\r\n \r\n // Status colors\r\n success: '#10b981',\r\n warning: '#f59e0b',\r\n error: '#ef4444',\r\n info: '#06b6d4',\r\n \r\n // Interactive states\r\n hover: '#f8fafc',\r\n active: '#f1f5f9',\r\n focus: 'rgba(59, 130, 246, 0.1)',\r\n \r\n // Shadows\r\n shadow: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',\r\n shadowMd: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',\r\n shadowLg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',\r\n};\r\n\r\n// Dark theme colors\r\nconst darkColors: ThemeColors = {\r\n // Background colors\r\n background: '#0f172a',\r\n backgroundSecondary: '#1e293b',\r\n backgroundTertiary: '#334155',\r\n \r\n // Text colors\r\n text: '#f8fafc',\r\n textSecondary: '#cbd5e1',\r\n textMuted: '#94a3b8',\r\n \r\n // Border colors\r\n border: '#334155',\r\n borderLight: '#475569',\r\n borderHover: '#64748b',\r\n \r\n // Accent colors\r\n primary: '#60a5fa',\r\n primaryHover: '#3b82f6',\r\n primaryActive: '#2563eb',\r\n \r\n // Status colors\r\n success: '#34d399',\r\n warning: '#fbbf24',\r\n error: '#f87171',\r\n info: '#22d3ee',\r\n \r\n // Interactive states\r\n hover: '#1e293b',\r\n active: '#334155',\r\n focus: 'rgba(96, 165, 250, 0.1)',\r\n \r\n // Shadows\r\n shadow: '0 1px 2px 0 rgba(0, 0, 0, 0.3)',\r\n shadowMd: '0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3)',\r\n shadowLg: '0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3)',\r\n};\r\n\r\n// Base theme structure\r\nconst baseTheme = {\r\n spacing: {\r\n xs: '0.25rem',\r\n sm: '0.5rem',\r\n md: '0.75rem',\r\n lg: '1rem',\r\n xl: '1.25rem',\r\n '2xl': '1.5rem',\r\n '3xl': '2rem',\r\n '4xl': '3rem',\r\n },\r\n radius: {\r\n none: '0',\r\n sm: '0.25rem',\r\n md: '0.375rem',\r\n lg: '0.5rem',\r\n xl: '0.75rem',\r\n '2xl': '1rem',\r\n full: '9999px',\r\n },\r\n typography: {\r\n fontFamily: {\r\n sans: 'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif',\r\n serif: 'ui-serif, Georgia, Cambria, \"Times New Roman\", Times, serif',\r\n mono: 'ui-monospace, SFMono-Regular, \"SF Mono\", Consolas, \"Liberation Mono\", Menlo, monospace',\r\n },\r\n fontSize: {\r\n xs: '0.75rem',\r\n sm: '0.875rem',\r\n base: '1rem',\r\n lg: '1.125rem',\r\n xl: '1.25rem',\r\n '2xl': '1.5rem',\r\n '3xl': '1.875rem',\r\n '4xl': '2.25rem',\r\n '5xl': '3rem',\r\n },\r\n fontWeight: {\r\n light: '300',\r\n normal: '400',\r\n medium: '500',\r\n semibold: '600',\r\n bold: '700',\r\n },\r\n lineHeight: {\r\n tight: '1.25',\r\n normal: '1.5',\r\n relaxed: '1.75',\r\n },\r\n },\r\n transitions: {\r\n fast: 'all 0.1s ease',\r\n normal: 'all 0.2s ease',\r\n slow: 'all 0.3s ease',\r\n bounce: 'all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)',\r\n },\r\n zIndex: {\r\n dropdown: 1000,\r\n modal: 1050,\r\n tooltip: 1100,\r\n overlay: 1200,\r\n },\r\n};\r\n\r\n// Light theme\r\nexport const lightTheme: Theme = {\r\n name: 'light',\r\n mode: 'light',\r\n colors: lightColors,\r\n ...baseTheme,\r\n};\r\n\r\n// Dark theme\r\nexport const darkTheme: Theme = {\r\n name: 'dark',\r\n mode: 'dark',\r\n colors: darkColors,\r\n ...baseTheme,\r\n};\r\n\r\n// Default theme (light)\r\nexport const defaultTheme = lightTheme;\r\n\r\n// Theme presets\r\nexport const themes = {\r\n light: lightTheme,\r\n dark: darkTheme,\r\n};\r\n\r\n// Default themes for the provider\r\nexport const defaultThemes = {\r\n default: lightTheme,\r\n light: lightTheme,\r\n dark: darkTheme,\r\n};\r\n\r\n// Helper function to merge themes\r\nexport function mergeTheme(baseTheme: Theme, customTheme: Partial<Theme>): Theme {\r\n return {\r\n ...baseTheme,\r\n ...customTheme,\r\n colors: {\r\n ...baseTheme.colors,\r\n ...customTheme.colors,\r\n },\r\n spacing: {\r\n ...baseTheme.spacing,\r\n ...customTheme.spacing,\r\n },\r\n radius: {\r\n ...baseTheme.radius,\r\n ...customTheme.radius,\r\n },\r\n typography: {\r\n ...baseTheme.typography,\r\n ...customTheme.typography,\r\n fontFamily: {\r\n ...baseTheme.typography.fontFamily,\r\n ...customTheme.typography?.fontFamily,\r\n },\r\n fontSize: {\r\n ...baseTheme.typography.fontSize,\r\n ...customTheme.typography?.fontSize,\r\n },\r\n fontWeight: {\r\n ...baseTheme.typography.fontWeight,\r\n ...customTheme.typography?.fontWeight,\r\n },\r\n lineHeight: {\r\n ...baseTheme.typography.lineHeight,\r\n ...customTheme.typography?.lineHeight,\r\n },\r\n },\r\n transitions: {\r\n ...baseTheme.transitions,\r\n ...customTheme.transitions,\r\n },\r\n zIndex: {\r\n ...baseTheme.zIndex,\r\n ...customTheme.zIndex,\r\n },\r\n };\r\n}\r\n","import * as React from 'react';\r\nimport { createContext, useContext, useEffect, useState, ReactNode } from 'react';\r\nimport { Theme, ThemeConfig, ThemeMode } from '../types';\r\nimport { defaultThemes } from '../themes';\r\nimport { applyTheme } from '../utils/applyTheme';\r\n\r\nexport interface ThemeContextType {\r\n currentTheme: Theme;\r\n mode: ThemeMode;\r\n setMode: (mode: ThemeMode) => void;\r\n setTheme: (theme: Theme) => void;\r\n themes: Record<string, Theme>;\r\n toggleMode: () => void;\r\n}\r\n\r\nconst ThemeContext = createContext<ThemeContextType | undefined>(undefined);\r\n\r\nexport interface ThemeProviderProps {\r\n children: ReactNode;\r\n config?: ThemeConfig;\r\n defaultMode?: ThemeMode;\r\n defaultTheme?: string;\r\n persistMode?: boolean;\r\n storageKey?: string;\r\n customThemes?: Record<string, Theme>;\r\n}\r\n\r\nexport const ThemeProvider: React.FC<ThemeProviderProps> = ({\r\n children,\r\n defaultMode = 'auto',\r\n defaultTheme = 'default',\r\n persistMode = true,\r\n storageKey = 'asafarim-theme-mode',\r\n customThemes = {},\r\n}) => {\r\n const allThemes = { ...defaultThemes, ...customThemes };\r\n \r\n // Get initial mode from localStorage or use default\r\n const getInitialMode = (): ThemeMode => {\r\n if (!persistMode || typeof window === 'undefined') return defaultMode;\r\n \r\n try {\r\n const stored = localStorage.getItem(storageKey);\r\n if (stored && ['light', 'dark', 'auto'].includes(stored)) {\r\n return stored as ThemeMode;\r\n }\r\n } catch (error) {\r\n console.warn('Failed to read theme mode from localStorage:', error);\r\n }\r\n \r\n return defaultMode;\r\n };\r\n const [mode, setModeState] = useState<ThemeMode>(getInitialMode);\r\n const [currentThemeName, setCurrentThemeName] = useState<string>(defaultTheme);\r\n\r\n // Get the effective mode (resolving 'auto' to actual light/dark)\r\n const getEffectiveMode = (): 'light' | 'dark' => {\r\n if (mode === 'auto') {\r\n if (typeof window !== 'undefined') {\r\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\r\n }\r\n return 'light'; // fallback for SSR\r\n }\r\n return mode;\r\n };\r\n // Get the current theme based on mode and theme name\r\n const getCurrentTheme = (): Theme => {\r\n const effectiveMode = getEffectiveMode();\r\n \r\n // If user selected a specific theme, use it\r\n if (currentThemeName !== 'default' && currentThemeName in allThemes) {\r\n return allThemes[currentThemeName as keyof typeof allThemes];\r\n }\r\n \r\n // Otherwise use the theme that matches the effective mode\r\n return effectiveMode === 'dark' ? allThemes.dark : allThemes.light;\r\n };\r\n\r\n const currentTheme = getCurrentTheme();\r\n\r\n // Update mode and persist if enabled\r\n const setMode = (newMode: ThemeMode) => {\r\n setModeState(newMode);\r\n \r\n if (persistMode && typeof window !== 'undefined') {\r\n try {\r\n localStorage.setItem(storageKey, newMode);\r\n } catch (error) {\r\n console.warn('Failed to save theme mode to localStorage:', error);\r\n }\r\n }\r\n };\r\n\r\n // Toggle between light and dark modes\r\n const toggleMode = () => {\r\n if (mode === 'auto') {\r\n // If auto, switch to opposite of system preference\r\n const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches;\r\n setMode(systemDark ? 'light' : 'dark');\r\n } else {\r\n setMode(mode === 'light' ? 'dark' : 'light');\r\n }\r\n };\r\n // Set theme by name\r\n const setTheme = (theme: Theme) => {\r\n setCurrentThemeName(theme.name);\r\n };\r\n // Apply theme to document\r\n useEffect(() => {\r\n applyTheme(currentTheme, mode);\r\n }, [currentTheme, mode, currentThemeName]); // Add currentThemeName as dependency\r\n\r\n // Listen for system theme changes when in auto mode\r\n useEffect(() => {\r\n if (mode !== 'auto') return;\r\n\r\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\r\n const handleChange = () => {\r\n // Force re-render when system preference changes\r\n applyTheme(getCurrentTheme(), mode);\r\n };\r\n\r\n mediaQuery.addEventListener('change', handleChange);\r\n return () => mediaQuery.removeEventListener('change', handleChange);\r\n }, [mode]);\r\n\r\n const contextValue: ThemeContextType = {\r\n currentTheme,\r\n mode,\r\n setMode,\r\n setTheme,\r\n themes: allThemes,\r\n toggleMode,\r\n };\r\n\r\n return (\r\n <ThemeContext.Provider value={contextValue}>\r\n {children}\r\n </ThemeContext.Provider>\r\n );\r\n};\r\n\r\nexport const useThemeContext = () => {\r\n const context = useContext(ThemeContext);\r\n if (context === undefined) {\r\n throw new Error('useThemeContext must be used within a ThemeProvider');\r\n }\r\n return context;\r\n};\r\n","import { Theme, ThemeMode } from '../types';\r\n\r\n/**\r\n * Applies theme CSS variables to the document root\r\n */\r\nexport function applyTheme(theme: Theme, mode: ThemeMode): void {\r\n if (typeof document === 'undefined') return;\r\n\r\n const root = document.documentElement;\r\n \r\n // Determine the effective mode\r\n let effectiveMode = mode;\r\n if (mode === 'auto') {\r\n effectiveMode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\r\n }\r\n\r\n // Set data attributes for CSS targeting\r\n root.setAttribute('data-theme', theme.name);\r\n root.setAttribute('data-theme-mode', effectiveMode);\r\n\r\n // Apply color variables\r\n Object.entries(theme.colors).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-color-${kebabCase(key)}`, value);\r\n });\r\n\r\n // Apply spacing variables\r\n Object.entries(theme.spacing).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-spacing-${key}`, value);\r\n });\r\n\r\n // Apply radius variables\r\n Object.entries(theme.radius).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-radius-${key}`, value);\r\n });\r\n\r\n // Apply typography variables\r\n Object.entries(theme.typography.fontFamily).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-font-family-${key}`, value);\r\n });\r\n\r\n Object.entries(theme.typography.fontSize).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-font-size-${key}`, value);\r\n });\r\n\r\n Object.entries(theme.typography.fontWeight).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-font-weight-${key}`, value);\r\n });\r\n\r\n Object.entries(theme.typography.lineHeight).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-line-height-${key}`, value);\r\n });\r\n\r\n // Apply transition variables\r\n Object.entries(theme.transitions).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-transition-${key}`, value);\r\n });\r\n\r\n // Apply z-index variables\r\n Object.entries(theme.zIndex).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-z-index-${kebabCase(key)}`, value.toString());\r\n });\r\n\r\n // Add theme class to body for additional styling\r\n document.body.className = document.body.className.replace(/theme-\\w+/g, '');\r\n document.body.classList.add(`theme-${theme.name}`, `theme-${effectiveMode}`);\r\n}\r\n\r\n/**\r\n * Removes all theme-related CSS variables and classes\r\n */\r\nexport function removeTheme(): void {\r\n if (typeof document === 'undefined') return;\r\n\r\n const root = document.documentElement;\r\n \r\n // Remove data attributes\r\n root.removeAttribute('data-theme');\r\n root.removeAttribute('data-theme-mode');\r\n\r\n // Remove CSS variables (this is a simplified approach - in production you might want to track which variables were set)\r\n const styles = root.style;\r\n for (let i = styles.length - 1; i >= 0; i--) {\r\n const property = styles[i];\r\n if (property.startsWith('--theme-')) {\r\n root.style.removeProperty(property);\r\n }\r\n }\r\n\r\n // Remove theme classes from body\r\n document.body.className = document.body.className.replace(/theme-\\w+/g, '');\r\n}\r\n\r\n/**\r\n * Converts camelCase to kebab-case\r\n */\r\nfunction kebabCase(str: string): string {\r\n return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);\r\n}\r\n","import { useThemeContext, ThemeContextType } from '../components/ThemeProvider';\r\n\r\n/**\r\n * Hook to access theme context\r\n */\r\nexport function useTheme(): ThemeContextType {\r\n return useThemeContext();\r\n}\r\n","import { useTheme } from './useTheme';\r\n\r\n/**\r\n * Hook that provides theme toggle functionality\r\n */\r\nexport function useThemeToggle() {\r\n const { mode, setMode, toggleMode } = useTheme();\r\n \r\n // Get effective mode (resolving 'auto' to actual light/dark)\r\n const getEffectiveMode = (): 'light' | 'dark' => {\r\n if (mode === 'auto') {\r\n if (typeof window !== 'undefined') {\r\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\r\n }\r\n return 'light'; // fallback for SSR\r\n }\r\n return mode;\r\n };\r\n\r\n const effectiveMode = getEffectiveMode();\r\n \r\n return {\r\n mode,\r\n setMode,\r\n toggleMode,\r\n isDark: effectiveMode === 'dark',\r\n isLight: effectiveMode === 'light',\r\n isAuto: mode === 'auto',\r\n effectiveMode, // Expose the resolved mode\r\n };\r\n}\r\n","import * as React from 'react';\r\nimport { useTheme } from '../hooks/useTheme';\r\n\r\nexport interface ThemeToggleProps {\r\n className?: string;\r\n style?: React.CSSProperties;\r\n showLabels?: boolean;\r\n size?: 'sm' | 'md' | 'lg';\r\n}\r\n\r\nexport const ThemeToggle: React.FC<ThemeToggleProps> = ({\r\n className = '',\r\n style = {},\r\n showLabels = false,\r\n size = 'md',\r\n}) => {\r\n const { mode, toggleMode } = useTheme();\r\n\r\n const sizeClasses = {\r\n sm: 'w-8 h-8 text-sm',\r\n md: 'w-10 h-10 text-base',\r\n lg: 'w-12 h-12 text-lg',\r\n };\r\n\r\n const buttonClass = `\r\n ${sizeClasses[size]}\r\n inline-flex items-center justify-center\r\n rounded-md border border-gray-300\r\n bg-white hover:bg-gray-50\r\n dark:bg-gray-800 dark:border-gray-600 dark:hover:bg-gray-700\r\n focus:outline-none focus:ring-2 focus:ring-blue-500\r\n transition-all duration-200\r\n ${className}\r\n `.trim();\r\n\r\n const getIcon = () => {\r\n switch (mode) {\r\n case 'light':\r\n return '☀️';\r\n case 'dark':\r\n return '🌙';\r\n case 'auto':\r\n default:\r\n return '🌓';\r\n }\r\n };\r\n\r\n const getLabel = () => {\r\n switch (mode) {\r\n case 'light':\r\n return 'Light';\r\n case 'dark':\r\n return 'Dark';\r\n case 'auto':\r\n default:\r\n return 'Auto';\r\n }\r\n };\r\n\r\n return (\r\n <button\r\n onClick={toggleMode}\r\n className={buttonClass}\r\n style={style}\r\n title={`Current theme: ${getLabel()}. Click to toggle.`}\r\n aria-label={`Switch theme. Current: ${getLabel()}`}\r\n >\r\n <span role=\"img\" aria-hidden=\"true\">\r\n {getIcon()}\r\n </span>\r\n {showLabels && (\r\n <span className=\"ml-2 text-sm font-medium\">\r\n {getLabel()}\r\n </span>\r\n )}\r\n </button>\r\n );\r\n};\r\n","import * as React from \"react\";\r\nimport { useTheme } from \"../hooks/useTheme\";\r\nimport { ThemeMode } from \"../types\";\r\n\r\nexport interface ThemeSelectorProps {\r\n className?: string;\r\n style?: React.CSSProperties;\r\n showLabels?: boolean;\r\n options?: Array<{\r\n mode: ThemeMode;\r\n label: string;\r\n icon?: string;\r\n }>;\r\n}\r\n\r\nexport const ThemeSelector: React.FC<ThemeSelectorProps> = ({\r\n className = \"\",\r\n style = {},\r\n showLabels = true,\r\n options = [\r\n { mode: \"light\", label: \"Light\", icon: \"☀️\" },\r\n { mode: \"dark\", label: \"Dark\", icon: \"🌙\" },\r\n { mode: \"auto\", label: \"Auto\", icon: \"🌓\" },\r\n ],\r\n}) => {\r\n const { mode, setMode } = useTheme();\r\n\r\n const selectClass = `\r\n px-3 py-2 border border-gray-300 rounded-md\r\n bg-white dark:bg-gray-800 dark:border-gray-600\r\n text-gray-900 dark:text-gray-100\r\n focus:outline-none focus:ring-2 focus:ring-blue-500\r\n transition-all duration-200\r\n ${className}\r\n `.trim();\r\n\r\n return (\r\n <select\r\n value={mode}\r\n onChange={(e) => setMode(e.target.value as ThemeMode)}\r\n className={selectClass}\r\n style={style}\r\n aria-label=\"Select theme mode\"\r\n >\r\n {options.map((option) => (\r\n <option key={option.mode} value={option.mode}>\r\n {showLabels\r\n ? `${option.icon ? option.icon + \" \" : \"\"}${option.label}`\r\n : option.icon || option.label}\r\n </option>\r\n ))}\r\n </select>\r\n );\r\n};\r\n","import { Theme } from '../types';\r\n\r\n/**\r\n * Creates a new theme by merging a base theme with custom properties\r\n */\r\nexport function createTheme(\r\n baseTheme: Theme,\r\n customTheme: Partial<Theme>\r\n): Theme {\r\n return {\r\n ...baseTheme,\r\n ...customTheme,\r\n name: customTheme.name || `${baseTheme.name}-custom`,\r\n colors: {\r\n ...baseTheme.colors,\r\n ...customTheme.colors,\r\n },\r\n spacing: {\r\n ...baseTheme.spacing,\r\n ...customTheme.spacing,\r\n },\r\n radius: {\r\n ...baseTheme.radius,\r\n ...customTheme.radius,\r\n },\r\n typography: {\r\n ...baseTheme.typography,\r\n ...customTheme.typography,\r\n fontFamily: {\r\n ...baseTheme.typography.fontFamily,\r\n ...customTheme.typography?.fontFamily,\r\n },\r\n fontSize: {\r\n ...baseTheme.typography.fontSize,\r\n ...customTheme.typography?.fontSize,\r\n },\r\n fontWeight: {\r\n ...baseTheme.typography.fontWeight,\r\n ...customTheme.typography?.fontWeight,\r\n },\r\n lineHeight: {\r\n ...baseTheme.typography.lineHeight,\r\n ...customTheme.typography?.lineHeight,\r\n },\r\n },\r\n transitions: {\r\n ...baseTheme.transitions,\r\n ...customTheme.transitions,\r\n },\r\n zIndex: {\r\n ...baseTheme.zIndex,\r\n ...customTheme.zIndex,\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Creates a theme variant with modified colors\r\n */\r\nexport function createThemeVariant(\r\n baseTheme: Theme,\r\n colorOverrides: Partial<Theme['colors']>,\r\n name?: string\r\n): Theme {\r\n return createTheme(baseTheme, {\r\n name: name || `${baseTheme.name}-variant`,\r\n colors: {\r\n ...baseTheme.colors,\r\n ...colorOverrides,\r\n },\r\n });\r\n}\r\n","import { Theme } from '../types';\r\n\r\n/**\r\n * Merges multiple themes into a single theme\r\n * Later themes in the array take precedence over earlier ones\r\n */\r\nexport function mergeThemes(...themes: Array<Theme | Partial<Theme>>): Theme {\r\n if (themes.length === 0) {\r\n throw new Error('At least one theme must be provided to mergeThemes');\r\n }\r\n\r\n const [baseTheme, ...additionalThemes] = themes;\r\n \r\n if (!isFullTheme(baseTheme)) {\r\n throw new Error('First theme must be a complete theme object');\r\n }\r\n return additionalThemes.reduce((merged: Theme, theme): Theme => {\r\n return {\r\n ...merged,\r\n ...theme,\r\n name: theme.name || merged.name,\r\n mode: theme.mode || merged.mode,\r\n colors: {\r\n ...merged.colors,\r\n ...theme.colors,\r\n },\r\n spacing: {\r\n ...merged.spacing,\r\n ...theme.spacing,\r\n },\r\n radius: {\r\n ...merged.radius,\r\n ...theme.radius,\r\n },\r\n typography: {\r\n ...merged.typography,\r\n ...theme.typography,\r\n fontFamily: {\r\n ...merged.typography.fontFamily,\r\n ...theme.typography?.fontFamily,\r\n },\r\n fontSize: {\r\n ...merged.typography.fontSize,\r\n ...theme.typography?.fontSize,\r\n },\r\n fontWeight: {\r\n ...merged.typography.fontWeight,\r\n ...theme.typography?.fontWeight,\r\n },\r\n lineHeight: {\r\n ...merged.typography.lineHeight,\r\n ...theme.typography?.lineHeight,\r\n },\r\n },\r\n transitions: {\r\n ...merged.transitions,\r\n ...theme.transitions,\r\n },\r\n zIndex: {\r\n ...merged.zIndex,\r\n ...theme.zIndex,\r\n },\r\n };\r\n }, baseTheme);\r\n}\r\n\r\n/**\r\n * Type guard to check if an object is a complete theme\r\n */\r\nfunction isFullTheme(theme: Theme | Partial<Theme>): theme is Theme {\r\n return !!(\r\n theme &&\r\n typeof theme === 'object' &&\r\n 'name' in theme &&\r\n 'mode' in theme &&\r\n 'colors' in theme &&\r\n 'spacing' in theme &&\r\n 'radius' in theme &&\r\n 'typography' in theme &&\r\n 'transitions' in theme &&\r\n 'zIndex' in theme\r\n );\r\n}\r\n\r\n/**\r\n * Merges theme colors only\r\n */\r\nexport function mergeThemeColors(\r\n baseColors: Theme['colors'],\r\n ...colorSets: Array<Partial<Theme['colors']>>\r\n): Theme['colors'] {\r\n return colorSets.reduce((merged: Theme['colors'], colors): Theme['colors'] => ({\r\n ...merged,\r\n ...colors,\r\n }), baseColors);\r\n}\r\n\r\n/**\r\n * Deep merge utility for complex theme objects\r\n */\r\nexport function deepMergeThemes(target: Theme, ...sources: Array<Partial<Theme>>): Theme {\r\n return sources.reduce((merged: Theme, source): Theme => {\r\n const result = { ...merged };\r\n \r\n for (const key in source) {\r\n const sourceValue = source[key as keyof Theme];\r\n const targetValue = merged[key as keyof Theme];\r\n \r\n if (sourceValue && typeof sourceValue === 'object' && !Array.isArray(sourceValue) && targetValue && typeof targetValue === 'object') {\r\n result[key as keyof Theme] = {\r\n ...targetValue,\r\n ...sourceValue,\r\n } as any;\r\n } else if (sourceValue !== undefined) {\r\n result[key as keyof Theme] = sourceValue as any;\r\n }\r\n }\r\n \r\n return result;\r\n }, target);\r\n}\r\n"],"mappings":"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","names":["index_exports","__export","ThemeProvider","ThemeSelector","ThemeToggle","applyTheme","createTheme","darkTheme","deepMergeThemes","defaultTheme","defaultThemes","lightTheme","mergeTheme","mergeThemeColors","mergeThemes","themes","useTheme","useThemeToggle","__toCommonJS","lightColors","darkColors","baseTheme","lightTheme","darkTheme","defaultTheme","themes","defaultThemes","mergeTheme","customTheme","import_react","applyTheme","theme","mode","root","effectiveMode","key","value","kebabCase","kebabCase","str","match","import_jsx_runtime","ThemeContext","ThemeProvider","children","defaultMode","defaultTheme","persistMode","storageKey","customThemes","allThemes","defaultThemes","getInitialMode","stored","error","mode","setModeState","currentThemeName","setCurrentThemeName","getEffectiveMode","getCurrentTheme","effectiveMode","currentTheme","setMode","newMode","toggleMode","systemDark","setTheme","theme","applyTheme","mediaQuery","handleChange","contextValue","useThemeContext","context","useTheme","useThemeContext","useThemeToggle","mode","setMode","toggleMode","useTheme","effectiveMode","import_jsx_runtime","ThemeToggle","className","style","showLabels","size","mode","toggleMode","useTheme","buttonClass","getIcon","getLabel","import_jsx_runtime","ThemeSelector","className","style","showLabels","options","mode","setMode","useTheme","selectClass","e","option","createTheme","baseTheme","customTheme","mergeThemes","themes","baseTheme","additionalThemes","isFullTheme","merged","theme","mergeThemeColors","baseColors","colorSets","colors","deepMergeThemes","target","sources","source","result","key","sourceValue","targetValue"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,18 @@
1
+ var N={background:"#ffffff",backgroundSecondary:"#f8fafc",backgroundTertiary:"#f1f5f9",text:"#0f172a",textSecondary:"#475569",textMuted:"#64748b",border:"#e2e8f0",borderLight:"#f1f5f9",borderHover:"#cbd5e1",primary:"#3b82f6",primaryHover:"#2563eb",primaryActive:"#1d4ed8",success:"#10b981",warning:"#f59e0b",error:"#ef4444",info:"#06b6d4",hover:"#f8fafc",active:"#f1f5f9",focus:"rgba(59, 130, 246, 0.1)",shadow:"0 1px 2px 0 rgba(0, 0, 0, 0.05)",shadowMd:"0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",shadowLg:"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)"},L={background:"#0f172a",backgroundSecondary:"#1e293b",backgroundTertiary:"#334155",text:"#f8fafc",textSecondary:"#cbd5e1",textMuted:"#94a3b8",border:"#334155",borderLight:"#475569",borderHover:"#64748b",primary:"#60a5fa",primaryHover:"#3b82f6",primaryActive:"#2563eb",success:"#34d399",warning:"#fbbf24",error:"#f87171",info:"#22d3ee",hover:"#1e293b",active:"#334155",focus:"rgba(96, 165, 250, 0.1)",shadow:"0 1px 2px 0 rgba(0, 0, 0, 0.3)",shadowMd:"0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3)",shadowLg:"0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3)"},T={spacing:{xs:"0.25rem",sm:"0.5rem",md:"0.75rem",lg:"1rem",xl:"1.25rem","2xl":"1.5rem","3xl":"2rem","4xl":"3rem"},radius:{none:"0",sm:"0.25rem",md:"0.375rem",lg:"0.5rem",xl:"0.75rem","2xl":"1rem",full:"9999px"},typography:{fontFamily:{sans:'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif',serif:'ui-serif, Georgia, Cambria, "Times New Roman", Times, serif',mono:'ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace'},fontSize:{xs:"0.75rem",sm:"0.875rem",base:"1rem",lg:"1.125rem",xl:"1.25rem","2xl":"1.5rem","3xl":"1.875rem","4xl":"2.25rem","5xl":"3rem"},fontWeight:{light:"300",normal:"400",medium:"500",semibold:"600",bold:"700"},lineHeight:{tight:"1.25",normal:"1.5",relaxed:"1.75"}},transitions:{fast:"all 0.1s ease",normal:"all 0.2s ease",slow:"all 0.3s ease",bounce:"all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)"},zIndex:{dropdown:1e3,modal:1050,tooltip:1100,overlay:1200}},f={name:"light",mode:"light",colors:N,...T},b={name:"dark",mode:"dark",colors:L,...T},J=f,K={light:f,dark:b},k={default:f,light:f,dark:b};function X(e,o){return{...e,...o,colors:{...e.colors,...o.colors},spacing:{...e.spacing,...o.spacing},radius:{...e.radius,...o.radius},typography:{...e.typography,...o.typography,fontFamily:{...e.typography.fontFamily,...o.typography?.fontFamily},fontSize:{...e.typography.fontSize,...o.typography?.fontSize},fontWeight:{...e.typography.fontWeight,...o.typography?.fontWeight},lineHeight:{...e.typography.lineHeight,...o.typography?.lineHeight}},transitions:{...e.transitions,...o.transitions},zIndex:{...e.zIndex,...o.zIndex}}}import{createContext as R,useContext as W,useEffect as v,useState as M}from"react";function g(e,o){if(typeof document>"u")return;let n=document.documentElement,r=o;o==="auto"&&(r=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"),n.setAttribute("data-theme",e.name),n.setAttribute("data-theme-mode",r),Object.entries(e.colors).forEach(([t,a])=>{n.style.setProperty(`--theme-color-${w(t)}`,a)}),Object.entries(e.spacing).forEach(([t,a])=>{n.style.setProperty(`--theme-spacing-${t}`,a)}),Object.entries(e.radius).forEach(([t,a])=>{n.style.setProperty(`--theme-radius-${t}`,a)}),Object.entries(e.typography.fontFamily).forEach(([t,a])=>{n.style.setProperty(`--theme-font-family-${t}`,a)}),Object.entries(e.typography.fontSize).forEach(([t,a])=>{n.style.setProperty(`--theme-font-size-${t}`,a)}),Object.entries(e.typography.fontWeight).forEach(([t,a])=>{n.style.setProperty(`--theme-font-weight-${t}`,a)}),Object.entries(e.typography.lineHeight).forEach(([t,a])=>{n.style.setProperty(`--theme-line-height-${t}`,a)}),Object.entries(e.transitions).forEach(([t,a])=>{n.style.setProperty(`--theme-transition-${t}`,a)}),Object.entries(e.zIndex).forEach(([t,a])=>{n.style.setProperty(`--theme-z-index-${w(t)}`,a.toString())}),document.body.className=document.body.className.replace(/theme-\w+/g,""),document.body.classList.add(`theme-${e.name}`,`theme-${r}`)}function w(e){return e.replace(/[A-Z]/g,o=>`-${o.toLowerCase()}`)}import{jsx as j}from"react/jsx-runtime";var C=R(void 0),S=({children:e,defaultMode:o="auto",defaultTheme:n="default",persistMode:r=!0,storageKey:t="asafarim-theme-mode",customThemes:a={}})=>{let l={...k,...a},i=()=>{if(!r||typeof window>"u")return o;try{let s=localStorage.getItem(t);if(s&&["light","dark","auto"].includes(s))return s}catch(s){console.warn("Failed to read theme mode from localStorage:",s)}return o},[m,c]=M(i),[p,$]=M(n),E=()=>m==="auto"?typeof window<"u"&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":m,x=()=>{let s=E();return p!=="default"&&p in l?l[p]:s==="dark"?l.dark:l.light},y=x(),u=s=>{if(c(s),r&&typeof window<"u")try{localStorage.setItem(t,s)}catch(h){console.warn("Failed to save theme mode to localStorage:",h)}},A=()=>{if(m==="auto"){let s=window.matchMedia("(prefers-color-scheme: dark)").matches;u(s?"light":"dark")}else u(m==="light"?"dark":"light")},I=s=>{$(s.name)};v(()=>{g(y,m)},[y,m,p]),v(()=>{if(m!=="auto")return;let s=window.matchMedia("(prefers-color-scheme: dark)"),h=()=>{g(x(),m)};return s.addEventListener("change",h),()=>s.removeEventListener("change",h)},[m]);let H={currentTheme:y,mode:m,setMode:u,setTheme:I,themes:l,toggleMode:A};return j(C.Provider,{value:H,children:e})},P=()=>{let e=W(C);if(e===void 0)throw new Error("useThemeContext must be used within a ThemeProvider");return e};function d(){return P()}function O(){let{mode:e,setMode:o,toggleMode:n}=d(),t=e==="auto"?typeof window<"u"&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":e;return{mode:e,setMode:o,toggleMode:n,isDark:t==="dark",isLight:t==="light",isAuto:e==="auto",effectiveMode:t}}import{jsx as z,jsxs as V}from"react/jsx-runtime";var D=({className:e="",style:o={},showLabels:n=!1,size:r="md"})=>{let{mode:t,toggleMode:a}=d(),i=`
2
+ ${{sm:"w-8 h-8 text-sm",md:"w-10 h-10 text-base",lg:"w-12 h-12 text-lg"}[r]}
3
+ inline-flex items-center justify-center
4
+ rounded-md border border-gray-300
5
+ bg-white hover:bg-gray-50
6
+ dark:bg-gray-800 dark:border-gray-600 dark:hover:bg-gray-700
7
+ focus:outline-none focus:ring-2 focus:ring-blue-500
8
+ transition-all duration-200
9
+ ${e}
10
+ `.trim(),m=()=>{switch(t){case"light":return"\u2600\uFE0F";case"dark":return"\u{1F319}";case"auto":default:return"\u{1F313}"}},c=()=>{switch(t){case"light":return"Light";case"dark":return"Dark";case"auto":default:return"Auto"}};return V("button",{onClick:a,className:i,style:o,title:`Current theme: ${c()}. Click to toggle.`,"aria-label":`Switch theme. Current: ${c()}`,children:[z("span",{role:"img","aria-hidden":"true",children:m()}),n&&z("span",{className:"ml-2 text-sm font-medium",children:c()})]})};import{jsx as F}from"react/jsx-runtime";var B=({className:e="",style:o={},showLabels:n=!0,options:r=[{mode:"light",label:"Light",icon:"\u2600\uFE0F"},{mode:"dark",label:"Dark",icon:"\u{1F319}"},{mode:"auto",label:"Auto",icon:"\u{1F313}"}]})=>{let{mode:t,setMode:a}=d(),l=`
11
+ px-3 py-2 border border-gray-300 rounded-md
12
+ bg-white dark:bg-gray-800 dark:border-gray-600
13
+ text-gray-900 dark:text-gray-100
14
+ focus:outline-none focus:ring-2 focus:ring-blue-500
15
+ transition-all duration-200
16
+ ${e}
17
+ `.trim();return F("select",{value:t,onChange:i=>a(i.target.value),className:l,style:o,"aria-label":"Select theme mode",children:r.map(i=>F("option",{value:i.mode,children:n?`${i.icon?i.icon+" ":""}${i.label}`:i.icon||i.label},i.mode))})};function G(e,o){return{...e,...o,name:o.name||`${e.name}-custom`,colors:{...e.colors,...o.colors},spacing:{...e.spacing,...o.spacing},radius:{...e.radius,...o.radius},typography:{...e.typography,...o.typography,fontFamily:{...e.typography.fontFamily,...o.typography?.fontFamily},fontSize:{...e.typography.fontSize,...o.typography?.fontSize},fontWeight:{...e.typography.fontWeight,...o.typography?.fontWeight},lineHeight:{...e.typography.lineHeight,...o.typography?.lineHeight}},transitions:{...e.transitions,...o.transitions},zIndex:{...e.zIndex,...o.zIndex}}}function Q(...e){if(e.length===0)throw new Error("At least one theme must be provided to mergeThemes");let[o,...n]=e;if(!U(o))throw new Error("First theme must be a complete theme object");return n.reduce((r,t)=>({...r,...t,name:t.name||r.name,mode:t.mode||r.mode,colors:{...r.colors,...t.colors},spacing:{...r.spacing,...t.spacing},radius:{...r.radius,...t.radius},typography:{...r.typography,...t.typography,fontFamily:{...r.typography.fontFamily,...t.typography?.fontFamily},fontSize:{...r.typography.fontSize,...t.typography?.fontSize},fontWeight:{...r.typography.fontWeight,...t.typography?.fontWeight},lineHeight:{...r.typography.lineHeight,...t.typography?.lineHeight}},transitions:{...r.transitions,...t.transitions},zIndex:{...r.zIndex,...t.zIndex}}),o)}function U(e){return!!(e&&typeof e=="object"&&"name"in e&&"mode"in e&&"colors"in e&&"spacing"in e&&"radius"in e&&"typography"in e&&"transitions"in e&&"zIndex"in e)}function Z(e,...o){return o.reduce((n,r)=>({...n,...r}),e)}function q(e,...o){return o.reduce((n,r)=>{let t={...n};for(let a in r){let l=r[a],i=n[a];l&&typeof l=="object"&&!Array.isArray(l)&&i&&typeof i=="object"?t[a]={...i,...l}:l!==void 0&&(t[a]=l)}return t},e)}export{S as ThemeProvider,B as ThemeSelector,D as ThemeToggle,g as applyTheme,G as createTheme,b as darkTheme,q as deepMergeThemes,S as default,J as defaultTheme,k as defaultThemes,f as lightTheme,X as mergeTheme,Z as mergeThemeColors,Q as mergeThemes,K as themes,d as useTheme,O as useThemeToggle};
18
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/themes.ts","../src/components/ThemeProvider.tsx","../src/utils/applyTheme.ts","../src/hooks/useTheme.ts","../src/hooks/useThemeToggle.ts","../src/components/ThemeToggle.tsx","../src/components/ThemeSelector.tsx","../src/utils/createTheme.ts","../src/utils/mergeThemes.ts"],"sourcesContent":["import type { Theme, ThemeColors } from './types';\r\n\r\n// Light theme colors\r\nconst lightColors: ThemeColors = {\r\n // Background colors\r\n background: '#ffffff',\r\n backgroundSecondary: '#f8fafc',\r\n backgroundTertiary: '#f1f5f9',\r\n \r\n // Text colors\r\n text: '#0f172a',\r\n textSecondary: '#475569',\r\n textMuted: '#64748b',\r\n \r\n // Border colors\r\n border: '#e2e8f0',\r\n borderLight: '#f1f5f9',\r\n borderHover: '#cbd5e1',\r\n \r\n // Accent colors\r\n primary: '#3b82f6',\r\n primaryHover: '#2563eb',\r\n primaryActive: '#1d4ed8',\r\n \r\n // Status colors\r\n success: '#10b981',\r\n warning: '#f59e0b',\r\n error: '#ef4444',\r\n info: '#06b6d4',\r\n \r\n // Interactive states\r\n hover: '#f8fafc',\r\n active: '#f1f5f9',\r\n focus: 'rgba(59, 130, 246, 0.1)',\r\n \r\n // Shadows\r\n shadow: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',\r\n shadowMd: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',\r\n shadowLg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',\r\n};\r\n\r\n// Dark theme colors\r\nconst darkColors: ThemeColors = {\r\n // Background colors\r\n background: '#0f172a',\r\n backgroundSecondary: '#1e293b',\r\n backgroundTertiary: '#334155',\r\n \r\n // Text colors\r\n text: '#f8fafc',\r\n textSecondary: '#cbd5e1',\r\n textMuted: '#94a3b8',\r\n \r\n // Border colors\r\n border: '#334155',\r\n borderLight: '#475569',\r\n borderHover: '#64748b',\r\n \r\n // Accent colors\r\n primary: '#60a5fa',\r\n primaryHover: '#3b82f6',\r\n primaryActive: '#2563eb',\r\n \r\n // Status colors\r\n success: '#34d399',\r\n warning: '#fbbf24',\r\n error: '#f87171',\r\n info: '#22d3ee',\r\n \r\n // Interactive states\r\n hover: '#1e293b',\r\n active: '#334155',\r\n focus: 'rgba(96, 165, 250, 0.1)',\r\n \r\n // Shadows\r\n shadow: '0 1px 2px 0 rgba(0, 0, 0, 0.3)',\r\n shadowMd: '0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3)',\r\n shadowLg: '0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3)',\r\n};\r\n\r\n// Base theme structure\r\nconst baseTheme = {\r\n spacing: {\r\n xs: '0.25rem',\r\n sm: '0.5rem',\r\n md: '0.75rem',\r\n lg: '1rem',\r\n xl: '1.25rem',\r\n '2xl': '1.5rem',\r\n '3xl': '2rem',\r\n '4xl': '3rem',\r\n },\r\n radius: {\r\n none: '0',\r\n sm: '0.25rem',\r\n md: '0.375rem',\r\n lg: '0.5rem',\r\n xl: '0.75rem',\r\n '2xl': '1rem',\r\n full: '9999px',\r\n },\r\n typography: {\r\n fontFamily: {\r\n sans: 'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif',\r\n serif: 'ui-serif, Georgia, Cambria, \"Times New Roman\", Times, serif',\r\n mono: 'ui-monospace, SFMono-Regular, \"SF Mono\", Consolas, \"Liberation Mono\", Menlo, monospace',\r\n },\r\n fontSize: {\r\n xs: '0.75rem',\r\n sm: '0.875rem',\r\n base: '1rem',\r\n lg: '1.125rem',\r\n xl: '1.25rem',\r\n '2xl': '1.5rem',\r\n '3xl': '1.875rem',\r\n '4xl': '2.25rem',\r\n '5xl': '3rem',\r\n },\r\n fontWeight: {\r\n light: '300',\r\n normal: '400',\r\n medium: '500',\r\n semibold: '600',\r\n bold: '700',\r\n },\r\n lineHeight: {\r\n tight: '1.25',\r\n normal: '1.5',\r\n relaxed: '1.75',\r\n },\r\n },\r\n transitions: {\r\n fast: 'all 0.1s ease',\r\n normal: 'all 0.2s ease',\r\n slow: 'all 0.3s ease',\r\n bounce: 'all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)',\r\n },\r\n zIndex: {\r\n dropdown: 1000,\r\n modal: 1050,\r\n tooltip: 1100,\r\n overlay: 1200,\r\n },\r\n};\r\n\r\n// Light theme\r\nexport const lightTheme: Theme = {\r\n name: 'light',\r\n mode: 'light',\r\n colors: lightColors,\r\n ...baseTheme,\r\n};\r\n\r\n// Dark theme\r\nexport const darkTheme: Theme = {\r\n name: 'dark',\r\n mode: 'dark',\r\n colors: darkColors,\r\n ...baseTheme,\r\n};\r\n\r\n// Default theme (light)\r\nexport const defaultTheme = lightTheme;\r\n\r\n// Theme presets\r\nexport const themes = {\r\n light: lightTheme,\r\n dark: darkTheme,\r\n};\r\n\r\n// Default themes for the provider\r\nexport const defaultThemes = {\r\n default: lightTheme,\r\n light: lightTheme,\r\n dark: darkTheme,\r\n};\r\n\r\n// Helper function to merge themes\r\nexport function mergeTheme(baseTheme: Theme, customTheme: Partial<Theme>): Theme {\r\n return {\r\n ...baseTheme,\r\n ...customTheme,\r\n colors: {\r\n ...baseTheme.colors,\r\n ...customTheme.colors,\r\n },\r\n spacing: {\r\n ...baseTheme.spacing,\r\n ...customTheme.spacing,\r\n },\r\n radius: {\r\n ...baseTheme.radius,\r\n ...customTheme.radius,\r\n },\r\n typography: {\r\n ...baseTheme.typography,\r\n ...customTheme.typography,\r\n fontFamily: {\r\n ...baseTheme.typography.fontFamily,\r\n ...customTheme.typography?.fontFamily,\r\n },\r\n fontSize: {\r\n ...baseTheme.typography.fontSize,\r\n ...customTheme.typography?.fontSize,\r\n },\r\n fontWeight: {\r\n ...baseTheme.typography.fontWeight,\r\n ...customTheme.typography?.fontWeight,\r\n },\r\n lineHeight: {\r\n ...baseTheme.typography.lineHeight,\r\n ...customTheme.typography?.lineHeight,\r\n },\r\n },\r\n transitions: {\r\n ...baseTheme.transitions,\r\n ...customTheme.transitions,\r\n },\r\n zIndex: {\r\n ...baseTheme.zIndex,\r\n ...customTheme.zIndex,\r\n },\r\n };\r\n}\r\n","import * as React from 'react';\r\nimport { createContext, useContext, useEffect, useState, ReactNode } from 'react';\r\nimport { Theme, ThemeConfig, ThemeMode } from '../types';\r\nimport { defaultThemes } from '../themes';\r\nimport { applyTheme } from '../utils/applyTheme';\r\n\r\nexport interface ThemeContextType {\r\n currentTheme: Theme;\r\n mode: ThemeMode;\r\n setMode: (mode: ThemeMode) => void;\r\n setTheme: (theme: Theme) => void;\r\n themes: Record<string, Theme>;\r\n toggleMode: () => void;\r\n}\r\n\r\nconst ThemeContext = createContext<ThemeContextType | undefined>(undefined);\r\n\r\nexport interface ThemeProviderProps {\r\n children: ReactNode;\r\n config?: ThemeConfig;\r\n defaultMode?: ThemeMode;\r\n defaultTheme?: string;\r\n persistMode?: boolean;\r\n storageKey?: string;\r\n customThemes?: Record<string, Theme>;\r\n}\r\n\r\nexport const ThemeProvider: React.FC<ThemeProviderProps> = ({\r\n children,\r\n defaultMode = 'auto',\r\n defaultTheme = 'default',\r\n persistMode = true,\r\n storageKey = 'asafarim-theme-mode',\r\n customThemes = {},\r\n}) => {\r\n const allThemes = { ...defaultThemes, ...customThemes };\r\n \r\n // Get initial mode from localStorage or use default\r\n const getInitialMode = (): ThemeMode => {\r\n if (!persistMode || typeof window === 'undefined') return defaultMode;\r\n \r\n try {\r\n const stored = localStorage.getItem(storageKey);\r\n if (stored && ['light', 'dark', 'auto'].includes(stored)) {\r\n return stored as ThemeMode;\r\n }\r\n } catch (error) {\r\n console.warn('Failed to read theme mode from localStorage:', error);\r\n }\r\n \r\n return defaultMode;\r\n };\r\n const [mode, setModeState] = useState<ThemeMode>(getInitialMode);\r\n const [currentThemeName, setCurrentThemeName] = useState<string>(defaultTheme);\r\n\r\n // Get the effective mode (resolving 'auto' to actual light/dark)\r\n const getEffectiveMode = (): 'light' | 'dark' => {\r\n if (mode === 'auto') {\r\n if (typeof window !== 'undefined') {\r\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\r\n }\r\n return 'light'; // fallback for SSR\r\n }\r\n return mode;\r\n };\r\n // Get the current theme based on mode and theme name\r\n const getCurrentTheme = (): Theme => {\r\n const effectiveMode = getEffectiveMode();\r\n \r\n // If user selected a specific theme, use it\r\n if (currentThemeName !== 'default' && currentThemeName in allThemes) {\r\n return allThemes[currentThemeName as keyof typeof allThemes];\r\n }\r\n \r\n // Otherwise use the theme that matches the effective mode\r\n return effectiveMode === 'dark' ? allThemes.dark : allThemes.light;\r\n };\r\n\r\n const currentTheme = getCurrentTheme();\r\n\r\n // Update mode and persist if enabled\r\n const setMode = (newMode: ThemeMode) => {\r\n setModeState(newMode);\r\n \r\n if (persistMode && typeof window !== 'undefined') {\r\n try {\r\n localStorage.setItem(storageKey, newMode);\r\n } catch (error) {\r\n console.warn('Failed to save theme mode to localStorage:', error);\r\n }\r\n }\r\n };\r\n\r\n // Toggle between light and dark modes\r\n const toggleMode = () => {\r\n if (mode === 'auto') {\r\n // If auto, switch to opposite of system preference\r\n const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches;\r\n setMode(systemDark ? 'light' : 'dark');\r\n } else {\r\n setMode(mode === 'light' ? 'dark' : 'light');\r\n }\r\n };\r\n // Set theme by name\r\n const setTheme = (theme: Theme) => {\r\n setCurrentThemeName(theme.name);\r\n };\r\n // Apply theme to document\r\n useEffect(() => {\r\n applyTheme(currentTheme, mode);\r\n }, [currentTheme, mode, currentThemeName]); // Add currentThemeName as dependency\r\n\r\n // Listen for system theme changes when in auto mode\r\n useEffect(() => {\r\n if (mode !== 'auto') return;\r\n\r\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\r\n const handleChange = () => {\r\n // Force re-render when system preference changes\r\n applyTheme(getCurrentTheme(), mode);\r\n };\r\n\r\n mediaQuery.addEventListener('change', handleChange);\r\n return () => mediaQuery.removeEventListener('change', handleChange);\r\n }, [mode]);\r\n\r\n const contextValue: ThemeContextType = {\r\n currentTheme,\r\n mode,\r\n setMode,\r\n setTheme,\r\n themes: allThemes,\r\n toggleMode,\r\n };\r\n\r\n return (\r\n <ThemeContext.Provider value={contextValue}>\r\n {children}\r\n </ThemeContext.Provider>\r\n );\r\n};\r\n\r\nexport const useThemeContext = () => {\r\n const context = useContext(ThemeContext);\r\n if (context === undefined) {\r\n throw new Error('useThemeContext must be used within a ThemeProvider');\r\n }\r\n return context;\r\n};\r\n","import { Theme, ThemeMode } from '../types';\r\n\r\n/**\r\n * Applies theme CSS variables to the document root\r\n */\r\nexport function applyTheme(theme: Theme, mode: ThemeMode): void {\r\n if (typeof document === 'undefined') return;\r\n\r\n const root = document.documentElement;\r\n \r\n // Determine the effective mode\r\n let effectiveMode = mode;\r\n if (mode === 'auto') {\r\n effectiveMode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\r\n }\r\n\r\n // Set data attributes for CSS targeting\r\n root.setAttribute('data-theme', theme.name);\r\n root.setAttribute('data-theme-mode', effectiveMode);\r\n\r\n // Apply color variables\r\n Object.entries(theme.colors).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-color-${kebabCase(key)}`, value);\r\n });\r\n\r\n // Apply spacing variables\r\n Object.entries(theme.spacing).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-spacing-${key}`, value);\r\n });\r\n\r\n // Apply radius variables\r\n Object.entries(theme.radius).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-radius-${key}`, value);\r\n });\r\n\r\n // Apply typography variables\r\n Object.entries(theme.typography.fontFamily).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-font-family-${key}`, value);\r\n });\r\n\r\n Object.entries(theme.typography.fontSize).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-font-size-${key}`, value);\r\n });\r\n\r\n Object.entries(theme.typography.fontWeight).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-font-weight-${key}`, value);\r\n });\r\n\r\n Object.entries(theme.typography.lineHeight).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-line-height-${key}`, value);\r\n });\r\n\r\n // Apply transition variables\r\n Object.entries(theme.transitions).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-transition-${key}`, value);\r\n });\r\n\r\n // Apply z-index variables\r\n Object.entries(theme.zIndex).forEach(([key, value]) => {\r\n root.style.setProperty(`--theme-z-index-${kebabCase(key)}`, value.toString());\r\n });\r\n\r\n // Add theme class to body for additional styling\r\n document.body.className = document.body.className.replace(/theme-\\w+/g, '');\r\n document.body.classList.add(`theme-${theme.name}`, `theme-${effectiveMode}`);\r\n}\r\n\r\n/**\r\n * Removes all theme-related CSS variables and classes\r\n */\r\nexport function removeTheme(): void {\r\n if (typeof document === 'undefined') return;\r\n\r\n const root = document.documentElement;\r\n \r\n // Remove data attributes\r\n root.removeAttribute('data-theme');\r\n root.removeAttribute('data-theme-mode');\r\n\r\n // Remove CSS variables (this is a simplified approach - in production you might want to track which variables were set)\r\n const styles = root.style;\r\n for (let i = styles.length - 1; i >= 0; i--) {\r\n const property = styles[i];\r\n if (property.startsWith('--theme-')) {\r\n root.style.removeProperty(property);\r\n }\r\n }\r\n\r\n // Remove theme classes from body\r\n document.body.className = document.body.className.replace(/theme-\\w+/g, '');\r\n}\r\n\r\n/**\r\n * Converts camelCase to kebab-case\r\n */\r\nfunction kebabCase(str: string): string {\r\n return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);\r\n}\r\n","import { useThemeContext, ThemeContextType } from '../components/ThemeProvider';\r\n\r\n/**\r\n * Hook to access theme context\r\n */\r\nexport function useTheme(): ThemeContextType {\r\n return useThemeContext();\r\n}\r\n","import { useTheme } from './useTheme';\r\n\r\n/**\r\n * Hook that provides theme toggle functionality\r\n */\r\nexport function useThemeToggle() {\r\n const { mode, setMode, toggleMode } = useTheme();\r\n \r\n // Get effective mode (resolving 'auto' to actual light/dark)\r\n const getEffectiveMode = (): 'light' | 'dark' => {\r\n if (mode === 'auto') {\r\n if (typeof window !== 'undefined') {\r\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\r\n }\r\n return 'light'; // fallback for SSR\r\n }\r\n return mode;\r\n };\r\n\r\n const effectiveMode = getEffectiveMode();\r\n \r\n return {\r\n mode,\r\n setMode,\r\n toggleMode,\r\n isDark: effectiveMode === 'dark',\r\n isLight: effectiveMode === 'light',\r\n isAuto: mode === 'auto',\r\n effectiveMode, // Expose the resolved mode\r\n };\r\n}\r\n","import * as React from 'react';\r\nimport { useTheme } from '../hooks/useTheme';\r\n\r\nexport interface ThemeToggleProps {\r\n className?: string;\r\n style?: React.CSSProperties;\r\n showLabels?: boolean;\r\n size?: 'sm' | 'md' | 'lg';\r\n}\r\n\r\nexport const ThemeToggle: React.FC<ThemeToggleProps> = ({\r\n className = '',\r\n style = {},\r\n showLabels = false,\r\n size = 'md',\r\n}) => {\r\n const { mode, toggleMode } = useTheme();\r\n\r\n const sizeClasses = {\r\n sm: 'w-8 h-8 text-sm',\r\n md: 'w-10 h-10 text-base',\r\n lg: 'w-12 h-12 text-lg',\r\n };\r\n\r\n const buttonClass = `\r\n ${sizeClasses[size]}\r\n inline-flex items-center justify-center\r\n rounded-md border border-gray-300\r\n bg-white hover:bg-gray-50\r\n dark:bg-gray-800 dark:border-gray-600 dark:hover:bg-gray-700\r\n focus:outline-none focus:ring-2 focus:ring-blue-500\r\n transition-all duration-200\r\n ${className}\r\n `.trim();\r\n\r\n const getIcon = () => {\r\n switch (mode) {\r\n case 'light':\r\n return '☀️';\r\n case 'dark':\r\n return '🌙';\r\n case 'auto':\r\n default:\r\n return '🌓';\r\n }\r\n };\r\n\r\n const getLabel = () => {\r\n switch (mode) {\r\n case 'light':\r\n return 'Light';\r\n case 'dark':\r\n return 'Dark';\r\n case 'auto':\r\n default:\r\n return 'Auto';\r\n }\r\n };\r\n\r\n return (\r\n <button\r\n onClick={toggleMode}\r\n className={buttonClass}\r\n style={style}\r\n title={`Current theme: ${getLabel()}. Click to toggle.`}\r\n aria-label={`Switch theme. Current: ${getLabel()}`}\r\n >\r\n <span role=\"img\" aria-hidden=\"true\">\r\n {getIcon()}\r\n </span>\r\n {showLabels && (\r\n <span className=\"ml-2 text-sm font-medium\">\r\n {getLabel()}\r\n </span>\r\n )}\r\n </button>\r\n );\r\n};\r\n","import * as React from \"react\";\r\nimport { useTheme } from \"../hooks/useTheme\";\r\nimport { ThemeMode } from \"../types\";\r\n\r\nexport interface ThemeSelectorProps {\r\n className?: string;\r\n style?: React.CSSProperties;\r\n showLabels?: boolean;\r\n options?: Array<{\r\n mode: ThemeMode;\r\n label: string;\r\n icon?: string;\r\n }>;\r\n}\r\n\r\nexport const ThemeSelector: React.FC<ThemeSelectorProps> = ({\r\n className = \"\",\r\n style = {},\r\n showLabels = true,\r\n options = [\r\n { mode: \"light\", label: \"Light\", icon: \"☀️\" },\r\n { mode: \"dark\", label: \"Dark\", icon: \"🌙\" },\r\n { mode: \"auto\", label: \"Auto\", icon: \"🌓\" },\r\n ],\r\n}) => {\r\n const { mode, setMode } = useTheme();\r\n\r\n const selectClass = `\r\n px-3 py-2 border border-gray-300 rounded-md\r\n bg-white dark:bg-gray-800 dark:border-gray-600\r\n text-gray-900 dark:text-gray-100\r\n focus:outline-none focus:ring-2 focus:ring-blue-500\r\n transition-all duration-200\r\n ${className}\r\n `.trim();\r\n\r\n return (\r\n <select\r\n value={mode}\r\n onChange={(e) => setMode(e.target.value as ThemeMode)}\r\n className={selectClass}\r\n style={style}\r\n aria-label=\"Select theme mode\"\r\n >\r\n {options.map((option) => (\r\n <option key={option.mode} value={option.mode}>\r\n {showLabels\r\n ? `${option.icon ? option.icon + \" \" : \"\"}${option.label}`\r\n : option.icon || option.label}\r\n </option>\r\n ))}\r\n </select>\r\n );\r\n};\r\n","import { Theme } from '../types';\r\n\r\n/**\r\n * Creates a new theme by merging a base theme with custom properties\r\n */\r\nexport function createTheme(\r\n baseTheme: Theme,\r\n customTheme: Partial<Theme>\r\n): Theme {\r\n return {\r\n ...baseTheme,\r\n ...customTheme,\r\n name: customTheme.name || `${baseTheme.name}-custom`,\r\n colors: {\r\n ...baseTheme.colors,\r\n ...customTheme.colors,\r\n },\r\n spacing: {\r\n ...baseTheme.spacing,\r\n ...customTheme.spacing,\r\n },\r\n radius: {\r\n ...baseTheme.radius,\r\n ...customTheme.radius,\r\n },\r\n typography: {\r\n ...baseTheme.typography,\r\n ...customTheme.typography,\r\n fontFamily: {\r\n ...baseTheme.typography.fontFamily,\r\n ...customTheme.typography?.fontFamily,\r\n },\r\n fontSize: {\r\n ...baseTheme.typography.fontSize,\r\n ...customTheme.typography?.fontSize,\r\n },\r\n fontWeight: {\r\n ...baseTheme.typography.fontWeight,\r\n ...customTheme.typography?.fontWeight,\r\n },\r\n lineHeight: {\r\n ...baseTheme.typography.lineHeight,\r\n ...customTheme.typography?.lineHeight,\r\n },\r\n },\r\n transitions: {\r\n ...baseTheme.transitions,\r\n ...customTheme.transitions,\r\n },\r\n zIndex: {\r\n ...baseTheme.zIndex,\r\n ...customTheme.zIndex,\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Creates a theme variant with modified colors\r\n */\r\nexport function createThemeVariant(\r\n baseTheme: Theme,\r\n colorOverrides: Partial<Theme['colors']>,\r\n name?: string\r\n): Theme {\r\n return createTheme(baseTheme, {\r\n name: name || `${baseTheme.name}-variant`,\r\n colors: {\r\n ...baseTheme.colors,\r\n ...colorOverrides,\r\n },\r\n });\r\n}\r\n","import { Theme } from '../types';\r\n\r\n/**\r\n * Merges multiple themes into a single theme\r\n * Later themes in the array take precedence over earlier ones\r\n */\r\nexport function mergeThemes(...themes: Array<Theme | Partial<Theme>>): Theme {\r\n if (themes.length === 0) {\r\n throw new Error('At least one theme must be provided to mergeThemes');\r\n }\r\n\r\n const [baseTheme, ...additionalThemes] = themes;\r\n \r\n if (!isFullTheme(baseTheme)) {\r\n throw new Error('First theme must be a complete theme object');\r\n }\r\n return additionalThemes.reduce((merged: Theme, theme): Theme => {\r\n return {\r\n ...merged,\r\n ...theme,\r\n name: theme.name || merged.name,\r\n mode: theme.mode || merged.mode,\r\n colors: {\r\n ...merged.colors,\r\n ...theme.colors,\r\n },\r\n spacing: {\r\n ...merged.spacing,\r\n ...theme.spacing,\r\n },\r\n radius: {\r\n ...merged.radius,\r\n ...theme.radius,\r\n },\r\n typography: {\r\n ...merged.typography,\r\n ...theme.typography,\r\n fontFamily: {\r\n ...merged.typography.fontFamily,\r\n ...theme.typography?.fontFamily,\r\n },\r\n fontSize: {\r\n ...merged.typography.fontSize,\r\n ...theme.typography?.fontSize,\r\n },\r\n fontWeight: {\r\n ...merged.typography.fontWeight,\r\n ...theme.typography?.fontWeight,\r\n },\r\n lineHeight: {\r\n ...merged.typography.lineHeight,\r\n ...theme.typography?.lineHeight,\r\n },\r\n },\r\n transitions: {\r\n ...merged.transitions,\r\n ...theme.transitions,\r\n },\r\n zIndex: {\r\n ...merged.zIndex,\r\n ...theme.zIndex,\r\n },\r\n };\r\n }, baseTheme);\r\n}\r\n\r\n/**\r\n * Type guard to check if an object is a complete theme\r\n */\r\nfunction isFullTheme(theme: Theme | Partial<Theme>): theme is Theme {\r\n return !!(\r\n theme &&\r\n typeof theme === 'object' &&\r\n 'name' in theme &&\r\n 'mode' in theme &&\r\n 'colors' in theme &&\r\n 'spacing' in theme &&\r\n 'radius' in theme &&\r\n 'typography' in theme &&\r\n 'transitions' in theme &&\r\n 'zIndex' in theme\r\n );\r\n}\r\n\r\n/**\r\n * Merges theme colors only\r\n */\r\nexport function mergeThemeColors(\r\n baseColors: Theme['colors'],\r\n ...colorSets: Array<Partial<Theme['colors']>>\r\n): Theme['colors'] {\r\n return colorSets.reduce((merged: Theme['colors'], colors): Theme['colors'] => ({\r\n ...merged,\r\n ...colors,\r\n }), baseColors);\r\n}\r\n\r\n/**\r\n * Deep merge utility for complex theme objects\r\n */\r\nexport function deepMergeThemes(target: Theme, ...sources: Array<Partial<Theme>>): Theme {\r\n return sources.reduce((merged: Theme, source): Theme => {\r\n const result = { ...merged };\r\n \r\n for (const key in source) {\r\n const sourceValue = source[key as keyof Theme];\r\n const targetValue = merged[key as keyof Theme];\r\n \r\n if (sourceValue && typeof sourceValue === 'object' && !Array.isArray(sourceValue) && targetValue && typeof targetValue === 'object') {\r\n result[key as keyof Theme] = {\r\n ...targetValue,\r\n ...sourceValue,\r\n } as any;\r\n } else if (sourceValue !== undefined) {\r\n result[key as keyof Theme] = sourceValue as any;\r\n }\r\n }\r\n \r\n return result;\r\n }, target);\r\n}\r\n"],"mappings":"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","names":["lightColors","darkColors","baseTheme","lightTheme","darkTheme","defaultTheme","themes","defaultThemes","mergeTheme","customTheme","createContext","useContext","useEffect","useState","applyTheme","theme","mode","root","effectiveMode","key","value","kebabCase","kebabCase","str","match","jsx","ThemeContext","createContext","ThemeProvider","children","defaultMode","defaultTheme","persistMode","storageKey","customThemes","allThemes","defaultThemes","getInitialMode","stored","error","mode","setModeState","useState","currentThemeName","setCurrentThemeName","getEffectiveMode","getCurrentTheme","effectiveMode","currentTheme","setMode","newMode","toggleMode","systemDark","setTheme","theme","useEffect","applyTheme","mediaQuery","handleChange","contextValue","useThemeContext","context","useContext","useTheme","useThemeContext","useThemeToggle","mode","setMode","toggleMode","useTheme","effectiveMode","jsx","jsxs","ThemeToggle","className","style","showLabels","size","mode","toggleMode","useTheme","buttonClass","getIcon","getLabel","jsx","ThemeSelector","className","style","showLabels","options","mode","setMode","useTheme","selectClass","e","option","createTheme","baseTheme","customTheme","mergeThemes","themes","baseTheme","additionalThemes","isFullTheme","merged","theme","mergeThemeColors","baseColors","colorSets","colors","deepMergeThemes","target","sources","source","result","key","sourceValue","targetValue"]}
package/package.json ADDED
@@ -0,0 +1,87 @@
1
+ {
2
+ "name": "@asafarim/react-themes",
3
+ "version": "1.0.0",
4
+ "description": "A comprehensive theme management system for React applications with automatic dark/light mode detection, custom theme creation, and smooth transitions.",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.mjs",
15
+ "require": "./dist/index.js"
16
+ },
17
+ "./styles.css": "./src/styles.css"
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "README.md",
22
+ "LICENSE"
23
+ ],
24
+ "keywords": [
25
+ "react",
26
+ "themes",
27
+ "dark-mode",
28
+ "light-mode",
29
+ "css-variables",
30
+ "theme-management",
31
+ "typescript",
32
+ "ui",
33
+ "components"
34
+ ],
35
+ "author": "Ali Safari <ali@asafarim.com>",
36
+ "license": "MIT",
37
+ "homepage": "https://github.com/AliSafari-IT/asafarim/tree/main/ASafariM.Clients/packages/react-themes#readme",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/AliSafari-IT/asafarim.git",
41
+ "directory": "ASafariM.Clients/packages/react-themes"
42
+ },
43
+ "bugs": {
44
+ "url": "https://github.com/AliSafari-IT/asafarim/issues"
45
+ },
46
+ "peerDependencies": {
47
+ "react": ">=16.8.0",
48
+ "react-dom": ">=16.8.0"
49
+ },
50
+ "devDependencies": {
51
+ "@types/react": "^18.2.66",
52
+ "@types/react-dom": "^18.2.22",
53
+ "@typescript-eslint/eslint-plugin": "^7.2.0",
54
+ "@typescript-eslint/parser": "^7.2.0",
55
+ "eslint": "^8.57.0",
56
+ "eslint-plugin-react": "^7.34.0",
57
+ "eslint-plugin-react-hooks": "^4.6.0",
58
+ "tsup": "^8.0.2",
59
+ "typescript": "^5.4.2"
60
+ },
61
+ "tsup": {
62
+ "entry": [
63
+ "src/index.ts"
64
+ ],
65
+ "format": [
66
+ "cjs",
67
+ "esm"
68
+ ],
69
+ "dts": true,
70
+ "splitting": false,
71
+ "sourcemap": true,
72
+ "clean": true,
73
+ "minify": true,
74
+ "external": [
75
+ "react",
76
+ "react-dom"
77
+ ]
78
+ },
79
+ "scripts": {
80
+ "build": "tsup",
81
+ "dev": "tsup --watch",
82
+ "type-check": "tsc --noEmit",
83
+ "lint": "eslint src --ext .ts,.tsx",
84
+ "lint:fix": "eslint src --ext .ts,.tsx --fix",
85
+ "clean": "rm -rf dist"
86
+ }
87
+ }