uni-theme-select 1.0.0 → 1.0.2

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 ADDED
@@ -0,0 +1,240 @@
1
+ # uni-theme-select
2
+
3
+ # Uni Theme Toggle
4
+
5
+ A lightweight, plug-and-play theme switcher with built-in custom color support using CSS variables and Coloris.
6
+
7
+ Easily add Dark, Light, Beige, or fully Custom themes to any web application.
8
+
9
+ ---
10
+
11
+ ## Features
12
+
13
+ * Predefined themes (Dark, Light, Beige)
14
+ * Custom theme builder (Background, Primary, Secondary colors)
15
+ * CSS Variable based theming
16
+ * Theme persistence via `localStorage`
17
+ * Mount anywhere in DOM
18
+ * Zero framework dependency (Vanilla JS compatible)
19
+ * Lightweight and modular
20
+
21
+ ---
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ npm install uni-theme-toggle
27
+ ```
28
+
29
+ or
30
+
31
+ ```bash
32
+ yarn add uni-theme-toggle
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Usage
38
+
39
+ ### Import
40
+
41
+ ```ts
42
+ import {
43
+ setTheme,
44
+ loadSavedTheme,
45
+ mountToggleTheme,
46
+ unMountToggleTheme
47
+ } from "uni-theme-toggle";
48
+ ```
49
+
50
+ ---
51
+
52
+ ### Mount the Theme Toggle
53
+
54
+ ```ts
55
+ mountToggleTheme({
56
+ containerId: "app" // optional
57
+ });
58
+ ```
59
+
60
+ If `containerId` is not provided, the toggle mounts to `document.body`.
61
+
62
+ ---
63
+
64
+ ### Load Saved Theme on App Start
65
+
66
+ ```ts
67
+ loadSavedTheme();
68
+ ```
69
+
70
+ This restores the previously selected theme from `localStorage`.
71
+
72
+ ---
73
+
74
+ ### Manually Set Theme
75
+
76
+ ```ts
77
+ setTheme("dark");
78
+ setTheme("light");
79
+ setTheme("beige");
80
+ ```
81
+
82
+ ---
83
+
84
+ ### Set Custom Theme
85
+
86
+ ```ts
87
+ setTheme("custom", {
88
+ bgColor: "#121212",
89
+ primaryColor: "#4f46e5",
90
+ secondaryColor: "#f59e0b"
91
+ });
92
+ ```
93
+
94
+ ---
95
+
96
+ ## How It Works
97
+
98
+ The package updates CSS variables on the `:root` element:
99
+
100
+ ```css
101
+ :root {
102
+ --bgColor: #000;
103
+ --primaryColor: #fff;
104
+ --secondaryColor: #ccc;
105
+ }
106
+ ```
107
+
108
+ Your app should use these variables:
109
+
110
+ ```css
111
+ body {
112
+ background-color: var(--bgColor);
113
+ }
114
+
115
+ button {
116
+ background-color: var(--primaryColor);
117
+ }
118
+ ```
119
+
120
+ ---
121
+
122
+ ## Available API
123
+
124
+ ### `setTheme(name: string, themeProps?: Record<string, string>)`
125
+
126
+ Apply a theme.
127
+
128
+ ---
129
+
130
+ ### `getAvailableThemes(): string[]`
131
+
132
+ Returns available predefined themes.
133
+
134
+ ---
135
+
136
+ ### `loadSavedTheme()`
137
+
138
+ Loads previously stored theme from `localStorage`.
139
+
140
+ ---
141
+
142
+ ### `mountToggleTheme(options?)`
143
+
144
+ Mounts the theme toggle UI.
145
+
146
+ ```ts
147
+ mountToggleTheme({
148
+ containerId?: string
149
+ });
150
+ ```
151
+
152
+ ---
153
+
154
+ ### `unMountToggleTheme()`
155
+
156
+ Removes the toggle UI from DOM.
157
+
158
+ ---
159
+
160
+ ## Architecture
161
+
162
+ * Theme definitions stored in `themes.ts`
163
+ * CSS injected dynamically
164
+ * Color picker powered by Coloris
165
+ * Fully dynamic DOM rendering
166
+ * No global HTML required
167
+
168
+ ---
169
+
170
+ ## Customization
171
+
172
+ You can extend predefined themes by editing:
173
+
174
+ ```ts
175
+ themes.ts
176
+ ```
177
+
178
+ Example:
179
+
180
+ ```ts
181
+ export const themes = [
182
+ {
183
+ name: "dark",
184
+ properties: {
185
+ bgColor: "#121212",
186
+ primaryColor: "#ffffff",
187
+ secondaryColor: "#999999"
188
+ }
189
+ }
190
+ ];
191
+ ```
192
+
193
+ ---
194
+
195
+ ## Theme Persistence
196
+
197
+ Selected theme is stored in:
198
+
199
+ ```
200
+ localStorage key: "uts-theme"
201
+ ```
202
+
203
+ ---
204
+
205
+ ## Requirements
206
+
207
+ * Modern browser (supports CSS variables)
208
+ * Bundler that supports CSS imports (Vite, Webpack, etc.)
209
+
210
+ ---
211
+
212
+ ## Example
213
+
214
+ ```ts
215
+ document.addEventListener("DOMContentLoaded", () => {
216
+ loadSavedTheme();
217
+ mountToggleTheme();
218
+ });
219
+ ```
220
+
221
+ ---
222
+
223
+ ## Remove Toggle
224
+
225
+ ```ts
226
+ unMountToggleTheme();
227
+ ```
228
+
229
+ ---
230
+
231
+ ## 🧩 Roadmap
232
+
233
+ * Theme export/import
234
+ * Animation support
235
+ * Multi-theme preview
236
+ * TypeScript definitions improvements
237
+ * React wrapper
238
+
239
+ ---
240
+
package/dist/index.d.mts CHANGED
@@ -1,6 +1,7 @@
1
- declare function setTheme(name: string): void;
2
1
  declare function getAvailableThemes(): string[];
