@cruxext/theme 0.0.7 β†’ 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,9 +8,10 @@
8
8
  </div>
9
9
 
10
10
  <div align="center">
11
- <img src="https://img.shields.io/badge/v-0.0.7-black"/>
11
+ <img src="https://img.shields.io/badge/v-0.0.8-black"/>
12
12
  <a href="https://github.com/cruxext-org"><img src="https://img.shields.io/badge/πŸ”₯-@cruxext-black"/></a>
13
13
  <br>
14
+ <img src="https://img.shields.io/badge/coverage-100%25-brightgreen" alt="Test Coverage" />
14
15
  <img src="https://img.shields.io/github/issues/cruxext-org/theme?style=flat" alt="Github Repo Issues" />
15
16
  <img src="https://img.shields.io/github/stars/cruxext-org/theme?style=social" alt="GitHub Repo stars" />
16
17
  </div>
@@ -25,17 +26,10 @@
25
26
  - ## Overview πŸ‘€
26
27
 
27
28
  - #### Why ?
28
- > A lightweight, reactive theme management solution for dark/light mode switching with persistent storage and system preference detection, built for the CruxJS ecosystem.
29
+ > A lightweight, reactive theme management solution, built for [`@cruxjs`](https://github.com/cruxjs-org) ecosystem.
29
30
 
30
31
  - #### When ?
31
- > Use this extension when you need to:
32
- > - Implement dark/light mode switching in your application
33
- > - Respect user's system color scheme preferences
34
- > - Persist theme preferences across sessions
35
- > - Build reactive UI components that respond to theme changes
36
- > - Integrate theme management into CruxJS-based applications
37
-
38
- > When using [@cruxjs/app](https://github.com/cruxjs-org/app) and [@cruxjs/client](https://github.com/cruxjs-org/client).
32
+ > When you need to manage theme preferences in your [`@cruxjs`](https://github.com/cruxjs-org) application.
39
33
 
40
34
  <br>
41
35
  <br>
@@ -49,45 +43,37 @@
49
43
  hmm i @cruxext/theme
50
44
  ```
51
45
 
52
- ```ts
53
- // in your ts files
54
- import { ... } from `@cruxext/theme`;
55
- ```
56
-
57
46
  <div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> </div>
58
47
  <br>
59
48
 
60
- - ### Example
49
+ - ### Setup
61
50
 
62
51
  ```typescript
63
- import { type JSXElement } from '@minejs/jsx';
64
- import { effect, signal } from '@minejs/signals';
65
- import { Button } from '@cruxkit/core';
66
- import { toggleTheme, getCurrentTheme } from '@cruxext/theme';
67
-
68
- export function MyComponent(): JSXElement {
69
- const isDark = signal(getCurrentTheme() == 'dark');
70
-
71
- effect(() => {
72
- console.log('isDark:', isDark());
73
- const btn = document.querySelector('#theme_button');
74
- if(!btn) return;
75
- toggleTheme();
76
-
77
- btn.textContent = isDark() ? 'β˜€οΈ Light Mode' : 'πŸŒ™ Dark Mode';
78
- });
79
-
80
- return (
81
- <Button
82
- id="theme_button"
83
- variant="solid"
84
- color="brand"
85
- onClick={() => isDark.set(!isDark())}
86
- >
87
- {isDark() ? 'β˜€οΈ Light Mode' : 'πŸŒ™ Dark Mode'}
88
- </Button>
89
- );
90
- }
52
+ // in your client config at `client.ts` file, add the theme extension.
53
+ import { themeExtension } from `@cruxext/theme`;
54
+
55
+ const config: ClientManagerConfig = {
56
+ ...
57
+
58
+ extensions: [
59
+ ...
60
+ createThemeExtension(),
61
+ ],
62
+ };
63
+ ```
64
+
65
+ - ### Usage
66
+
67
+ ```typescript
68
+ import { toggleTheme, getCurrentTheme } from '@cruxext/theme';
69
+ import { Button } from '@cruxkit/button';
70
+
71
+ <Button
72
+ onClick={ () => toggleTheme() }
73
+ leftIcon={{name: getCurrentTheme() === 'light' ? 'sun' : 'moon' }}
74
+ >
75
+ Toggle Theme
76
+ </Button>
91
77
  ```
92
78
 
93
79
  <br>
@@ -95,60 +81,34 @@
95
81
 
96
82
  - ## Documentation πŸ“‘
97
83
 
98
-
99
84
  - ### API ⛓️
100
85
 
101
- - #### `createThemeExtension(config?: ThemeConfig): ClientExtension`
102
- > Initializes the theme extension for your CruxJS application. Call this during your app bootstrap.
86
+ - #### Main-Functions
103
87
 
104
88
  ```typescript
105
- import { createThemeExtension } from '@cruxext/theme';
89
+ export function themeExtension(config?: ThemeConfig) : ClientExtension
106
90
 
107
- const themeExt = createThemeExtension({
108
- default: 'light',
109
- available: ['light', 'dark', 'auto']
110
- });
91
+ export const getThemeManager = () => themeManager;
92
+ export const setTheme = (themeName: string) => getThemeManager().setTheme(themeName);
93
+ export const toggleTheme = () => getThemeManager().toggleTheme();
94
+ export const getCurrentTheme = () => getThemeManager().getTheme();
111
95
  ```
112
96
 
113
- - #### `setTheme(themeName: string): void`
114
-
115
- > Sets the active theme to the specified name. Must be one of the available themes defined in config.
97
+ - #### Toast Class Methods
116
98
 
117
99
  ```typescript
118
- import { setTheme } from '@cruxext/theme';
119
-
120
- setTheme('dark');
100
+ getTheme () : string
101
+ setTheme (themeName: string) : void
102
+ toggleTheme () : void
121
103
  ```
122
104
 
123
- - #### `toggleTheme(): void`
124
-
125
- > Toggles between available themes. Cycles through the first non-current available theme.
105
+ - #### Types
126
106
 
127
107
  ```typescript
128
- import { toggleTheme } from '@cruxext/theme';
129
-
130
- toggleTheme();
131
- ```
132
-
133
- - #### `getCurrentTheme(): string`
134
-
135
- > Returns the name of the currently active theme.
136
-
137
- ```typescript
138
- import { getCurrentTheme } from '@cruxext/theme';
139
-
140
- const current = getCurrentTheme(); // 'light' | 'dark' | etc.
141
- ```
142
-
143
- - #### `getThemeManager(): ThemeManager`
144
-
145
- > Returns the ThemeManager instance for advanced usage and direct signal access.
146
-
147
- ```typescript
148
- import { getThemeManager, signal } from '@cruxext/theme';
149
-
150
- const manager = getThemeManager();
151
- const themeSignal = manager.signal; // reactive signal
108
+ export interface ThemeConfig {
109
+ default : string;
110
+ available : string[];
111
+ }
152
112
  ```
153
113
 
154
114
  <div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> </div>
@@ -156,14 +116,12 @@
156
116
 
157
117
  - ### Related πŸ”—
158
118
 
159
- - ##### [@minejs/signals](https://github.com/minejs-org/signals)
160
- > Reactive signals library used for theme state management
161
-
119
+ - ##### [@minejs/jsx](https://github.com/minejs-org/jsx)
162
120
  - ##### [@minejs/store](https://github.com/minejs-org/store)
163
- > Persistent storage solution for maintaining theme preferences
121
+ - ##### [@minejs/signals](https://github.com/minejs-org/signals)
164
122
 
165
- - ##### [@cruxkit/core](https://github.com/cruxkit/core)
166
- > Core UI component library that works seamlessly with theming
123
+ - ##### [@cruxjs/client](https://github.com/cruxjs-org/client)
124
+ - ##### [@cruxjs/app](https://github.com/cruxjs-org/app)
167
125
 
168
126
  <!-- β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β• -->
169
127
 
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var store=require('@minejs/store'),signals=require('@minejs/signals');var i=class{constructor(e){this.config=e;let t=new store.Storage({type:"local"});this.store=store.createStore({state:{theme:e.default},persist:true,storage:t,storageKey:"app:theme"}),this.signal=this.store.state.theme;let a=t.get("app:theme:theme")||e.default;this.signal.set(a),this.applyTheme(a),signals.effect(()=>{let n=this.signal?.();n&&this.applyTheme(n),console.log(`[ThemeManager] Reactive effect applied theme: ${n}`);}),signals.effect(()=>{let n=window.matchMedia("(prefers-color-scheme: dark)"),h=g=>{t.get("app:theme:theme")||this.signal.set(g.matches?"dark":"light");};return n.addEventListener("change",h),()=>n.removeEventListener("change",h)});}getTheme(){return this.signal?.()??this.config.default??"light"}setTheme(e){if(!this.config.available.includes(e)){console.warn(`[ThemeManager] Unsupported theme: ${e}`);return}this.signal&&(this.signal.set(e),console.log(`[ThemeManager] Theme set to: ${e}`));}toggleTheme(){if(!this.signal)return;let e=this.signal(),t=this.config.available.find(r=>r!==e);t&&(this.signal.set(t),console.log(`[ThemeManager] Theme toggled to: ${t}`));}applyTheme(e){(document.documentElement||document.rootElement).setAttribute("data-theme",e),console.log(`[ThemeManager] Applied theme: ${e}`);}};var m,s=()=>m,E=o=>s().setTheme(o),x=()=>s().toggleTheme(),y=()=>s().getTheme();function C(o){return {name:"ThemeExtension",onBoot:e=>{o&&(e.cconfig.theme={...e.cconfig.theme,...o}),e.cconfig.theme||(e.cconfig.theme={default:"dark",available:["dark","light"]}),m=new i({default:e.cconfig.theme.default,available:e.cconfig.theme.available});}}}exports.ThemeManager=i;exports.createThemeExtension=C;exports.getCurrentTheme=y;exports.getThemeManager=s;exports.setTheme=E;exports.toggleTheme=x;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';var store=require('@minejs/store'),signals=require('@minejs/signals');var i=class{constructor(e){this.config=e;let t=new store.Storage({type:"local"});this.store=store.createStore({state:{theme:e.default},persist:true,storage:t,storageKey:"app:theme"}),this.signal=this.store.state.theme;let a=t.get("app:theme:theme")||e.default;this.signal.set(a),this.applyTheme(a),signals.effect(()=>{let n=this.signal?.();n&&this.applyTheme(n),console.log(`[ThemeManager] Reactive effect applied theme: ${n}`);}),signals.effect(()=>{let n=window.matchMedia("(prefers-color-scheme: dark)"),h=g=>{t.get("app:theme:theme")||this.signal.set(g.matches?"dark":"light");};return n.addEventListener("change",h),()=>n.removeEventListener("change",h)});}getTheme(){return this.signal?.()??this.config.default??"light"}setTheme(e){if(!this.config.available.includes(e)){console.warn(`[ThemeManager] Unsupported theme: ${e}`);return}this.signal&&(this.signal.set(e),console.log(`[ThemeManager] Theme set to: ${e}`));}toggleTheme(){if(!this.signal)return;let e=this.signal(),t=this.config.available.find(r=>r!==e);t&&(this.signal.set(t),console.log(`[ThemeManager] Theme toggled to: ${t}`));}applyTheme(e){(document.documentElement||document.rootElement).setAttribute("data-theme",e),console.log(`[ThemeManager] Applied theme: ${e}`);}};var m;function E(o){return {name:"ThemeExtension",onBoot:e=>{o&&(e.cconfig.theme={...e.cconfig.theme,...o}),e.cconfig.theme||(e.cconfig.theme={default:"dark",available:["dark","light"]}),m=new i({default:e.cconfig.theme.default,available:e.cconfig.theme.available});}}}var s=()=>m,x=o=>s().setTheme(o),y=()=>s().toggleTheme(),C=()=>s().getTheme();exports.ThemeManager=i;exports.getCurrentTheme=C;exports.getThemeManager=s;exports.setTheme=x;exports.themeExtension=E;exports.toggleTheme=y;//# sourceMappingURL=index.cjs.map
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mod/theme_manager.ts","../src/index.ts"],"names":["ThemeManager","config","storage","Storage","createStore","initialTheme","effect","currentTheme","mediaQuery","handleChange","e","themeName","nextTheme","t","themeManager","getThemeManager","setTheme","toggleTheme","getCurrentTheme","createThemeExtension","ctx"],"mappings":"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","file":"index.cjs","sourcesContent":["// src/mod/theme_manager.ts\r\n//\r\n// Made with ❀️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import { ThemeConfig } from \"../types\";\r\n import { createStore, Storage } from '@minejs/store';\r\n import { signal, effect } from '@minejs/signals';\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n export class ThemeManager {\r\n\r\n // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ INIT ──────────────────────────────┐\r\n\r\n public store: ReturnType<typeof createStore>;\r\n public signal: ReturnType<typeof signal<string>>;\r\n\r\n constructor(public config: ThemeConfig) {\r\n\r\n const storage = new Storage({ type: 'local' });\r\n\r\n this.store = createStore({\r\n state: {\r\n theme: config.default\r\n },\r\n persist: true,\r\n storage,\r\n storageKey: 'app:theme'\r\n });\r\n\r\n this.signal = this.store.state.theme;\r\n\r\n // Set initial theme on body\r\n const storedTheme = storage.get('app:theme:theme') as string | null;\r\n const initialTheme = storedTheme || config.default;\r\n this.signal.set(initialTheme);\r\n this.applyTheme(initialTheme);\r\n\r\n // Setup reactive effect: apply theme whenever signal changes\r\n effect(() => {\r\n const currentTheme = this.signal?.();\r\n if (currentTheme) {\r\n this.applyTheme(currentTheme);\r\n }\r\n\r\n console.log(`[ThemeManager] Reactive effect applied theme: ${currentTheme}`);\r\n });\r\n\r\n // Listen for system theme changes\r\n effect(() => {\r\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\r\n\r\n const handleChange = (e: MediaQueryListEvent) => {\r\n if (!storage.get('app:theme:theme')) this.signal.set(e.matches ? 'dark' : 'light');\r\n };\r\n\r\n mediaQuery.addEventListener('change', handleChange);\r\n return () => mediaQuery.removeEventListener('change', handleChange);\r\n });\r\n }\r\n\r\n // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\r\n\r\n\r\n // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ MAIN ──────────────────────────────┐\r\n\r\n getTheme(): string {\r\n return this.signal?.() ?? this.config.default ?? 'light';\r\n }\r\n\r\n setTheme(themeName: string): void {\r\n if (!this.config.available.includes(themeName)) {\r\n console.warn(`[ThemeManager] Unsupported theme: ${themeName}`);\r\n return;\r\n }\r\n\r\n // Update signal directly - effect will handle DOM updates\r\n if (this.signal) {\r\n this.signal.set(themeName);\r\n console.log(`[ThemeManager] Theme set to: ${themeName}`);\r\n }\r\n }\r\n\r\n toggleTheme(): void {\r\n if (!this.signal) return;\r\n const currentTheme = this.signal();\r\n const nextTheme = this.config.available.find(t => t !== currentTheme);\r\n if (nextTheme) {\r\n this.signal.set(nextTheme);\r\n console.log(`[ThemeManager] Theme toggled to: ${nextTheme}`);\r\n }\r\n }\r\n\r\n // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\r\n\r\n\r\n // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ HELP ──────────────────────────────┐\r\n\r\n private applyTheme(themeName: string): void {\r\n const htmlEl = document.documentElement || document.rootElement;\r\n htmlEl.setAttribute('data-theme', themeName);\r\n console.log(`[ThemeManager] Applied theme: ${themeName}`);\r\n }\r\n\r\n // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\r\n\r\n };\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\r\n","// src/index.ts\r\n//\r\n// Made with ❀️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import { ClientExtension, ExtensionContext } from \"@cruxjs/base\";\r\n import { ThemeConfig } from \"./types\";\r\n import { ThemeManager } from \"./mod/theme_manager\";\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ MAIN ════════════════════════════════════════╗\r\n\r\n // Theme manager instance\r\n let themeManager : ThemeManager;\r\n\r\n // Exported theme functions\r\n export const getThemeManager = () => themeManager;\r\n export const setTheme = (themeName: string) => getThemeManager().setTheme(themeName);\r\n export const toggleTheme = () => getThemeManager().toggleTheme();\r\n export const getCurrentTheme = () => getThemeManager().getTheme();\r\n\r\n // Theme extension\r\n export function createThemeExtension(config?: ThemeConfig) : ClientExtension {\r\n return {\r\n name : 'ThemeExtension',\r\n\r\n onBoot: (ctx: ExtensionContext) => {\r\n // if config provided, merge into client config\r\n if (config) {\r\n ctx.cconfig.theme = {\r\n ...ctx.cconfig.theme,\r\n ...config\r\n };\r\n }\r\n\r\n // if no theme config provided, set default\r\n if (!ctx.cconfig.theme) {\r\n ctx.cconfig.theme = {\r\n default : 'dark',\r\n available : ['dark', 'light']\r\n };\r\n }\r\n\r\n // create theme manager instance\r\n themeManager = new ThemeManager({\r\n default : ctx.cconfig.theme!.default,\r\n available : ctx.cconfig.theme!.available\r\n });\r\n }\r\n };\r\n };\r\n\r\n // export\r\n export * from \"./types\";\r\n export { ThemeManager };\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•"]}
1
+ {"version":3,"sources":["../src/mod/manager.ts","../src/index.ts"],"names":["ThemeManager","config","storage","Storage","createStore","initialTheme","effect","currentTheme","mediaQuery","handleChange","e","themeName","nextTheme","t","themeManager","themeExtension","ctx","getThemeManager","setTheme","toggleTheme","getCurrentTheme"],"mappings":"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","file":"index.cjs","sourcesContent":["// src/mod/manager.ts\r\n//\r\n// Made with ❀️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import { ThemeConfig } from \"../types\";\r\n import { createStore, Storage } from '@minejs/store';\r\n import { signal, effect } from '@minejs/signals';\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n export class ThemeManager {\r\n\r\n // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ INIT ──────────────────────────────┐\r\n\r\n public store: ReturnType<typeof createStore>;\r\n public signal: ReturnType<typeof signal<string>>;\r\n\r\n constructor(public config: ThemeConfig) {\r\n\r\n const storage = new Storage({ type: 'local' });\r\n\r\n this.store = createStore({\r\n state: {\r\n theme: config.default\r\n },\r\n persist: true,\r\n storage,\r\n storageKey: 'app:theme'\r\n });\r\n\r\n this.signal = this.store.state.theme;\r\n\r\n // Set initial theme on body\r\n const storedTheme = storage.get('app:theme:theme') as string | null;\r\n const initialTheme = storedTheme || config.default;\r\n this.signal.set(initialTheme);\r\n this.applyTheme(initialTheme);\r\n\r\n // Setup reactive effect: apply theme whenever signal changes\r\n effect(() => {\r\n const currentTheme = this.signal?.();\r\n if (currentTheme) {\r\n this.applyTheme(currentTheme);\r\n }\r\n\r\n console.log(`[ThemeManager] Reactive effect applied theme: ${currentTheme}`);\r\n });\r\n\r\n // Listen for system theme changes\r\n effect(() => {\r\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\r\n\r\n const handleChange = (e: MediaQueryListEvent) => {\r\n if (!storage.get('app:theme:theme')) this.signal.set(e.matches ? 'dark' : 'light');\r\n };\r\n\r\n mediaQuery.addEventListener('change', handleChange);\r\n return () => mediaQuery.removeEventListener('change', handleChange);\r\n });\r\n }\r\n\r\n // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\r\n\r\n\r\n // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ MAIN ──────────────────────────────┐\r\n\r\n getTheme(): string {\r\n return this.signal?.() ?? this.config.default ?? 'light';\r\n }\r\n\r\n setTheme(themeName: string): void {\r\n if (!this.config.available.includes(themeName)) {\r\n console.warn(`[ThemeManager] Unsupported theme: ${themeName}`);\r\n return;\r\n }\r\n\r\n // Update signal directly - effect will handle DOM updates\r\n if (this.signal) {\r\n this.signal.set(themeName);\r\n console.log(`[ThemeManager] Theme set to: ${themeName}`);\r\n }\r\n }\r\n\r\n toggleTheme(): void {\r\n if (!this.signal) return;\r\n const currentTheme = this.signal();\r\n const nextTheme = this.config.available.find(t => t !== currentTheme);\r\n if (nextTheme) {\r\n this.signal.set(nextTheme);\r\n console.log(`[ThemeManager] Theme toggled to: ${nextTheme}`);\r\n }\r\n }\r\n\r\n // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\r\n\r\n\r\n // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ HELP ──────────────────────────────┐\r\n\r\n private applyTheme(themeName: string): void {\r\n const htmlEl = document.documentElement || document.rootElement;\r\n htmlEl.setAttribute('data-theme', themeName);\r\n console.log(`[ThemeManager] Applied theme: ${themeName}`);\r\n }\r\n\r\n // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\r\n\r\n };\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\r\n","// src/index.ts\r\n//\r\n// Made with ❀️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import { ClientExtension, ExtensionContext } from \"@cruxjs/base\";\r\n import { ThemeConfig } from \"./types\";\r\n import { ThemeManager } from \"./mod/manager\";\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ INIT ════════════════════════════════════════╗\r\n\r\n // Theme manager instance\r\n let themeManager : ThemeManager;\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n /**\r\n * Create a theme extension\r\n * @param config Theme configuration\r\n * @returns Theme extension\r\n */\r\n export function themeExtension(config?: ThemeConfig) : ClientExtension {\r\n return {\r\n name : 'ThemeExtension',\r\n\r\n onBoot: (ctx: ExtensionContext) => {\r\n // if config provided, merge into client config\r\n if (config) {\r\n ctx.cconfig.theme = {\r\n ...ctx.cconfig.theme,\r\n ...config\r\n };\r\n }\r\n\r\n // if no theme config provided, set default\r\n if (!ctx.cconfig.theme) {\r\n ctx.cconfig.theme = {\r\n default : 'dark',\r\n available : ['dark', 'light']\r\n };\r\n }\r\n\r\n // create theme manager instance\r\n themeManager = new ThemeManager({\r\n default : ctx.cconfig.theme!.default,\r\n available : ctx.cconfig.theme!.available\r\n });\r\n }\r\n };\r\n };\r\n\r\n // Exported theme functions\r\n export const getThemeManager = () => themeManager;\r\n export const setTheme = (themeName: string) => getThemeManager().setTheme(themeName);\r\n export const toggleTheme = () => getThemeManager().toggleTheme();\r\n export const getCurrentTheme = () => getThemeManager().getTheme();\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ ════ ════════════════════════════════════════╗\r\n\r\n export * from \"./types\";\r\n export { ThemeManager };\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•"]}
package/dist/index.d.cts CHANGED
@@ -14,10 +14,15 @@ declare class ThemeManager {
14
14
  private applyTheme;
15
15
  }
16
16
 
17
+ /**
18
+ * Create a theme extension
19
+ * @param config Theme configuration
20
+ * @returns Theme extension
21
+ */
22
+ declare function themeExtension(config?: ThemeConfig): ClientExtension;
17
23
  declare const getThemeManager: () => ThemeManager;
18
24
  declare const setTheme: (themeName: string) => void;
19
25
  declare const toggleTheme: () => void;
20
26
  declare const getCurrentTheme: () => string;
21
- declare function createThemeExtension(config?: ThemeConfig): ClientExtension;
22
27
 
23
- export { ThemeManager, createThemeExtension, getCurrentTheme, getThemeManager, setTheme, toggleTheme };
28
+ export { ThemeManager, getCurrentTheme, getThemeManager, setTheme, themeExtension, toggleTheme };
package/dist/index.d.ts CHANGED
@@ -14,10 +14,15 @@ declare class ThemeManager {
14
14
  private applyTheme;
15
15
  }
16
16
 
17
+ /**
18
+ * Create a theme extension
19
+ * @param config Theme configuration
20
+ * @returns Theme extension
21
+ */
22
+ declare function themeExtension(config?: ThemeConfig): ClientExtension;
17
23
  declare const getThemeManager: () => ThemeManager;
18
24
  declare const setTheme: (themeName: string) => void;
19
25
  declare const toggleTheme: () => void;
20
26
  declare const getCurrentTheme: () => string;
21
- declare function createThemeExtension(config?: ThemeConfig): ClientExtension;
22
27
 
23
- export { ThemeManager, createThemeExtension, getCurrentTheme, getThemeManager, setTheme, toggleTheme };
28
+ export { ThemeManager, getCurrentTheme, getThemeManager, setTheme, themeExtension, toggleTheme };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import {Storage,createStore}from'@minejs/store';import {effect}from'@minejs/signals';var i=class{constructor(e){this.config=e;let t=new Storage({type:"local"});this.store=createStore({state:{theme:e.default},persist:true,storage:t,storageKey:"app:theme"}),this.signal=this.store.state.theme;let a=t.get("app:theme:theme")||e.default;this.signal.set(a),this.applyTheme(a),effect(()=>{let n=this.signal?.();n&&this.applyTheme(n),console.log(`[ThemeManager] Reactive effect applied theme: ${n}`);}),effect(()=>{let n=window.matchMedia("(prefers-color-scheme: dark)"),h=g=>{t.get("app:theme:theme")||this.signal.set(g.matches?"dark":"light");};return n.addEventListener("change",h),()=>n.removeEventListener("change",h)});}getTheme(){return this.signal?.()??this.config.default??"light"}setTheme(e){if(!this.config.available.includes(e)){console.warn(`[ThemeManager] Unsupported theme: ${e}`);return}this.signal&&(this.signal.set(e),console.log(`[ThemeManager] Theme set to: ${e}`));}toggleTheme(){if(!this.signal)return;let e=this.signal(),t=this.config.available.find(r=>r!==e);t&&(this.signal.set(t),console.log(`[ThemeManager] Theme toggled to: ${t}`));}applyTheme(e){(document.documentElement||document.rootElement).setAttribute("data-theme",e),console.log(`[ThemeManager] Applied theme: ${e}`);}};var m,s=()=>m,E=o=>s().setTheme(o),x=()=>s().toggleTheme(),y=()=>s().getTheme();function C(o){return {name:"ThemeExtension",onBoot:e=>{o&&(e.cconfig.theme={...e.cconfig.theme,...o}),e.cconfig.theme||(e.cconfig.theme={default:"dark",available:["dark","light"]}),m=new i({default:e.cconfig.theme.default,available:e.cconfig.theme.available});}}}export{i as ThemeManager,C as createThemeExtension,y as getCurrentTheme,s as getThemeManager,E as setTheme,x as toggleTheme};//# sourceMappingURL=index.js.map
1
+ import {Storage,createStore}from'@minejs/store';import {effect}from'@minejs/signals';var i=class{constructor(e){this.config=e;let t=new Storage({type:"local"});this.store=createStore({state:{theme:e.default},persist:true,storage:t,storageKey:"app:theme"}),this.signal=this.store.state.theme;let a=t.get("app:theme:theme")||e.default;this.signal.set(a),this.applyTheme(a),effect(()=>{let n=this.signal?.();n&&this.applyTheme(n),console.log(`[ThemeManager] Reactive effect applied theme: ${n}`);}),effect(()=>{let n=window.matchMedia("(prefers-color-scheme: dark)"),h=g=>{t.get("app:theme:theme")||this.signal.set(g.matches?"dark":"light");};return n.addEventListener("change",h),()=>n.removeEventListener("change",h)});}getTheme(){return this.signal?.()??this.config.default??"light"}setTheme(e){if(!this.config.available.includes(e)){console.warn(`[ThemeManager] Unsupported theme: ${e}`);return}this.signal&&(this.signal.set(e),console.log(`[ThemeManager] Theme set to: ${e}`));}toggleTheme(){if(!this.signal)return;let e=this.signal(),t=this.config.available.find(r=>r!==e);t&&(this.signal.set(t),console.log(`[ThemeManager] Theme toggled to: ${t}`));}applyTheme(e){(document.documentElement||document.rootElement).setAttribute("data-theme",e),console.log(`[ThemeManager] Applied theme: ${e}`);}};var m;function E(o){return {name:"ThemeExtension",onBoot:e=>{o&&(e.cconfig.theme={...e.cconfig.theme,...o}),e.cconfig.theme||(e.cconfig.theme={default:"dark",available:["dark","light"]}),m=new i({default:e.cconfig.theme.default,available:e.cconfig.theme.available});}}}var s=()=>m,x=o=>s().setTheme(o),y=()=>s().toggleTheme(),C=()=>s().getTheme();export{i as ThemeManager,C as getCurrentTheme,s as getThemeManager,x as setTheme,E as themeExtension,y as toggleTheme};//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mod/theme_manager.ts","../src/index.ts"],"names":["ThemeManager","config","storage","Storage","createStore","initialTheme","effect","currentTheme","mediaQuery","handleChange","e","themeName","nextTheme","t","themeManager","getThemeManager","setTheme","toggleTheme","getCurrentTheme","createThemeExtension","ctx"],"mappings":"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","file":"index.js","sourcesContent":["// src/mod/theme_manager.ts\r\n//\r\n// Made with ❀️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import { ThemeConfig } from \"../types\";\r\n import { createStore, Storage } from '@minejs/store';\r\n import { signal, effect } from '@minejs/signals';\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n export class ThemeManager {\r\n\r\n // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ INIT ──────────────────────────────┐\r\n\r\n public store: ReturnType<typeof createStore>;\r\n public signal: ReturnType<typeof signal<string>>;\r\n\r\n constructor(public config: ThemeConfig) {\r\n\r\n const storage = new Storage({ type: 'local' });\r\n\r\n this.store = createStore({\r\n state: {\r\n theme: config.default\r\n },\r\n persist: true,\r\n storage,\r\n storageKey: 'app:theme'\r\n });\r\n\r\n this.signal = this.store.state.theme;\r\n\r\n // Set initial theme on body\r\n const storedTheme = storage.get('app:theme:theme') as string | null;\r\n const initialTheme = storedTheme || config.default;\r\n this.signal.set(initialTheme);\r\n this.applyTheme(initialTheme);\r\n\r\n // Setup reactive effect: apply theme whenever signal changes\r\n effect(() => {\r\n const currentTheme = this.signal?.();\r\n if (currentTheme) {\r\n this.applyTheme(currentTheme);\r\n }\r\n\r\n console.log(`[ThemeManager] Reactive effect applied theme: ${currentTheme}`);\r\n });\r\n\r\n // Listen for system theme changes\r\n effect(() => {\r\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\r\n\r\n const handleChange = (e: MediaQueryListEvent) => {\r\n if (!storage.get('app:theme:theme')) this.signal.set(e.matches ? 'dark' : 'light');\r\n };\r\n\r\n mediaQuery.addEventListener('change', handleChange);\r\n return () => mediaQuery.removeEventListener('change', handleChange);\r\n });\r\n }\r\n\r\n // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\r\n\r\n\r\n // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ MAIN ──────────────────────────────┐\r\n\r\n getTheme(): string {\r\n return this.signal?.() ?? this.config.default ?? 'light';\r\n }\r\n\r\n setTheme(themeName: string): void {\r\n if (!this.config.available.includes(themeName)) {\r\n console.warn(`[ThemeManager] Unsupported theme: ${themeName}`);\r\n return;\r\n }\r\n\r\n // Update signal directly - effect will handle DOM updates\r\n if (this.signal) {\r\n this.signal.set(themeName);\r\n console.log(`[ThemeManager] Theme set to: ${themeName}`);\r\n }\r\n }\r\n\r\n toggleTheme(): void {\r\n if (!this.signal) return;\r\n const currentTheme = this.signal();\r\n const nextTheme = this.config.available.find(t => t !== currentTheme);\r\n if (nextTheme) {\r\n this.signal.set(nextTheme);\r\n console.log(`[ThemeManager] Theme toggled to: ${nextTheme}`);\r\n }\r\n }\r\n\r\n // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\r\n\r\n\r\n // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ HELP ──────────────────────────────┐\r\n\r\n private applyTheme(themeName: string): void {\r\n const htmlEl = document.documentElement || document.rootElement;\r\n htmlEl.setAttribute('data-theme', themeName);\r\n console.log(`[ThemeManager] Applied theme: ${themeName}`);\r\n }\r\n\r\n // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\r\n\r\n };\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\r\n","// src/index.ts\r\n//\r\n// Made with ❀️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import { ClientExtension, ExtensionContext } from \"@cruxjs/base\";\r\n import { ThemeConfig } from \"./types\";\r\n import { ThemeManager } from \"./mod/theme_manager\";\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ MAIN ════════════════════════════════════════╗\r\n\r\n // Theme manager instance\r\n let themeManager : ThemeManager;\r\n\r\n // Exported theme functions\r\n export const getThemeManager = () => themeManager;\r\n export const setTheme = (themeName: string) => getThemeManager().setTheme(themeName);\r\n export const toggleTheme = () => getThemeManager().toggleTheme();\r\n export const getCurrentTheme = () => getThemeManager().getTheme();\r\n\r\n // Theme extension\r\n export function createThemeExtension(config?: ThemeConfig) : ClientExtension {\r\n return {\r\n name : 'ThemeExtension',\r\n\r\n onBoot: (ctx: ExtensionContext) => {\r\n // if config provided, merge into client config\r\n if (config) {\r\n ctx.cconfig.theme = {\r\n ...ctx.cconfig.theme,\r\n ...config\r\n };\r\n }\r\n\r\n // if no theme config provided, set default\r\n if (!ctx.cconfig.theme) {\r\n ctx.cconfig.theme = {\r\n default : 'dark',\r\n available : ['dark', 'light']\r\n };\r\n }\r\n\r\n // create theme manager instance\r\n themeManager = new ThemeManager({\r\n default : ctx.cconfig.theme!.default,\r\n available : ctx.cconfig.theme!.available\r\n });\r\n }\r\n };\r\n };\r\n\r\n // export\r\n export * from \"./types\";\r\n export { ThemeManager };\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•"]}
1
+ {"version":3,"sources":["../src/mod/manager.ts","../src/index.ts"],"names":["ThemeManager","config","storage","Storage","createStore","initialTheme","effect","currentTheme","mediaQuery","handleChange","e","themeName","nextTheme","t","themeManager","themeExtension","ctx","getThemeManager","setTheme","toggleTheme","getCurrentTheme"],"mappings":"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","file":"index.js","sourcesContent":["// src/mod/manager.ts\r\n//\r\n// Made with ❀️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import { ThemeConfig } from \"../types\";\r\n import { createStore, Storage } from '@minejs/store';\r\n import { signal, effect } from '@minejs/signals';\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n export class ThemeManager {\r\n\r\n // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ INIT ──────────────────────────────┐\r\n\r\n public store: ReturnType<typeof createStore>;\r\n public signal: ReturnType<typeof signal<string>>;\r\n\r\n constructor(public config: ThemeConfig) {\r\n\r\n const storage = new Storage({ type: 'local' });\r\n\r\n this.store = createStore({\r\n state: {\r\n theme: config.default\r\n },\r\n persist: true,\r\n storage,\r\n storageKey: 'app:theme'\r\n });\r\n\r\n this.signal = this.store.state.theme;\r\n\r\n // Set initial theme on body\r\n const storedTheme = storage.get('app:theme:theme') as string | null;\r\n const initialTheme = storedTheme || config.default;\r\n this.signal.set(initialTheme);\r\n this.applyTheme(initialTheme);\r\n\r\n // Setup reactive effect: apply theme whenever signal changes\r\n effect(() => {\r\n const currentTheme = this.signal?.();\r\n if (currentTheme) {\r\n this.applyTheme(currentTheme);\r\n }\r\n\r\n console.log(`[ThemeManager] Reactive effect applied theme: ${currentTheme}`);\r\n });\r\n\r\n // Listen for system theme changes\r\n effect(() => {\r\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\r\n\r\n const handleChange = (e: MediaQueryListEvent) => {\r\n if (!storage.get('app:theme:theme')) this.signal.set(e.matches ? 'dark' : 'light');\r\n };\r\n\r\n mediaQuery.addEventListener('change', handleChange);\r\n return () => mediaQuery.removeEventListener('change', handleChange);\r\n });\r\n }\r\n\r\n // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\r\n\r\n\r\n // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ MAIN ──────────────────────────────┐\r\n\r\n getTheme(): string {\r\n return this.signal?.() ?? this.config.default ?? 'light';\r\n }\r\n\r\n setTheme(themeName: string): void {\r\n if (!this.config.available.includes(themeName)) {\r\n console.warn(`[ThemeManager] Unsupported theme: ${themeName}`);\r\n return;\r\n }\r\n\r\n // Update signal directly - effect will handle DOM updates\r\n if (this.signal) {\r\n this.signal.set(themeName);\r\n console.log(`[ThemeManager] Theme set to: ${themeName}`);\r\n }\r\n }\r\n\r\n toggleTheme(): void {\r\n if (!this.signal) return;\r\n const currentTheme = this.signal();\r\n const nextTheme = this.config.available.find(t => t !== currentTheme);\r\n if (nextTheme) {\r\n this.signal.set(nextTheme);\r\n console.log(`[ThemeManager] Theme toggled to: ${nextTheme}`);\r\n }\r\n }\r\n\r\n // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\r\n\r\n\r\n // β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ HELP ──────────────────────────────┐\r\n\r\n private applyTheme(themeName: string): void {\r\n const htmlEl = document.documentElement || document.rootElement;\r\n htmlEl.setAttribute('data-theme', themeName);\r\n console.log(`[ThemeManager] Applied theme: ${themeName}`);\r\n }\r\n\r\n // β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\r\n\r\n };\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\r\n","// src/index.ts\r\n//\r\n// Made with ❀️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import { ClientExtension, ExtensionContext } from \"@cruxjs/base\";\r\n import { ThemeConfig } from \"./types\";\r\n import { ThemeManager } from \"./mod/manager\";\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ INIT ════════════════════════════════════════╗\r\n\r\n // Theme manager instance\r\n let themeManager : ThemeManager;\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n /**\r\n * Create a theme extension\r\n * @param config Theme configuration\r\n * @returns Theme extension\r\n */\r\n export function themeExtension(config?: ThemeConfig) : ClientExtension {\r\n return {\r\n name : 'ThemeExtension',\r\n\r\n onBoot: (ctx: ExtensionContext) => {\r\n // if config provided, merge into client config\r\n if (config) {\r\n ctx.cconfig.theme = {\r\n ...ctx.cconfig.theme,\r\n ...config\r\n };\r\n }\r\n\r\n // if no theme config provided, set default\r\n if (!ctx.cconfig.theme) {\r\n ctx.cconfig.theme = {\r\n default : 'dark',\r\n available : ['dark', 'light']\r\n };\r\n }\r\n\r\n // create theme manager instance\r\n themeManager = new ThemeManager({\r\n default : ctx.cconfig.theme!.default,\r\n available : ctx.cconfig.theme!.available\r\n });\r\n }\r\n };\r\n };\r\n\r\n // Exported theme functions\r\n export const getThemeManager = () => themeManager;\r\n export const setTheme = (themeName: string) => getThemeManager().setTheme(themeName);\r\n export const toggleTheme = () => getThemeManager().toggleTheme();\r\n export const getCurrentTheme = () => getThemeManager().getTheme();\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ ════ ════════════════════════════════════════╗\r\n\r\n export * from \"./types\";\r\n export { ThemeManager };\r\n\r\n// β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cruxext/theme",
3
- "version": "0.0.7",
4
- "description": "Lightweight reactive theme manager for CruxJS with dark/light mode support and persistent storage.",
3
+ "version": "0.0.8",
4
+ "description": "A lightweight, reactive theme management solution, built for @cruxjs ecosystem.",
5
5
  "keywords": ["cruxjs", "extension", "theme"],
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/cruxext-org/theme#readme",
@@ -48,12 +48,14 @@
48
48
  "@eslint/js": "^9.39.2",
49
49
  "@stylistic/eslint-plugin": "^5.7.0",
50
50
  "@types/bun": "^1.3.6",
51
+ "@types/jsdom": "^27.0.0",
51
52
  "@types/node": "^20.19.30",
52
53
  "bun-plugin-dts": "^0.3.0",
53
54
  "bun-types": "^1.3.6",
55
+ "jsdom": "^27.4.0",
54
56
  "ts-node": "^10.9.2",
55
57
  "tsup": "^8.5.1",
56
58
  "typescript": "^5.9.3",
57
- "typescript-eslint": "^8.53.0"
59
+ "typescript-eslint": "^8.53.1"
58
60
  }
59
61
  }