@cruxext/theme 0.0.6 → 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 +49 -91
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +10 -8
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.
|
|
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
|
|
29
|
+
> A lightweight, reactive theme management solution, built for [`@cruxjs`](https://github.com/cruxjs-org) ecosystem.
|
|
29
30
|
|
|
30
31
|
- #### When ?
|
|
31
|
-
>
|
|
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
|
-
- ###
|
|
49
|
+
- ### Setup
|
|
61
50
|
|
|
62
51
|
```typescript
|
|
63
|
-
|
|
64
|
-
import {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
- ####
|
|
102
|
-
> Initializes the theme extension for your CruxJS application. Call this during your app bootstrap.
|
|
86
|
+
- #### Main-Functions
|
|
103
87
|
|
|
104
88
|
```typescript
|
|
105
|
-
|
|
89
|
+
export function themeExtension(config?: ThemeConfig) : ClientExtension
|
|
106
90
|
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
- ####
|
|
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
|
-
|
|
119
|
-
|
|
120
|
-
|
|
100
|
+
getTheme () : string
|
|
101
|
+
setTheme (themeName: string) : void
|
|
102
|
+
toggleTheme () : void
|
|
121
103
|
```
|
|
122
104
|
|
|
123
|
-
- ####
|
|
124
|
-
|
|
125
|
-
> Toggles between available themes. Cycles through the first non-current available theme.
|
|
105
|
+
- #### Types
|
|
126
106
|
|
|
127
107
|
```typescript
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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/
|
|
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
|
-
|
|
121
|
+
- ##### [@minejs/signals](https://github.com/minejs-org/signals)
|
|
164
122
|
|
|
165
|
-
- ##### [@
|
|
166
|
-
|
|
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')
|
|
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
|
package/dist/index.cjs.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.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/client\";\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
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ThemeConfig, ClientExtension } from '@cruxjs/
|
|
2
|
-
export { ThemeConfig } from '@cruxjs/
|
|
1
|
+
import { ThemeConfig, ClientExtension } from '@cruxjs/base';
|
|
2
|
+
export { ThemeConfig } from '@cruxjs/base';
|
|
3
3
|
import { createStore } from '@minejs/store';
|
|
4
4
|
import { signal } from '@minejs/signals';
|
|
5
5
|
|
|
@@ -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,
|
|
28
|
+
export { ThemeManager, getCurrentTheme, getThemeManager, setTheme, themeExtension, toggleTheme };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ThemeConfig, ClientExtension } from '@cruxjs/
|
|
2
|
-
export { ThemeConfig } from '@cruxjs/
|
|
1
|
+
import { ThemeConfig, ClientExtension } from '@cruxjs/base';
|
|
2
|
+
export { ThemeConfig } from '@cruxjs/base';
|
|
3
3
|
import { createStore } from '@minejs/store';
|
|
4
4
|
import { signal } from '@minejs/signals';
|
|
5
5
|
|
|
@@ -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,
|
|
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';
|
|
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/client\";\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.
|
|
4
|
-
"description": "
|
|
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",
|
|
@@ -40,20 +40,22 @@
|
|
|
40
40
|
"bun": "^1.3.3"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@cruxjs/
|
|
43
|
+
"@cruxjs/base": "^0.1.8",
|
|
44
44
|
"@minejs/signals": "^0.0.6",
|
|
45
45
|
"@minejs/store": "^0.0.3"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@eslint/js": "^9.39.2",
|
|
49
|
-
"@stylistic/eslint-plugin": "^5.
|
|
50
|
-
"@types/bun": "^1.3.
|
|
51
|
-
"@types/
|
|
49
|
+
"@stylistic/eslint-plugin": "^5.7.0",
|
|
50
|
+
"@types/bun": "^1.3.6",
|
|
51
|
+
"@types/jsdom": "^27.0.0",
|
|
52
|
+
"@types/node": "^20.19.30",
|
|
52
53
|
"bun-plugin-dts": "^0.3.0",
|
|
53
|
-
"bun-types": "^1.3.
|
|
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.
|
|
59
|
+
"typescript-eslint": "^8.53.1"
|
|
58
60
|
}
|
|
59
61
|
}
|