3
2
  declare function loadSavedTheme(): void;
3
+ declare function mountToggleTheme(options?: Record<string, string>): void;
4
+ declare function unMountToggleTheme(): void;
4
5
 
5
6
  type Theme = {
6
7
  name: string;
@@ -9,4 +10,4 @@ type Theme = {
9
10
 
10
11
  declare const themes: Theme[];
11
12
 
12
- export { type Theme, getAvailableThemes, loadSavedTheme, setTheme, themes };
13
+ export { type Theme, getAvailableThemes, loadSavedTheme, mountToggleTheme, themes, unMountToggleTheme };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- declare function setTheme(name: string): void;
2
1
  declare function getAvailableThemes(): string[];
3
2
  declare function loadSavedTheme(): void;
3
+ declare function mountToggleTheme(options?: Record<string, string>): void;
4
+ declare function unMountToggleTheme(): void;
4
5
 
5
6
  type Theme = {
6
7
  name: string;
@@ -9,4 +10,4 @@ type Theme = {
9
10
 
10
11
  declare const themes: Theme[];
11
12
 
12
- export { type Theme, getAvailableThemes, loadSavedTheme, setTheme, themes };
13
+ export { type Theme, getAvailableThemes, loadSavedTheme, mountToggleTheme, themes, unMountToggleTheme };
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
+ "use strict";
2
+ var __create = Object.create;
1
3
  var __defProp = Object.defineProperty;
2
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
4
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
8
  var __export = (target, all) => {
6
9
  for (var name in all)
@@ -14,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
14
17
  }
15
18
  return to;
16
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
17
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
29
 
19
30
  // src/index.ts
@@ -21,8 +32,9 @@ var index_exports = {};
21
32
  __export(index_exports, {
22
33
  getAvailableThemes: () => getAvailableThemes,
23
34
  loadSavedTheme: () => loadSavedTheme,
24
- setTheme: () => setTheme,
25
- themes: () => themes
35
+ mountToggleTheme: () => mountToggleTheme,
36
+ themes: () => themes,
37
+ unMountToggleTheme: () => unMountToggleTheme
26
38
  });
27
39
  module.exports = __toCommonJS(index_exports);
28
40
 
@@ -51,35 +63,313 @@ var themes = [
51
63
  "text-color": "#333333",
52
64
  "primary-color": "#c19a6b"
53
65
  }
66
+ },
67
+ {
68
+ name: "custom",
69
+ properties: {
70
+ "primary-button-text-color": "",
71
+ "primary-button-color": "",
72
+ "primary-button-border-color": "",
73
+ "primary-button-border-radius": "",
74
+ "secondary-button-text-color": "",
75
+ "secondary-button-color": "",
76
+ "secondary-button-border-color": "",
77
+ "secondary-button-border-radius": "",
78
+ "bg-color": "",
79
+ "font-family": "",
80
+ "primary-font-color": "",
81
+ "primary-font-size": "",
82
+ "primary-font-weight": "",
83
+ "secondary-font-color": "",
84
+ "secondary-font-weight": "",
85
+ "secondary-font-size": ""
86
+ }
54
87
  }
55
88
  ];
56
89
 
57
- // src/themeManager.ts
58
- function setTheme(name) {
59
- const theme = themes.find((t) => t.name === name);
60
- if (!theme) {
61
- console.warn(`Theme "${name}" not found`);
62
- return;
90
+ // src/coreFunctions.ts
91
+ var import_coloris = require("@melloware/coloris/dist/coloris.css");
92
+ var import_coloris2 = __toESM(require("@melloware/coloris"));
93
+
94
+ // src/store.ts
95
+ var ThemeStore = class {
96
+ constructor() {
97
+ this.currentTheme = "custom";
98
+ this.themeProps = {};
99
+ this.listeners = [];
100
+ }
101
+ setTheme(themeName, themeProps) {
102
+ this.currentTheme = themeName;
103
+ this.themeProps = themeProps;
104
+ this.notify();
105
+ }
106
+ getTheme() {
107
+ return {
108
+ themeName: this.currentTheme,
109
+ properties: this.themeProps
110
+ };
111
+ }
112
+ subscribe(listener) {
113
+ this.listeners.push(listener);
114
+ return () => {
115
+ this.listeners = this.listeners.filter((l) => l !== listener);
116
+ };
117
+ }
118
+ notify() {
119
+ this.listeners.forEach((listener) => listener(this.currentTheme, this.themeProps));
120
+ }
121
+ };
122
+ var themeStore = new ThemeStore();
123
+
124
+ // src/coreFunctions.ts
125
+ var colorFields = [
126
+ { id: "bg-color", label: "Background Color", defaultValue: "#fff", type: "text", class: "radius-50" },
127
+ { id: "primary-button-color", label: "Primary Button Color", defaultValue: "rgb(174, 174, 174)", type: "text", class: "radius-50" },
128
+ { id: "primary-button-border-color", label: "Primary Button Border Color", defaultValue: "rgba(0, 0, 0, 0)", type: "text", class: "radius-50" },
129
+ { id: "primary-button-border-radius", label: "Primary Button Border Radius", defaultValue: "0", type: "text", units: ["px", "%", "em"] },
130
+ { id: "primary-button-text-color", label: "Primary Button Text Color", defaultValue: "#000", type: "text", class: "radius-50" },
131
+ { id: "secondary-button-color", label: "Secondary Button Color", defaultValue: "rgb(174, 174, 174)", type: "text", class: "radius-50" },
132
+ { id: "secondary-button-border-color", label: "Secondary Button Border Color", defaultValue: "rgba(0, 0, 0, 0)", type: "text", class: "radius-50" },
133
+ { id: "secondary-button-border-radius", label: "Secondary Button Border Radius", defaultValue: "0", type: "text", units: ["px", "%", "em"] },
134
+ { id: "secondary-button-text-color", label: "Secondary Button Text Color", defaultValue: "#000", type: "text", class: "radius-50" },
135
+ { id: "font-family", label: "Font Family", defaultValue: "", type: "text" },
136
+ { id: "primary-font-size", label: "Primary Font Size", defaultValue: "14", type: "text", units: ["px", "%", "em"] },
137
+ { id: "primary-font-color", label: "Primary Font Color", defaultValue: "#000", type: "text", class: "radius-50" },
138
+ { id: "primary-font-weight", label: "Primary Font Weight", defaultValue: "600", type: "text" },
139
+ { id: "secondary-font-size", label: "Secondary Font Size", defaultValue: "14", type: "text", units: ["px", "%", "em"] },
140
+ { id: "secondary-font-color", label: "Secondary Font Color", defaultValue: "#ccc", type: "text", class: "radius-50" },
141
+ { id: "secondary-font-weight", label: "Primary Font Weight", defaultValue: "500", type: "text" }
142
+ ];
143
+ function injectStyles() {
144
+ if (document.getElementById("uni-theme-style")) return;
145
+ const style = document.createElement("style");
146
+ style.id = "uni-theme-style";
147
+ style.innerHTML = `
148
+ #uni-theme-toggle {
149
+ position: fixed;
150
+ bottom: 20px;
151
+ right: 20px;
152
+ width: 50px;
153
+ height: 50px;
154
+ background: var(--bg, #222);
155
+ color: var(--text, #fff);
156
+ display: flex;
157
+ align-items: center;
158
+ justify-content: center;
159
+ border-radius: 50%;
160
+ cursor: pointer;
161
+ box-shadow: 0 4px 12px rgba(0,0,0,0.3);
162
+ z-index: 9999;
163
+ font-size:20px;
164
+ transition: right 0.3s ease;
165
+ }
166
+
167
+ #uni-theme-overlay {
168
+ position: fixed;
169
+ inset: 0;
170
+ background: rgba(0,0,0,0.3);
171
+ opacity: 0;
172
+ pointer-events: none;
173
+ transition: opacity 0.3s ease;
174
+ z-index: 9998;
175
+ }
176
+
177
+ #uni-theme-overlay.show {
178
+ opacity: 1;
179
+ pointer-events: all;
180
+ }
181
+
182
+ #uni-theme-panel {
183
+ position: fixed;
184
+ bottom: 20px;
185
+ right: -322px;
186
+ width: 280px;
187
+ background: var(--bg, #fff);
188
+ color: var(--text, #000);
189
+ padding: 20px;
190
+ box-shadow: -4px 0 12px rgba(0,0,0,0.2);
191
+ transition: right 0.3s ease;
192
+ z-index: 9999;
193
+ overflow: auto
194
+ }
195
+
196
+ #uni-theme-root.opened #uni-theme-panel{
197
+ right: 0;
198
+ }
199
+
200
+ #uni-theme-root.opened #uni-theme-toggle{
201
+ right: 322px;
202
+ transition: left 0.3s ease;
203
+ }
204
+
205
+ #uni-theme-panel button {
206
+ display: block;
207
+ margin: 10px 0;
208
+ padding: 8px;
209
+ width: 100%;
210
+ cursor: pointer;
211
+ }
212
+ #clr-picker{
213
+ z-index: 999999
214
+ }
215
+ #uni-theme-panel button{
216
+ margin: 0;
217
+ border-radius: 50%
218
+ }
219
+ .clr-field{
220
+ margin: 5px 0
221
+ }
222
+ .uni-input-group {
223
+ display: flex;
224
+ align-items: center;
225
+ justify-content: space-between;
226
+ margin-bottom: 14px;
227
+ gap: 12px;
228
+ }
229
+
230
+ .uni-input-group label {
231
+ font-size: 14px;
232
+ font-weight: 500;
233
+ color: #333;
234
+ }
235
+
236
+ .uni-input {
237
+ width: 36px;
238
+ height: 36px;
239
+ border: 2px solid #ddd;
240
+ cursor: pointer;
241
+ padding: 0;
242
+ }
243
+ .radius-50{
244
+ border-radius:50%
245
+ }
246
+
247
+ `;
248
+ document.head.appendChild(style);
249
+ }
250
+ function setTheme(name, customProps = {}) {
251
+ let themeProps = {};
252
+ if (name == "custom" && customProps) {
253
+ themeProps = customProps;
254
+ } else {
255
+ const theme = themes.find((t) => t.name === name);
256
+ if (!theme) {
257
+ console.warn(`Theme "${name}" not found`);
258
+ return;
259
+ }
260
+ themeProps = theme.properties;
63
261
  }
64
262
  const root = document.documentElement;
65
- Object.entries(theme.properties).forEach(([key, value]) => {
263
+ Object.entries(themeProps).forEach(([key, value]) => {
66
264
  root.style.setProperty(`--${key}`, value);
67
265
  });
68
- localStorage.setItem("uts-theme", name);
266
+ localStorage.setItem(
267
+ "uts-theme",
268
+ JSON.stringify({
269
+ name,
270
+ properties: themeProps
271
+ })
272
+ );
273
+ themeStore.setTheme(name, themeProps);
274
+ }
275
+ function constructPanel(container) {
276
+ const panel = document.createElement("div");
277
+ panel.id = "uni-theme-panel";
278
+ const title = document.createElement("h3");
279
+ title.textContent = "Select Custom Theme";
280
+ panel.appendChild(title);
281
+ colorFields.forEach((field) => {
282
+ const group = document.createElement("div");
283
+ group.className = "uni-input-group";
284
+ const label = document.createElement("label");
285
+ label.textContent = field.label;
286
+ const input = document.createElement("input");
287
+ input.type = field.type;
288
+ input.name = field.id;
289
+ input.className = `uni-input ${field.class}`;
290
+ input.id = `uni-theme-${field.id}`;
291
+ input.value = field.defaultValue;
292
+ group.appendChild(label);
293
+ group.appendChild(input);
294
+ if (field.units && field.units.length > 0) {
295
+ const inputUnits = document.createElement("select");
296
+ field.units.forEach((unit) => {
297
+ const option = document.createElement("option");
298
+ option.value = unit;
299
+ option.textContent = unit;
300
+ inputUnits.appendChild(option);
301
+ });
302
+ group.appendChild(inputUnits);
303
+ }
304
+ panel.appendChild(group);
305
+ });
306
+ container.appendChild(panel);
307
+ }
308
+ function injectHTML(options = {}) {
309
+ var _a, _b;
310
+ const container = document.createElement("div");
311
+ if (document.getElementById("uni-theme-root")) return;
312
+ container.id = "uni-theme-root";
313
+ container.innerHTML = `
314
+ <div id='uni-theme-toggle'>\u{1F3A8}</div>
315
+ `;
316
+ constructPanel(container);
317
+ (_a = document.getElementById(options.containerId)) == null ? void 0 : _a.style.setProperty("position", "relative");
318
+ options.containerId ? (_b = document.getElementById(options.containerId)) == null ? void 0 : _b.append(container) : document.body.appendChild(container);
319
+ return container;
69
320
  }
321
+ function initThemeElements() {
322
+ const themeToggler = document.getElementById("uni-theme-toggle");
323
+ const themePanel = document.getElementById("uni-theme-panel");
324
+ import_coloris2.default.init();
325
+ document.querySelectorAll(".uni-input").forEach((input) => {
326
+ (0, import_coloris2.default)({
327
+ el: `.uni-input.radius-50`,
328
+ alpha: true,
329
+ format: "hex"
330
+ });
331
+ input.addEventListener("input", (e) => {
332
+ const target = e.target;
333
+ const currentTheme = themeStore.getTheme();
334
+ currentTheme.properties[target.name] = target.value;
335
+ console.log(currentTheme);
336
+ setTheme(currentTheme.themeName, currentTheme.properties);
337
+ });
338
+ });
339
+ return { themeToggler, themePanel };
340
+ }
341
+
342
+ // src/themeManager.ts
70
343
  function getAvailableThemes() {
71
344
  return themes.map((t) => t.name);
72
345
  }
73
346
  function loadSavedTheme() {
74
347
  const saved = localStorage.getItem("uts-theme");
75
- if (saved) {
76
- setTheme(saved);
348
+ if (!saved) return;
349
+ const parsed = JSON.parse(saved);
350
+ if (parsed.name == "custom") {
351
+ setTheme(parsed.name, parsed.properties);
352
+ } else {
353
+ setTheme(parsed.name);
77
354
  }
78
355
  }
356
+ function mountToggleTheme(options = {}) {
357
+ injectStyles();
358
+ const container = injectHTML(options);
359
+ const { themeToggler, themePanel } = initThemeElements();
360
+ themeToggler == null ? void 0 : themeToggler.addEventListener("click", () => {
361
+ container == null ? void 0 : container.classList.toggle("opened");
362
+ });
363
+ }
364
+ function unMountToggleTheme() {
365
+ var _a;
366
+ (_a = document.getElementById("uni-theme-root")) == null ? void 0 : _a.remove();
367
+ }
79
368
  // Annotate the CommonJS export names for ESM import in node:
80
369
  0 && (module.exports = {
81
370
  getAvailableThemes,
82
371
  loadSavedTheme,
83
- setTheme,
84
- themes
372
+ mountToggleTheme,
373
+ themes,
374
+ unMountToggleTheme
85
375
  });
package/dist/index.mjs CHANGED
@@ -23,34 +23,312 @@ var themes = [
23
23
  "text-color": "#333333",
24
24
  "primary-color": "#c19a6b"
25
25
  }
26
+ },
27
+ {
28
+ name: "custom",
29
+ properties: {
30
+ "primary-button-text-color": "",
31
+ "primary-button-color": "",
32
+ "primary-button-border-color": "",
33
+ "primary-button-border-radius": "",
34
+ "secondary-button-text-color": "",
35
+ "secondary-button-color": "",
36
+ "secondary-button-border-color": "",
37
+ "secondary-button-border-radius": "",
38
+ "bg-color": "",
39
+ "font-family": "",
40
+ "primary-font-color": "",
41
+ "primary-font-size": "",
42
+ "primary-font-weight": "",
43
+ "secondary-font-color": "",
44
+ "secondary-font-weight": "",
45
+ "secondary-font-size": ""
46
+ }
26
47
  }
27
48
  ];
28
49
 
29
- // src/themeManager.ts
30
- function setTheme(name) {
31
- const theme = themes.find((t) => t.name === name);
32
- if (!theme) {
33
- console.warn(`Theme "${name}" not found`);
34
- return;
50
+ // src/coreFunctions.ts
51
+ import "@melloware/coloris/dist/coloris.css";
52
+ import Coloris from "@melloware/coloris";
53
+
54
+ // src/store.ts
55
+ var ThemeStore = class {
56
+ constructor() {
57
+ this.currentTheme = "custom";
58
+ this.themeProps = {};
59
+ this.listeners = [];
60
+ }
61
+ setTheme(themeName, themeProps) {
62
+ this.currentTheme = themeName;
63
+ this.themeProps = themeProps;
64
+ this.notify();
65
+ }
66
+ getTheme() {
67
+ return {
68
+ themeName: this.currentTheme,
69
+ properties: this.themeProps
70
+ };
71
+ }
72
+ subscribe(listener) {
73
+ this.listeners.push(listener);
74
+ return () => {
75
+ this.listeners = this.listeners.filter((l) => l !== listener);
76
+ };
77
+ }
78
+ notify() {
79
+ this.listeners.forEach((listener) => listener(this.currentTheme, this.themeProps));
80
+ }
81
+ };
82
+ var themeStore = new ThemeStore();
83
+
84
+ // src/coreFunctions.ts
85
+ var colorFields = [
86
+ { id: "bg-color", label: "Background Color", defaultValue: "#fff", type: "text", class: "radius-50" },
87
+ { id: "primary-button-color", label: "Primary Button Color", defaultValue: "rgb(174, 174, 174)", type: "text", class: "radius-50" },
88
+ { id: "primary-button-border-color", label: "Primary Button Border Color", defaultValue: "rgba(0, 0, 0, 0)", type: "text", class: "radius-50" },
89
+ { id: "primary-button-border-radius", label: "Primary Button Border Radius", defaultValue: "0", type: "text", units: ["px", "%", "em"] },
90
+ { id: "primary-button-text-color", label: "Primary Button Text Color", defaultValue: "#000", type: "text", class: "radius-50" },
91
+ { id: "secondary-button-color", label: "Secondary Button Color", defaultValue: "rgb(174, 174, 174)", type: "text", class: "radius-50" },
92
+ { id: "secondary-button-border-color", label: "Secondary Button Border Color", defaultValue: "rgba(0, 0, 0, 0)", type: "text", class: "radius-50" },
93
+ { id: "secondary-button-border-radius", label: "Secondary Button Border Radius", defaultValue: "0", type: "text", units: ["px", "%", "em"] },
94
+ { id: "secondary-button-text-color", label: "Secondary Button Text Color", defaultValue: "#000", type: "text", class: "radius-50" },
95
+ { id: "font-family", label: "Font Family", defaultValue: "", type: "text" },
96
+ { id: "primary-font-size", label: "Primary Font Size", defaultValue: "14", type: "text", units: ["px", "%", "em"] },
97
+ { id: "primary-font-color", label: "Primary Font Color", defaultValue: "#000", type: "text", class: "radius-50" },
98
+ { id: "primary-font-weight", label: "Primary Font Weight", defaultValue: "600", type: "text" },
99
+ { id: "secondary-font-size", label: "Secondary Font Size", defaultValue: "14", type: "text", units: ["px", "%", "em"] },
100
+ { id: "secondary-font-color", label: "Secondary Font Color", defaultValue: "#ccc", type: "text", class: "radius-50" },
101
+ { id: "secondary-font-weight", label: "Primary Font Weight", defaultValue: "500", type: "text" }
102
+ ];
103
+ function injectStyles() {
104
+ if (document.getElementById("uni-theme-style")) return;
105
+ const style = document.createElement("style");
106
+ style.id = "uni-theme-style";
107
+ style.innerHTML = `
108
+ #uni-theme-toggle {
109
+ position: fixed;
110
+ bottom: 20px;
111
+ right: 20px;
112
+ width: 50px;
113
+ height: 50px;
114
+ background: var(--bg, #222);
115
+ color: var(--text, #fff);
116
+ display: flex;
117
+ align-items: center;
118
+ justify-content: center;
119
+ border-radius: 50%;
120
+ cursor: pointer;
121
+ box-shadow: 0 4px 12px rgba(0,0,0,0.3);
122
+ z-index: 9999;
123
+ font-size:20px;
124
+ transition: right 0.3s ease;
125
+ }
126
+
127
+ #uni-theme-overlay {
128
+ position: fixed;
129
+ inset: 0;
130
+ background: rgba(0,0,0,0.3);
131
+ opacity: 0;
132
+ pointer-events: none;
133
+ transition: opacity 0.3s ease;
134
+ z-index: 9998;
135
+ }
136
+
137
+ #uni-theme-overlay.show {
138
+ opacity: 1;
139
+ pointer-events: all;
140
+ }
141
+
142
+ #uni-theme-panel {
143
+ position: fixed;
144
+ bottom: 20px;
145
+ right: -322px;
146
+ width: 280px;
147
+ background: var(--bg, #fff);
148
+ color: var(--text, #000);
149
+ padding: 20px;
150
+ box-shadow: -4px 0 12px rgba(0,0,0,0.2);
151
+ transition: right 0.3s ease;
152
+ z-index: 9999;
153
+ overflow: auto
154
+ }
155
+
156
+ #uni-theme-root.opened #uni-theme-panel{
157
+ right: 0;
158
+ }
159
+
160
+ #uni-theme-root.opened #uni-theme-toggle{
161
+ right: 322px;
162
+ transition: left 0.3s ease;
163
+ }
164
+
165
+ #uni-theme-panel button {
166
+ display: block;
167
+ margin: 10px 0;
168
+ padding: 8px;
169
+ width: 100%;
170
+ cursor: pointer;
171
+ }
172
+ #clr-picker{
173
+ z-index: 999999
174
+ }
175
+ #uni-theme-panel button{
176
+ margin: 0;
177
+ border-radius: 50%
178
+ }
179
+ .clr-field{
180
+ margin: 5px 0
181
+ }
182
+ .uni-input-group {
183
+ display: flex;
184
+ align-items: center;
185
+ justify-content: space-between;
186
+ margin-bottom: 14px;
187
+ gap: 12px;
188
+ }
189
+
190
+ .uni-input-group label {
191
+ font-size: 14px;
192
+ font-weight: 500;
193
+ color: #333;
194
+ }
195
+
196
+ .uni-input {
197
+ width: 36px;
198
+ height: 36px;
199
+ border: 2px solid #ddd;
200
+ cursor: pointer;
201
+ padding: 0;
202
+ }
203
+ .radius-50{
204
+ border-radius:50%
205
+ }
206
+
207
+ `;
208
+ document.head.appendChild(style);
209
+ }
210
+ function setTheme(name, customProps = {}) {
211
+ let themeProps = {};
212
+ if (name == "custom" && customProps) {
213
+ themeProps = customProps;
214
+ } else {
215
+ const theme = themes.find((t) => t.name === name);
216
+ if (!theme) {
217
+ console.warn(`Theme "${name}" not found`);
218
+ return;
219
+ }
220
+ themeProps = theme.properties;
35
221
  }
36
222
  const root = document.documentElement;
37
- Object.entries(theme.properties).forEach(([key, value]) => {
223
+ Object.entries(themeProps).forEach(([key, value]) => {
38
224
  root.style.setProperty(`--${key}`, value);
39
225
  });
40
- localStorage.setItem("uts-theme", name);
226
+ localStorage.setItem(
227
+ "uts-theme",
228
+ JSON.stringify({
229
+ name,
230
+ properties: themeProps
231
+ })
232
+ );
233
+ themeStore.setTheme(name, themeProps);
234
+ }
235
+ function constructPanel(container) {
236
+ const panel = document.createElement("div");
237
+ panel.id = "uni-theme-panel";
238
+ const title = document.createElement("h3");
239
+ title.textContent = "Select Custom Theme";
240
+ panel.appendChild(title);
241
+ colorFields.forEach((field) => {
242
+ const group = document.createElement("div");
243
+ group.className = "uni-input-group";
244
+ const label = document.createElement("label");
245
+ label.textContent = field.label;
246
+ const input = document.createElement("input");
247
+ input.type = field.type;
248
+ input.name = field.id;
249
+ input.className = `uni-input ${field.class}`;
250
+ input.id = `uni-theme-${field.id}`;
251
+ input.value = field.defaultValue;
252
+ group.appendChild(label);
253
+ group.appendChild(input);
254
+ if (field.units && field.units.length > 0) {
255
+ const inputUnits = document.createElement("select");
256
+ field.units.forEach((unit) => {
257
+ const option = document.createElement("option");
258
+ option.value = unit;
259
+ option.textContent = unit;
260
+ inputUnits.appendChild(option);
261
+ });
262
+ group.appendChild(inputUnits);
263
+ }
264
+ panel.appendChild(group);
265
+ });
266
+ container.appendChild(panel);
267
+ }
268
+ function injectHTML(options = {}) {
269
+ var _a, _b;
270
+ const container = document.createElement("div");
271
+ if (document.getElementById("uni-theme-root")) return;
272
+ container.id = "uni-theme-root";
273
+ container.innerHTML = `
274
+ <div id='uni-theme-toggle'>\u{1F3A8}</div>
275
+ `;
276
+ constructPanel(container);
277
+ (_a = document.getElementById(options.containerId)) == null ? void 0 : _a.style.setProperty("position", "relative");
278
+ options.containerId ? (_b = document.getElementById(options.containerId)) == null ? void 0 : _b.append(container) : document.body.appendChild(container);
279
+ return container;
41
280
  }
281
+ function initThemeElements() {
282
+ const themeToggler = document.getElementById("uni-theme-toggle");
283
+ const themePanel = document.getElementById("uni-theme-panel");
284
+ Coloris.init();
285
+ document.querySelectorAll(".uni-input").forEach((input) => {
286
+ Coloris({
287
+ el: `.uni-input.radius-50`,
288
+ alpha: true,
289
+ format: "hex"
290
+ });
291
+ input.addEventListener("input", (e) => {
292
+ const target = e.target;
293
+ const currentTheme = themeStore.getTheme();
294
+ currentTheme.properties[target.name] = target.value;
295
+ console.log(currentTheme);
296
+ setTheme(currentTheme.themeName, currentTheme.properties);
297
+ });
298
+ });
299
+ return { themeToggler, themePanel };
300
+ }
301
+
302
+ // src/themeManager.ts
42
303
  function getAvailableThemes() {
43
304
  return themes.map((t) => t.name);
44
305
  }
45
306
  function loadSavedTheme() {
46
307
  const saved = localStorage.getItem("uts-theme");
47
- if (saved) {
48
- setTheme(saved);
308
+ if (!saved) return;
309
+ const parsed = JSON.parse(saved);
310
+ if (parsed.name == "custom") {
311
+ setTheme(parsed.name, parsed.properties);
312
+ } else {
313
+ setTheme(parsed.name);
49
314
  }
50
315
  }
316
+ function mountToggleTheme(options = {}) {
317
+ injectStyles();
318
+ const container = injectHTML(options);
319
+ const { themeToggler, themePanel } = initThemeElements();
320
+ themeToggler == null ? void 0 : themeToggler.addEventListener("click", () => {
321
+ container == null ? void 0 : container.classList.toggle("opened");
322
+ });
323
+ }
324
+ function unMountToggleTheme() {
325
+ var _a;
326
+ (_a = document.getElementById("uni-theme-root")) == null ? void 0 : _a.remove();
327
+ }
51
328
  export {
52
329
  getAvailableThemes,
53
330
  loadSavedTheme,
54
- setTheme,
55
- themes
331
+ mountToggleTheme,
332
+ themes,
333
+ unMountToggleTheme
56
334
  };
package/package.json CHANGED
@@ -1,20 +1,29 @@
1
1
  {
2
2
  "name": "uni-theme-select",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Framework-agnostic theme switcher",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
8
- "files": ["dist"],
8
+ "files": [
9
+ "dist"
10
+ ],
9
11
  "scripts": {
10
12
  "build": "tsup src/index.ts --format cjs,esm --dts",
11
13
  "dev": "tsup src/index.ts --format cjs,esm --watch --dts"
12
14
  },
13
- "keywords": ["theme", "dark-mode", "css-variables"],
15
+ "keywords": [
16
+ "theme",
17
+ "dark-mode",
18
+ "css-variables"
19
+ ],
14
20
  "author": "sri_manohari",
15
21
  "license": "ISC",
16
22
  "devDependencies": {
17
23
  "tsup": "^8.5.1",
18
24
  "typescript": "^5.9.3"
25
+ },
26
+ "dependencies": {
27
+ "@melloware/coloris": "^0.25.0"
19
28
  }
20
29
  }