combo-ui-vue 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +564 -0
- package/dist/index.mjs +2693 -0
- package/package.json +46 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2693 @@
|
|
|
1
|
+
import { onMounted, onUnmounted, readonly, ref } from "vue";
|
|
2
|
+
//#region src/core/dark-mode.ts
|
|
3
|
+
var DarkMode = class {
|
|
4
|
+
mode = "auto";
|
|
5
|
+
mediaQuery = null;
|
|
6
|
+
callbacks = /* @__PURE__ */ new Set();
|
|
7
|
+
storageKey = "cux-dark-mode";
|
|
8
|
+
persist = true;
|
|
9
|
+
constructor(options) {
|
|
10
|
+
if (options?.persist !== void 0) this.persist = options.persist;
|
|
11
|
+
if (options?.storageKey) this.storageKey = options.storageKey;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Initialize dark mode system
|
|
15
|
+
*/
|
|
16
|
+
init(mode = "auto") {
|
|
17
|
+
this.mode = mode;
|
|
18
|
+
this.setupMediaQuery();
|
|
19
|
+
if (mode === "auto") {
|
|
20
|
+
const stored = this.getStoredPreference();
|
|
21
|
+
if (stored !== null) this.applyDarkMode(stored);
|
|
22
|
+
else this.applyDarkMode(this.getSystemPreference());
|
|
23
|
+
} else this.applyDarkMode(mode === "dark");
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Set up media query listener for system preference changes
|
|
27
|
+
*/
|
|
28
|
+
setupMediaQuery() {
|
|
29
|
+
if (typeof window === "undefined") return;
|
|
30
|
+
this.mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
31
|
+
this.mediaQuery.addEventListener("change", this.handleMediaQueryChange);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Handle system preference changes
|
|
35
|
+
*/
|
|
36
|
+
handleMediaQueryChange = (e) => {
|
|
37
|
+
if (this.mode === "auto") this.applyDarkMode(e.matches);
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Get system preference for dark mode
|
|
41
|
+
*/
|
|
42
|
+
getSystemPreference() {
|
|
43
|
+
if (typeof window === "undefined") return false;
|
|
44
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get stored preference from localStorage
|
|
48
|
+
*/
|
|
49
|
+
getStoredPreference() {
|
|
50
|
+
if (!this.persist || typeof localStorage === "undefined") return null;
|
|
51
|
+
const stored = localStorage.getItem(this.storageKey);
|
|
52
|
+
if (stored === "dark") return true;
|
|
53
|
+
if (stored === "light") return false;
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Store preference in localStorage
|
|
58
|
+
*/
|
|
59
|
+
storePreference(isDark) {
|
|
60
|
+
if (!this.persist || typeof localStorage === "undefined") return;
|
|
61
|
+
localStorage.setItem(this.storageKey, isDark ? "dark" : "light");
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Apply dark mode by toggling class on document element
|
|
65
|
+
*/
|
|
66
|
+
applyDarkMode(isDark) {
|
|
67
|
+
if (typeof document === "undefined") return;
|
|
68
|
+
document.documentElement.classList.toggle("dark", isDark);
|
|
69
|
+
this.storePreference(isDark);
|
|
70
|
+
this.notifyCallbacks(isDark);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Notify all registered callbacks
|
|
74
|
+
*/
|
|
75
|
+
notifyCallbacks(isDark) {
|
|
76
|
+
this.callbacks.forEach((callback) => callback(isDark));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get current dark mode state
|
|
80
|
+
*/
|
|
81
|
+
get isDark() {
|
|
82
|
+
if (typeof document === "undefined") return false;
|
|
83
|
+
return document.documentElement.classList.contains("dark");
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get current mode setting
|
|
87
|
+
*/
|
|
88
|
+
get currentMode() {
|
|
89
|
+
return this.mode;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Set dark mode
|
|
93
|
+
*/
|
|
94
|
+
setDarkMode(value) {
|
|
95
|
+
if (value === "auto") {
|
|
96
|
+
this.mode = "auto";
|
|
97
|
+
this.applyDarkMode(this.getSystemPreference());
|
|
98
|
+
if (this.persist && typeof localStorage !== "undefined") localStorage.removeItem(this.storageKey);
|
|
99
|
+
} else {
|
|
100
|
+
this.mode = "light";
|
|
101
|
+
this.applyDarkMode(value);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Toggle dark mode
|
|
106
|
+
*/
|
|
107
|
+
toggle() {
|
|
108
|
+
this.setDarkMode(!this.isDark);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Register a callback for dark mode changes
|
|
112
|
+
*/
|
|
113
|
+
onChange(callback) {
|
|
114
|
+
this.callbacks.add(callback);
|
|
115
|
+
return () => this.callbacks.delete(callback);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Clean up event listeners
|
|
119
|
+
*/
|
|
120
|
+
destroy() {
|
|
121
|
+
if (this.mediaQuery) this.mediaQuery.removeEventListener("change", this.handleMediaQueryChange);
|
|
122
|
+
this.callbacks.clear();
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
//#endregion
|
|
126
|
+
//#region src/core/css-generator.ts
|
|
127
|
+
/**
|
|
128
|
+
* CSS Injector - Manages style element injection
|
|
129
|
+
*/
|
|
130
|
+
const STYLE_ID = "cux-styles";
|
|
131
|
+
var CSSInjector = class {
|
|
132
|
+
styleElement = null;
|
|
133
|
+
/**
|
|
134
|
+
* Get or create the style element in the document head
|
|
135
|
+
*/
|
|
136
|
+
getStyleElement() {
|
|
137
|
+
if (this.styleElement) return this.styleElement;
|
|
138
|
+
let element = document.getElementById(STYLE_ID);
|
|
139
|
+
if (!element) {
|
|
140
|
+
element = document.createElement("style");
|
|
141
|
+
element.id = STYLE_ID;
|
|
142
|
+
document.head.appendChild(element);
|
|
143
|
+
}
|
|
144
|
+
this.styleElement = element;
|
|
145
|
+
return element;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Inject CSS into the document
|
|
149
|
+
*/
|
|
150
|
+
inject(css) {
|
|
151
|
+
this.getStyleElement().textContent = css;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Remove injected styles from the document
|
|
155
|
+
*/
|
|
156
|
+
destroy() {
|
|
157
|
+
if (this.styleElement?.parentNode) this.styleElement.parentNode.removeChild(this.styleElement);
|
|
158
|
+
this.styleElement = null;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
//#endregion
|
|
162
|
+
//#region src/core/theme-loader.ts
|
|
163
|
+
var ThemeLoader = class {
|
|
164
|
+
callbacks = /* @__PURE__ */ new Set();
|
|
165
|
+
/**
|
|
166
|
+
* Load theme from URL or object
|
|
167
|
+
*/
|
|
168
|
+
async load(theme) {
|
|
169
|
+
let themeData;
|
|
170
|
+
if (typeof theme === "string") themeData = await this.loadFromURL(theme);
|
|
171
|
+
else themeData = theme;
|
|
172
|
+
this.notifyCallbacks(themeData);
|
|
173
|
+
return themeData;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Load theme from URL
|
|
177
|
+
*/
|
|
178
|
+
async loadFromURL(url) {
|
|
179
|
+
try {
|
|
180
|
+
const response = await fetch(url);
|
|
181
|
+
if (!response.ok) throw new Error(`Failed to load theme: ${response.status} ${response.statusText}`);
|
|
182
|
+
return await response.json();
|
|
183
|
+
} catch (error) {
|
|
184
|
+
console.error("Error loading theme:", error);
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Load theme from File object (for file picker)
|
|
190
|
+
*/
|
|
191
|
+
async loadFromFile(file) {
|
|
192
|
+
return new Promise((resolve, reject) => {
|
|
193
|
+
const reader = new FileReader();
|
|
194
|
+
reader.onload = (e) => {
|
|
195
|
+
try {
|
|
196
|
+
const content = e.target?.result;
|
|
197
|
+
const themeData = JSON.parse(content);
|
|
198
|
+
this.notifyCallbacks(themeData);
|
|
199
|
+
resolve(themeData);
|
|
200
|
+
} catch {
|
|
201
|
+
reject(/* @__PURE__ */ new Error("Invalid JSON file"));
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
reader.onerror = () => {
|
|
205
|
+
reject(/* @__PURE__ */ new Error("Failed to read file"));
|
|
206
|
+
};
|
|
207
|
+
reader.readAsText(file);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Open file picker and load theme
|
|
212
|
+
*/
|
|
213
|
+
async openFilePicker() {
|
|
214
|
+
return new Promise((resolve) => {
|
|
215
|
+
const input = document.createElement("input");
|
|
216
|
+
input.type = "file";
|
|
217
|
+
input.accept = ".json";
|
|
218
|
+
input.onchange = async (e) => {
|
|
219
|
+
const file = e.target.files?.[0];
|
|
220
|
+
if (file) try {
|
|
221
|
+
resolve(await this.loadFromFile(file));
|
|
222
|
+
} catch (error) {
|
|
223
|
+
console.error("Error loading theme from file:", error);
|
|
224
|
+
resolve(null);
|
|
225
|
+
}
|
|
226
|
+
else resolve(null);
|
|
227
|
+
};
|
|
228
|
+
input.click();
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Register a callback for theme load events
|
|
233
|
+
*/
|
|
234
|
+
onLoad(callback) {
|
|
235
|
+
this.callbacks.add(callback);
|
|
236
|
+
return () => this.callbacks.delete(callback);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Notify all registered callbacks
|
|
240
|
+
*/
|
|
241
|
+
notifyCallbacks(theme) {
|
|
242
|
+
this.callbacks.forEach((callback) => callback(theme));
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Clean up
|
|
246
|
+
*/
|
|
247
|
+
destroy() {
|
|
248
|
+
this.callbacks.clear();
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
//#endregion
|
|
252
|
+
//#region src/core/theme-sync.ts
|
|
253
|
+
var ThemeSync = class {
|
|
254
|
+
url;
|
|
255
|
+
ws = null;
|
|
256
|
+
reconnect;
|
|
257
|
+
reconnectInterval;
|
|
258
|
+
maxReconnectAttempts;
|
|
259
|
+
reconnectAttempts = 0;
|
|
260
|
+
reconnectTimeout = null;
|
|
261
|
+
isIntentionallyClosed = false;
|
|
262
|
+
connectCallbacks = /* @__PURE__ */ new Set();
|
|
263
|
+
disconnectCallbacks = /* @__PURE__ */ new Set();
|
|
264
|
+
errorCallbacks = /* @__PURE__ */ new Set();
|
|
265
|
+
themeUpdateCallbacks = /* @__PURE__ */ new Set();
|
|
266
|
+
applyTheme;
|
|
267
|
+
constructor(applyTheme, options) {
|
|
268
|
+
this.applyTheme = applyTheme;
|
|
269
|
+
this.url = options.url;
|
|
270
|
+
this.reconnect = options.reconnect ?? true;
|
|
271
|
+
this.reconnectInterval = options.reconnectInterval ?? 3e3;
|
|
272
|
+
this.maxReconnectAttempts = options.maxReconnectAttempts ?? 10;
|
|
273
|
+
if (options.onConnect) this.connectCallbacks.add(options.onConnect);
|
|
274
|
+
if (options.onDisconnect) this.disconnectCallbacks.add(options.onDisconnect);
|
|
275
|
+
if (options.onError) this.errorCallbacks.add(options.onError);
|
|
276
|
+
if (options.onThemeUpdate) this.themeUpdateCallbacks.add(options.onThemeUpdate);
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Connect to WebSocket server
|
|
280
|
+
*/
|
|
281
|
+
connect() {
|
|
282
|
+
if (this.ws?.readyState === WebSocket.OPEN || this.ws?.readyState === WebSocket.CONNECTING) return;
|
|
283
|
+
this.isIntentionallyClosed = false;
|
|
284
|
+
try {
|
|
285
|
+
this.ws = new WebSocket(this.url);
|
|
286
|
+
this.setupEventListeners();
|
|
287
|
+
} catch (error) {
|
|
288
|
+
this.notifyErrorCallbacks(error);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Set up WebSocket event listeners
|
|
293
|
+
*/
|
|
294
|
+
setupEventListeners() {
|
|
295
|
+
if (!this.ws) return;
|
|
296
|
+
this.ws.onopen = () => {
|
|
297
|
+
this.reconnectAttempts = 0;
|
|
298
|
+
this.notifyConnectCallbacks();
|
|
299
|
+
};
|
|
300
|
+
this.ws.onmessage = (event) => {
|
|
301
|
+
try {
|
|
302
|
+
const message = JSON.parse(event.data);
|
|
303
|
+
if (message.type === "theme-update" && message.payload) {
|
|
304
|
+
console.log("[ThemeSync] Received theme with keys:", Object.keys(message.payload));
|
|
305
|
+
this.applyTheme(message.payload);
|
|
306
|
+
this.notifyThemeUpdateCallbacks(message.payload);
|
|
307
|
+
}
|
|
308
|
+
} catch (error) {
|
|
309
|
+
console.error("[ThemeSync] Error parsing message:", error);
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
this.ws.onclose = () => {
|
|
313
|
+
this.notifyDisconnectCallbacks();
|
|
314
|
+
if (!this.isIntentionallyClosed && this.reconnect) this.scheduleReconnect();
|
|
315
|
+
};
|
|
316
|
+
this.ws.onerror = (event) => {
|
|
317
|
+
const error = /* @__PURE__ */ new Error("WebSocket connection error");
|
|
318
|
+
this.notifyErrorCallbacks(error);
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Schedule reconnection attempt
|
|
323
|
+
*/
|
|
324
|
+
scheduleReconnect() {
|
|
325
|
+
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
326
|
+
console.warn(`[ThemeSync] Max reconnection attempts (${this.maxReconnectAttempts}) reached`);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
this.reconnectAttempts++;
|
|
330
|
+
this.reconnectTimeout = setTimeout(() => {
|
|
331
|
+
this.connect();
|
|
332
|
+
}, this.reconnectInterval);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Disconnect from WebSocket server
|
|
336
|
+
*/
|
|
337
|
+
disconnect() {
|
|
338
|
+
this.isIntentionallyClosed = true;
|
|
339
|
+
this.clearReconnectTimeout();
|
|
340
|
+
if (this.ws) {
|
|
341
|
+
this.ws.close();
|
|
342
|
+
this.ws = null;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Check if connected
|
|
347
|
+
*/
|
|
348
|
+
get isConnected() {
|
|
349
|
+
return this.ws?.readyState === WebSocket.OPEN;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Clear reconnection timeout
|
|
353
|
+
*/
|
|
354
|
+
clearReconnectTimeout() {
|
|
355
|
+
if (this.reconnectTimeout) {
|
|
356
|
+
clearTimeout(this.reconnectTimeout);
|
|
357
|
+
this.reconnectTimeout = null;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
onConnect(callback) {
|
|
361
|
+
this.connectCallbacks.add(callback);
|
|
362
|
+
return () => this.connectCallbacks.delete(callback);
|
|
363
|
+
}
|
|
364
|
+
onDisconnect(callback) {
|
|
365
|
+
this.disconnectCallbacks.add(callback);
|
|
366
|
+
return () => this.disconnectCallbacks.delete(callback);
|
|
367
|
+
}
|
|
368
|
+
onError(callback) {
|
|
369
|
+
this.errorCallbacks.add(callback);
|
|
370
|
+
return () => this.errorCallbacks.delete(callback);
|
|
371
|
+
}
|
|
372
|
+
onThemeUpdate(callback) {
|
|
373
|
+
this.themeUpdateCallbacks.add(callback);
|
|
374
|
+
return () => this.themeUpdateCallbacks.delete(callback);
|
|
375
|
+
}
|
|
376
|
+
notifyConnectCallbacks() {
|
|
377
|
+
this.connectCallbacks.forEach((cb) => cb());
|
|
378
|
+
}
|
|
379
|
+
notifyDisconnectCallbacks() {
|
|
380
|
+
this.disconnectCallbacks.forEach((cb) => cb());
|
|
381
|
+
}
|
|
382
|
+
notifyErrorCallbacks(error) {
|
|
383
|
+
this.errorCallbacks.forEach((cb) => cb(error));
|
|
384
|
+
}
|
|
385
|
+
notifyThemeUpdateCallbacks(theme) {
|
|
386
|
+
this.themeUpdateCallbacks.forEach((cb) => cb(theme));
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Destroy instance and clean up
|
|
390
|
+
*/
|
|
391
|
+
destroy() {
|
|
392
|
+
this.disconnect();
|
|
393
|
+
this.connectCallbacks.clear();
|
|
394
|
+
this.disconnectCallbacks.clear();
|
|
395
|
+
this.errorCallbacks.clear();
|
|
396
|
+
this.themeUpdateCallbacks.clear();
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
//#endregion
|
|
400
|
+
//#region src/core/google-fonts.ts
|
|
401
|
+
/**
|
|
402
|
+
* Google Fonts loader for vanilla library
|
|
403
|
+
*/
|
|
404
|
+
const injectedFamilies = /* @__PURE__ */ new Set();
|
|
405
|
+
/**
|
|
406
|
+
* Generate Google Fonts URL for the given family and variants
|
|
407
|
+
*/
|
|
408
|
+
function generateFontUrl(family, variants) {
|
|
409
|
+
const regulars = [];
|
|
410
|
+
const italics = [];
|
|
411
|
+
for (const v of variants) {
|
|
412
|
+
if (v === "regular") {
|
|
413
|
+
regulars.push(400);
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
if (v === "italic") {
|
|
417
|
+
italics.push(400);
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
if (v.endsWith("italic")) {
|
|
421
|
+
italics.push(parseInt(v) || 400);
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
const n = parseInt(v);
|
|
425
|
+
if (!isNaN(n)) regulars.push(n);
|
|
426
|
+
}
|
|
427
|
+
let url;
|
|
428
|
+
if (italics.length === 0) {
|
|
429
|
+
const wghtParam = regulars.map((w) => `0,${w}`).join(";");
|
|
430
|
+
url = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(family)}:ital,wght@${wghtParam}&display=swap`;
|
|
431
|
+
} else if (regulars.length === 0) {
|
|
432
|
+
const wghtParam = italics.map((w) => `1,${w}`).join(";");
|
|
433
|
+
url = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(family)}:ital,wght@${wghtParam}&display=swap`;
|
|
434
|
+
} else {
|
|
435
|
+
const pairs = [...regulars.map((w) => `0,${w}`), ...italics.map((w) => `1,${w}`)].join(";");
|
|
436
|
+
url = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(family)}:ital,wght@${pairs}&display=swap`;
|
|
437
|
+
}
|
|
438
|
+
return url;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Load a Google Font by injecting a <link> in the <head>
|
|
442
|
+
*/
|
|
443
|
+
function loadGoogleFont(family, style = "normal", weight = "400") {
|
|
444
|
+
if (injectedFamilies.has(family)) return;
|
|
445
|
+
const variants = [];
|
|
446
|
+
if (style === "italic") variants.push(weight.endsWith("italic") ? weight : `${weight}italic`);
|
|
447
|
+
else variants.push(weight === "regular" ? "regular" : weight);
|
|
448
|
+
const url = generateFontUrl(family, variants);
|
|
449
|
+
const link = document.createElement("link");
|
|
450
|
+
link.rel = "stylesheet";
|
|
451
|
+
link.href = url;
|
|
452
|
+
document.head.appendChild(link);
|
|
453
|
+
injectedFamilies.add(family);
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Load fonts from button variants
|
|
457
|
+
*/
|
|
458
|
+
function loadFontsFromButtonVariants(variants) {
|
|
459
|
+
for (const variant of variants) if (variant.fontFamily) loadGoogleFont(variant.fontFamily, variant.fontStyle || "normal", variant.fontWeight || "400");
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Load fonts from typography global config
|
|
463
|
+
*/
|
|
464
|
+
function loadFontsFromTypography(typography) {
|
|
465
|
+
if (typography.globalConfig?.fontFamily) loadGoogleFont(typography.globalConfig.fontFamily);
|
|
466
|
+
if (typography.variants) {
|
|
467
|
+
for (const variant of typography.variants) if (variant.fontFamily) loadGoogleFont(variant.fontFamily, variant.fontStyle || "normal", variant.fontWeight || "400");
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Load fonts from forms global config
|
|
472
|
+
*/
|
|
473
|
+
function loadFontsFromForms(forms) {
|
|
474
|
+
if (forms.globalConfig?.fontFamily) loadGoogleFont(forms.globalConfig.fontFamily);
|
|
475
|
+
if (forms.globalConfig?.optionFontFamily) loadGoogleFont(forms.globalConfig.optionFontFamily);
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Load fonts from avatar variants
|
|
479
|
+
*/
|
|
480
|
+
function loadFontsFromAvatarVariants(variants) {
|
|
481
|
+
for (const variant of variants) if (variant.fontFamily) loadGoogleFont(variant.fontFamily, variant.fontStyle || "normal", variant.fontWeight || "400");
|
|
482
|
+
}
|
|
483
|
+
//#endregion
|
|
484
|
+
//#region src/basscss/index.ts
|
|
485
|
+
/**
|
|
486
|
+
* Basscss utilities - included in bundle
|
|
487
|
+
*/
|
|
488
|
+
const BASSCSS_ID = "cux-basscss";
|
|
489
|
+
const BASSCSS_CSS = `.inline{display:inline}.block{display:block}.inline-block{display:inline-block}.table{display:table}.table-cell{display:table-cell}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.overflow-auto{overflow:auto}.clearfix:after,.clearfix:before{content:" ";display:table}.clearfix:after{clear:both}.left{float:left}.right{float:right}.fit{max-width:100%}.max-width-1{max-width:var(--width-1)}.max-width-2{max-width:var(--width-2)}.max-width-3{max-width:var(--width-3)}.max-width-4{max-width:var(--width-4)}.border-box{box-sizing:border-box}:root{--width-1:24rem;--width-2:32rem;--width-3:48rem;--width-4:64rem}.align-baseline{vertical-align:baseline}.align-top{vertical-align:top}.align-middle{vertical-align:middle}.align-bottom{vertical-align:bottom}.m0{margin:0}.mt0{margin-top:0}.mr0{margin-right:0}.mb0{margin-bottom:0}.ml0,.mx0{margin-left:0}.mx0{margin-right:0}.my0{margin-bottom:0;margin-top:0}.m1{margin:var(--space-1)}.mt1{margin-top:var(--space-1)}.mr1{margin-right:var(--space-1)}.mb1{margin-bottom:var(--space-1)}.ml1,.mx1{margin-left:var(--space-1)}.mx1{margin-right:var(--space-1)}.my1{margin-bottom:var(--space-1);margin-top:var(--space-1)}.m2{margin:var(--space-2)}.mt2{margin-top:var(--space-2)}.mr2{margin-right:var(--space-2)}.mb2{margin-bottom:var(--space-2)}.ml2,.mx2{margin-left:var(--space-2)}.mx2{margin-right:var(--space-2)}.my2{margin-bottom:var(--space-2);margin-top:var(--space-2)}.m3{margin:var(--space-3)}.mt3{margin-top:var(--space-3)}.mr3{margin-right:var(--space-3)}.mb3{margin-bottom:var(--space-3)}.ml3,.mx3{margin-left:var(--space-3)}.mx3{margin-right:var(--space-3)}.my3{margin-bottom:var(--space-3);margin-top:var(--space-3)}.m4{margin:var(--space-4)}.mt4{margin-top:var(--space-4)}.mr4{margin-right:var(--space-4)}.mb4{margin-bottom:var(--space-4)}.ml4,.mx4{margin-left:var(--space-4)}.mx4{margin-right:var(--space-4)}.my4{margin-bottom:var(--space-4);margin-top:var(--space-4)}.mxn1{margin-left:calc(var(--space-1)*-1);margin-right:calc(var(--space-1)*-1)}.mxn2{margin-left:calc(var(--space-2)*-1);margin-right:calc(var(--space-2)*-1)}.mxn3{margin-left:calc(var(--space-3)*-1);margin-right:calc(var(--space-3)*-1)}.mxn4{margin-left:calc(var(--space-4)*-1);margin-right:calc(var(--space-4)*-1)}.m-auto{margin:auto}.mt-auto{margin-top:auto}.mr-auto{margin-right:auto}.mb-auto{margin-bottom:auto}.ml-auto,.mx-auto{margin-left:auto}.mx-auto{margin-right:auto}.my-auto{margin-bottom:auto;margin-top:auto}.p0{padding:0}.pt0{padding-top:0}.pr0{padding-right:0}.pb0{padding-bottom:0}.pl0,.px0{padding-left:0}.px0{padding-right:0}.py0{padding-bottom:0;padding-top:0}.p1{padding:var(--space-1)}.pt1{padding-top:var(--space-1)}.pr1{padding-right:var(--space-1)}.pb1{padding-bottom:var(--space-1)}.pl1{padding-left:var(--space-1)}.py1{padding-bottom:var(--space-1);padding-top:var(--space-1)}.px1{padding-left:var(--space-1);padding-right:var(--space-1)}.p2{padding:var(--space-2)}.pt2{padding-top:var(--space-2)}.pr2{padding-right:var(--space-2)}.pb2{padding-bottom:var(--space-2)}.pl2{padding-left:var(--space-2)}.py2{padding-bottom:var(--space-2);padding-top:var(--space-2)}.px2{padding-left:var(--space-2);padding-right:var(--space-2)}.p3{padding:var(--space-3)}.pt3{padding-top:var(--space-3)}.pr3{padding-right:var(--space-3)}.pb3{padding-bottom:var(--space-3)}.pl3{padding-left:var(--space-3)}.py3{padding-bottom:var(--space-3);padding-top:var(--space-3)}.px3{padding-left:var(--space-3);padding-right:var(--space-3)}.p4{padding:var(--space-4)}.pt4{padding-top:var(--space-4)}.pr4{padding-right:var(--space-4)}.pb4{padding-bottom:var(--space-4)}.pl4{padding-left:var(--space-4)}.py4{padding-bottom:var(--space-4);padding-top:var(--space-4)}.px4{padding-left:var(--space-4);padding-right:var(--space-4)}:root{--space-1:.5rem;--space-2:1rem;--space-3:2rem;--space-4:4rem}.col{float:left}.col,.col-right{box-sizing:border-box}.col-right{float:right}.col-1{width:8.33333%}.col-2{width:16.66667%}.col-3{width:25%}.col-4{width:33.33333%}.col-5{width:41.66667%}.col-6{width:50%}.col-7{width:58.33333%}.col-8{width:66.66667%}.col-9{width:75%}.col-10{width:83.33333%}.col-11{width:91.66667%}.col-12{width:100%}.flex{display:flex}.flex-column{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.self-start{align-self:flex-start}.self-end{align-self:flex-end}.self-center{align-self:center}.self-baseline{align-self:baseline}.self-stretch{align-self:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.justify-evenly{justify-content:space-evenly}.content-start{align-content:flex-start}.content-end{align-content:flex-end}.content-center{align-content:center}.content-between{align-content:space-between}.content-around{align-content:space-around}.content-stretch{align-content:stretch}.flex-auto{flex:1 1 auto;min-height:0;min-width:0}.flex-none{flex:none}.order-0{order:0}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-last{order:99999}.relative{position:relative}.absolute{position:absolute}.fixed{position:fixed}.top-0{top:0}.right-0{right:0}.bottom-0{bottom:0}.left-0{left:0}.z1{z-index:var(--z1)}.z2{z-index:var(--z2)}.z3{z-index:var(--z3)}.z4{z-index:var(--z4)}:root{--z1:1;--z2:2;--z3:3;--z4:4}.border{border-style:solid;border-width:var(--border-width)}.border-top{border-top-style:solid;border-top-width:var(--border-width)}.border-right{border-right-style:solid;border-right-width:var(--border-width)}.border-bottom{border-bottom-style:solid;border-bottom-width:var(--border-width)}.border-left{border-left-style:solid;border-left-width:var(--border-width)}.border-none{border:0}.rounded{border-radius:var(--border-radius)}.circle{border-radius:50%}.rounded-top{border-radius:var(--border-radius) var(--border-radius) 0 0}.rounded-right{border-radius:0 var(--border-radius) var(--border-radius) 0}.rounded-bottom{border-radius:0 0 var(--border-radius) var(--border-radius)}.rounded-left{border-radius:var(--border-radius) 0 0 var(--border-radius)}.not-rounded{border-radius:0}:root{--border-width:1px;--border-radius:3px}.hide{height:1px;overflow:hidden;position:absolute!important;width:1px;clip:rect(1px,1px,1px,1px)}.display-none{display:none!important}`;
|
|
490
|
+
let injected = false;
|
|
491
|
+
/**
|
|
492
|
+
* Inject Basscss utilities into the page
|
|
493
|
+
*/
|
|
494
|
+
function injectBasscss() {
|
|
495
|
+
if (injected) return;
|
|
496
|
+
if (typeof document === "undefined") return;
|
|
497
|
+
if (document.getElementById(BASSCSS_ID)) {
|
|
498
|
+
injected = true;
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
const style = document.createElement("style");
|
|
502
|
+
style.id = BASSCSS_ID;
|
|
503
|
+
style.textContent = BASSCSS_CSS;
|
|
504
|
+
document.head.appendChild(style);
|
|
505
|
+
injected = true;
|
|
506
|
+
}
|
|
507
|
+
//#endregion
|
|
508
|
+
//#region src/core/base-styles.ts
|
|
509
|
+
/**
|
|
510
|
+
* Base styles for ComboUX
|
|
511
|
+
*/
|
|
512
|
+
const BASE_STYLES_ID = "cux-base-styles";
|
|
513
|
+
const DEFAULT_OPTIONS = {
|
|
514
|
+
backgroundColor: "#ffffff",
|
|
515
|
+
darkBackgroundColor: "#333333",
|
|
516
|
+
textColor: "#212529",
|
|
517
|
+
darkTextColor: "#f8f9fa"
|
|
518
|
+
};
|
|
519
|
+
/**
|
|
520
|
+
* Build base CSS with dynamic colors
|
|
521
|
+
*/
|
|
522
|
+
function buildBaseCSS(options = DEFAULT_OPTIONS) {
|
|
523
|
+
const bgColor = options.backgroundColor ?? DEFAULT_OPTIONS.backgroundColor;
|
|
524
|
+
const darkBgColor = options.darkBackgroundColor ?? DEFAULT_OPTIONS.darkBackgroundColor;
|
|
525
|
+
return `
|
|
526
|
+
/* Base styles */
|
|
527
|
+
:root {
|
|
528
|
+
--cux-bg: ${bgColor};
|
|
529
|
+
--cux-text: ${options.textColor ?? DEFAULT_OPTIONS.textColor};
|
|
530
|
+
--cux-text-muted: #6c757d;
|
|
531
|
+
--cux-border: #dee2e6;
|
|
532
|
+
--cux-surface: #f8f9fa;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
.dark {
|
|
536
|
+
--cux-bg: ${darkBgColor};
|
|
537
|
+
--cux-text: ${options.darkTextColor ?? DEFAULT_OPTIONS.darkTextColor};
|
|
538
|
+
--cux-text-muted: #adb5bd;
|
|
539
|
+
--cux-border: #495057;
|
|
540
|
+
--cux-surface: #222222;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
body {
|
|
544
|
+
background-color: var(--cux-bg);
|
|
545
|
+
color: var(--cux-text);
|
|
546
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
547
|
+
transition: background-color 0.2s ease, color 0.2s ease;
|
|
548
|
+
}
|
|
549
|
+
`;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Inject base styles with dynamic colors
|
|
553
|
+
*/
|
|
554
|
+
function injectBaseStyles(options) {
|
|
555
|
+
if (typeof document === "undefined") return;
|
|
556
|
+
const existing = document.getElementById(BASE_STYLES_ID);
|
|
557
|
+
if (existing) {
|
|
558
|
+
if (options) existing.textContent = buildBaseCSS(options);
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
const style = document.createElement("style");
|
|
562
|
+
style.id = BASE_STYLES_ID;
|
|
563
|
+
style.textContent = buildBaseCSS(options);
|
|
564
|
+
document.head.insertBefore(style, document.head.firstChild);
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Update base styles (for theme updates)
|
|
568
|
+
*/
|
|
569
|
+
function updateBaseStyles(options) {
|
|
570
|
+
if (typeof document === "undefined") return;
|
|
571
|
+
const existing = document.getElementById(BASE_STYLES_ID);
|
|
572
|
+
if (existing) existing.textContent = buildBaseCSS(options);
|
|
573
|
+
else injectBaseStyles(options);
|
|
574
|
+
}
|
|
575
|
+
//#endregion
|
|
576
|
+
//#region src/core/utils.ts
|
|
577
|
+
/**
|
|
578
|
+
* Convert a string to kebab-case for CSS class names
|
|
579
|
+
* Removes accents and special characters
|
|
580
|
+
*/
|
|
581
|
+
function toKebabCase(str) {
|
|
582
|
+
return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Build a CSS border string from BorderValue
|
|
586
|
+
*/
|
|
587
|
+
function buildBorder(border) {
|
|
588
|
+
if (!border) return "";
|
|
589
|
+
return `${border.width}${border.unit} ${border.style} ${border.color}`;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Build a CSS border-radius string from BorderRadiusValue
|
|
593
|
+
*/
|
|
594
|
+
function buildBorderRadius(radius) {
|
|
595
|
+
if (!radius) return "";
|
|
596
|
+
if (radius.linked) return `${radius.tl}${radius.unit}`;
|
|
597
|
+
return `${radius.tl}${radius.unit} ${radius.tr}${radius.unit} ${radius.br}${radius.unit} ${radius.bl}${radius.unit}`;
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Build a CSS padding string from PaddingValue
|
|
601
|
+
*/
|
|
602
|
+
function buildPadding(padding) {
|
|
603
|
+
if (!padding) return "";
|
|
604
|
+
const { top, right, bottom, left, unit } = padding;
|
|
605
|
+
if (top === right && right === bottom && bottom === left) return `${top}${unit}`;
|
|
606
|
+
if (top === bottom && right === left) return `${top}${unit} ${right}${unit}`;
|
|
607
|
+
return `${top}${unit} ${right}${unit} ${bottom}${unit} ${left}${unit}`;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Build a CSS font-size string from UnitNumber
|
|
611
|
+
*/
|
|
612
|
+
function buildFontSize(fontSize) {
|
|
613
|
+
if (!fontSize) return "";
|
|
614
|
+
return `${fontSize.value}${fontSize.unit}`;
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Build a CSS letter-spacing string
|
|
618
|
+
*/
|
|
619
|
+
function buildLetterSpacing(value) {
|
|
620
|
+
if (!value) return "";
|
|
621
|
+
if (typeof value === "object" && "value" in value) return `${value.value}${value.unit}`;
|
|
622
|
+
if (typeof value === "string") {
|
|
623
|
+
if (value.endsWith("px") || value.endsWith("em") || value.endsWith("rem")) return value;
|
|
624
|
+
return `${value}px`;
|
|
625
|
+
}
|
|
626
|
+
return "";
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Build a CSS border string from BorderValue | string
|
|
630
|
+
*/
|
|
631
|
+
function buildBorderOptional(border) {
|
|
632
|
+
if (!border) return "";
|
|
633
|
+
if (typeof border === "string") return border;
|
|
634
|
+
return `${border.width}${border.unit} ${border.style} ${border.color}`;
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Build a CSS offset string from UnitNumber | number
|
|
638
|
+
*/
|
|
639
|
+
function buildOffset(offset) {
|
|
640
|
+
if (offset === void 0) return "";
|
|
641
|
+
if (typeof offset === "number") return `${offset}px`;
|
|
642
|
+
return `${offset.value}${offset.unit}`;
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Deep merge objects (for dark mode overrides)
|
|
646
|
+
*/
|
|
647
|
+
function deepMerge(target, source) {
|
|
648
|
+
if (!source) return target;
|
|
649
|
+
const result = { ...target };
|
|
650
|
+
for (const key in source) {
|
|
651
|
+
const sourceValue = source[key];
|
|
652
|
+
const targetValue = target[key];
|
|
653
|
+
if (sourceValue !== void 0 && sourceValue !== null && typeof sourceValue === "object" && !Array.isArray(sourceValue) && targetValue !== null && typeof targetValue === "object" && !Array.isArray(targetValue)) result[key] = deepMerge(targetValue, sourceValue);
|
|
654
|
+
else if (sourceValue !== void 0) result[key] = sourceValue;
|
|
655
|
+
}
|
|
656
|
+
return result;
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Get effective font family (fallback to global config)
|
|
660
|
+
* Shared utility used by all component generators
|
|
661
|
+
*/
|
|
662
|
+
function getEffectiveFontFamily$2(variantFontFamily, globalFontFamily) {
|
|
663
|
+
if (variantFontFamily !== null && variantFontFamily !== void 0) return variantFontFamily;
|
|
664
|
+
return globalFontFamily || null;
|
|
665
|
+
}
|
|
666
|
+
//#endregion
|
|
667
|
+
//#region src/core/typography-generator.ts
|
|
668
|
+
/**
|
|
669
|
+
* Build CSS value from UnitNumber or string
|
|
670
|
+
*/
|
|
671
|
+
function buildUnitValue$1(value, defaultUnit = "px") {
|
|
672
|
+
if (!value) return "";
|
|
673
|
+
if (typeof value === "string") return value;
|
|
674
|
+
return `${value.value}${value.unit || defaultUnit}`;
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Get effective font family (fallback to global)
|
|
678
|
+
*/
|
|
679
|
+
function getEffectiveFontFamily$1(variant, globalConfig) {
|
|
680
|
+
return variant.fontFamily || globalConfig?.fontFamily || "system-ui, sans-serif";
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* Get effective color (fallback to global)
|
|
684
|
+
*/
|
|
685
|
+
function getEffectiveColor(variant, globalConfig, isDark = false) {
|
|
686
|
+
const darkOverride = isDark ? variant.dark?.color : null;
|
|
687
|
+
const globalDarkOverride = isDark ? globalConfig?.dark?.color : null;
|
|
688
|
+
if (darkOverride) return darkOverride;
|
|
689
|
+
if (variant.color) return variant.color;
|
|
690
|
+
if (globalDarkOverride) return globalDarkOverride;
|
|
691
|
+
if (globalConfig?.color) return globalConfig.color;
|
|
692
|
+
return isDark ? "#f8f9fa" : "#212529";
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Get line height as CSS value
|
|
696
|
+
*/
|
|
697
|
+
function buildLineHeight(value) {
|
|
698
|
+
if (!value) return "1.5";
|
|
699
|
+
return `${value.value}${value.unit || ""}`;
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Generate CSS for a single typography variant
|
|
703
|
+
*/
|
|
704
|
+
function generateTypographyVariantCSS(variant, globalConfig) {
|
|
705
|
+
const fontFamily = getEffectiveFontFamily$1(variant, globalConfig);
|
|
706
|
+
const color = getEffectiveColor(variant, globalConfig, false);
|
|
707
|
+
const css = [];
|
|
708
|
+
css.push(` font-family: '${fontFamily}', sans-serif;`);
|
|
709
|
+
css.push(` font-style: ${variant.fontStyle || "normal"};`);
|
|
710
|
+
css.push(` font-weight: ${variant.fontWeight || "400"};`);
|
|
711
|
+
if (variant.fontSize) css.push(` font-size: ${buildFontSize(variant.fontSize)};`);
|
|
712
|
+
if (variant.letterSpacing) css.push(` letter-spacing: ${buildUnitValue$1(variant.letterSpacing)};`);
|
|
713
|
+
if (variant.lineHeight) css.push(` line-height: ${buildLineHeight(variant.lineHeight)};`);
|
|
714
|
+
if (variant.textTransform) css.push(` text-transform: ${variant.textTransform};`);
|
|
715
|
+
if (variant.textDecoration) css.push(` text-decoration: ${variant.textDecoration};`);
|
|
716
|
+
css.push(` color: ${color};`);
|
|
717
|
+
return css.join("\n");
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Generate complete typography CSS
|
|
721
|
+
*/
|
|
722
|
+
function generateTypographyCSS(typography) {
|
|
723
|
+
const css = [];
|
|
724
|
+
const globalConfig = typography.globalConfig;
|
|
725
|
+
const variants = typography.variants || [];
|
|
726
|
+
css.push(`/* Typography Base */`);
|
|
727
|
+
css.push(`.cux-typography {`);
|
|
728
|
+
if (globalConfig?.fontFamily) css.push(` font-family: '${globalConfig.fontFamily}', sans-serif;`);
|
|
729
|
+
if (globalConfig?.color) css.push(` color: ${globalConfig.color};`);
|
|
730
|
+
css.push(`}`);
|
|
731
|
+
css.push("");
|
|
732
|
+
const headingVariants = variants.filter((v) => [
|
|
733
|
+
"h1",
|
|
734
|
+
"h2",
|
|
735
|
+
"h3",
|
|
736
|
+
"h4",
|
|
737
|
+
"h5",
|
|
738
|
+
"h6"
|
|
739
|
+
].includes(v.id));
|
|
740
|
+
const displayVariants = variants.filter((v) => v.id?.startsWith("display"));
|
|
741
|
+
const bodyVariants = variants.filter((v) => [
|
|
742
|
+
"body",
|
|
743
|
+
"small",
|
|
744
|
+
"caption",
|
|
745
|
+
"link"
|
|
746
|
+
].includes(v.id));
|
|
747
|
+
if (headingVariants.length > 0) {
|
|
748
|
+
css.push(`/* Headings */`);
|
|
749
|
+
headingVariants.forEach((variant) => {
|
|
750
|
+
css.push(`.cux-${variant.id} {`);
|
|
751
|
+
css.push(generateTypographyVariantCSS(variant, globalConfig));
|
|
752
|
+
css.push(`}`);
|
|
753
|
+
css.push(`.dark .cux-${variant.id} {`);
|
|
754
|
+
css.push(` color: ${getEffectiveColor(variant, globalConfig, true)};`);
|
|
755
|
+
css.push(`}`);
|
|
756
|
+
});
|
|
757
|
+
css.push("");
|
|
758
|
+
}
|
|
759
|
+
if (displayVariants.length > 0) {
|
|
760
|
+
css.push(`/* Display */`);
|
|
761
|
+
displayVariants.forEach((variant) => {
|
|
762
|
+
css.push(`.cux-${variant.id} {`);
|
|
763
|
+
css.push(generateTypographyVariantCSS(variant, globalConfig));
|
|
764
|
+
css.push(`}`);
|
|
765
|
+
css.push(`.dark .cux-${variant.id} {`);
|
|
766
|
+
css.push(` color: ${getEffectiveColor(variant, globalConfig, true)};`);
|
|
767
|
+
css.push(`}`);
|
|
768
|
+
});
|
|
769
|
+
css.push("");
|
|
770
|
+
}
|
|
771
|
+
if (bodyVariants.length > 0) {
|
|
772
|
+
css.push(`/* Body Text */`);
|
|
773
|
+
bodyVariants.forEach((variant) => {
|
|
774
|
+
css.push(`.cux-${variant.id} {`);
|
|
775
|
+
css.push(generateTypographyVariantCSS(variant, globalConfig));
|
|
776
|
+
css.push(`}`);
|
|
777
|
+
css.push(`.dark .cux-${variant.id} {`);
|
|
778
|
+
css.push(` color: ${getEffectiveColor(variant, globalConfig, true)};`);
|
|
779
|
+
css.push(`}`);
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
return css.join("\n");
|
|
783
|
+
}
|
|
784
|
+
//#endregion
|
|
785
|
+
//#region src/core/forms-generator.ts
|
|
786
|
+
/**
|
|
787
|
+
* Build CSS value from UnitNumber
|
|
788
|
+
*/
|
|
789
|
+
function buildUnitValue(value, defaultUnit = "px") {
|
|
790
|
+
if (!value) return "";
|
|
791
|
+
return `${value.value}${value.unit || defaultUnit}`;
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Get effective font family (fallback to typography)
|
|
795
|
+
*/
|
|
796
|
+
function getEffectiveFontFamily(formsFontFamily, typography) {
|
|
797
|
+
if (formsFontFamily) return formsFontFamily;
|
|
798
|
+
if (typography?.globalConfig?.fontFamily) return typography.globalConfig.fontFamily;
|
|
799
|
+
return "system-ui, sans-serif";
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* Generate complete forms CSS
|
|
803
|
+
*/
|
|
804
|
+
function generateFormsCSS(forms, typography) {
|
|
805
|
+
const css = [];
|
|
806
|
+
const config = forms.globalConfig;
|
|
807
|
+
if (!config) return "";
|
|
808
|
+
const effectiveFontFamily = getEffectiveFontFamily(config.fontFamily, typography);
|
|
809
|
+
css.push(`/* Forms Base Styles */`);
|
|
810
|
+
css.push(`.cux-field {`);
|
|
811
|
+
css.push(` position: relative;`);
|
|
812
|
+
css.push(` margin-bottom: ${config.fieldHeight || 95}px;`);
|
|
813
|
+
css.push(`}`);
|
|
814
|
+
if (config.showLabel) {
|
|
815
|
+
css.push(`.cux-label {`);
|
|
816
|
+
css.push(` display: block;`);
|
|
817
|
+
css.push(` font-family: '${effectiveFontFamily}', sans-serif;`);
|
|
818
|
+
css.push(` color: ${config.labelColor || "#212529"};`);
|
|
819
|
+
if (config.labelFontSize) css.push(` font-size: ${buildFontSize(config.labelFontSize)};`);
|
|
820
|
+
css.push(` font-weight: ${config.labelFontWeight || "500"};`);
|
|
821
|
+
css.push(` margin-bottom: ${config.labelMarginBottom || 4}px;`);
|
|
822
|
+
css.push(`}`);
|
|
823
|
+
css.push(`.dark .cux-label {`);
|
|
824
|
+
css.push(` color: ${config.dark?.labelColor || "#f8f9fa"};`);
|
|
825
|
+
css.push(`}`);
|
|
826
|
+
}
|
|
827
|
+
css.push(`.cux-input {`);
|
|
828
|
+
css.push(` width: 100%;`);
|
|
829
|
+
css.push(` font-family: '${effectiveFontFamily}', sans-serif;`);
|
|
830
|
+
css.push(` font-size: ${buildFontSize(config.fontSize || {
|
|
831
|
+
value: 14,
|
|
832
|
+
unit: "px"
|
|
833
|
+
})};`);
|
|
834
|
+
css.push(` color: ${config.color || "#212529"};`);
|
|
835
|
+
css.push(` background: ${config.background || "#ffffff"};`);
|
|
836
|
+
css.push(` border: ${buildBorder(config.border)};`);
|
|
837
|
+
css.push(` border-radius: ${buildBorderRadius(config.borderRadius)};`);
|
|
838
|
+
css.push(` padding: ${buildPadding(config.padding)};`);
|
|
839
|
+
css.push(` transition: border-color 0.15s ease, box-shadow 0.15s ease;`);
|
|
840
|
+
css.push(`}`);
|
|
841
|
+
css.push(`.dark .cux-input {`);
|
|
842
|
+
css.push(` color: ${config.dark?.color || "#f8f9fa"};`);
|
|
843
|
+
css.push(` background: ${config.dark?.background || "#222222"};`);
|
|
844
|
+
css.push(` border-color: ${config.dark?.borderColor || "#495057"};`);
|
|
845
|
+
css.push(`}`);
|
|
846
|
+
if (config.showPlaceholder) {
|
|
847
|
+
css.push(`.cux-input::placeholder {`);
|
|
848
|
+
css.push(` color: ${config.placeholderColor || "#6c757d"};`);
|
|
849
|
+
css.push(` opacity: 1;`);
|
|
850
|
+
css.push(`}`);
|
|
851
|
+
css.push(`.dark .cux-input::placeholder {`);
|
|
852
|
+
css.push(` color: ${config.dark?.placeholderColor || "#adb5bd"};`);
|
|
853
|
+
css.push(`}`);
|
|
854
|
+
}
|
|
855
|
+
css.push(`.cux-input:focus {`);
|
|
856
|
+
css.push(` outline: none;`);
|
|
857
|
+
css.push(` border-color: ${config.border?.color || "#ced4da"};`);
|
|
858
|
+
css.push(` box-shadow: 0 0 0 ${config.focusOutlineWidth || 3}px ${config.focusOutlineColor || "rgba(13, 110, 253, 0.16)"};`);
|
|
859
|
+
css.push(`}`);
|
|
860
|
+
css.push(`.dark .cux-input:focus {`);
|
|
861
|
+
css.push(` border-color: ${config.dark?.borderColor || "#495057"};`);
|
|
862
|
+
css.push(` box-shadow: 0 0 0 ${config.focusOutlineWidth || 3}px ${config.dark?.focusOutlineColor || "rgba(117, 149, 194, 0.4)"};`);
|
|
863
|
+
css.push(`}`);
|
|
864
|
+
css.push(`.cux-input.cux-error,`);
|
|
865
|
+
css.push(`.cux-input[aria-invalid="true"] {`);
|
|
866
|
+
css.push(` border-color: ${config.errorBorderColor || "#dc3545"};`);
|
|
867
|
+
css.push(`}`);
|
|
868
|
+
css.push(`.dark .cux-input.cux-error,`);
|
|
869
|
+
css.push(`.dark .cux-input[aria-invalid="true"] {`);
|
|
870
|
+
css.push(` border-color: ${config.dark?.errorBorderColor || "#ea868f"};`);
|
|
871
|
+
css.push(`}`);
|
|
872
|
+
css.push(`.cux-error-message {`);
|
|
873
|
+
css.push(` font-family: '${effectiveFontFamily}', sans-serif;`);
|
|
874
|
+
css.push(` color: ${config.errorColor || "#dc3545"};`);
|
|
875
|
+
if (config.errorFontSize) css.push(` font-size: ${buildFontSize(config.errorFontSize)};`);
|
|
876
|
+
css.push(` margin-top: ${config.errorMarginTop || 4}px;`);
|
|
877
|
+
css.push(`}`);
|
|
878
|
+
css.push(`.dark .cux-error-message {`);
|
|
879
|
+
css.push(` color: ${config.dark?.errorColor || "#ea868f"};`);
|
|
880
|
+
css.push(`}`);
|
|
881
|
+
css.push(`.cux-input:disabled {`);
|
|
882
|
+
css.push(` opacity: ${config.disabledOpacity || .65};`);
|
|
883
|
+
css.push(` color: ${config.disabledColor || "#6c757d"};`);
|
|
884
|
+
css.push(` background: ${config.disabledBackground || "#e9ecef"};`);
|
|
885
|
+
css.push(` border-color: ${config.disabledBorderColor || "#ced4da"};`);
|
|
886
|
+
css.push(` cursor: not-allowed;`);
|
|
887
|
+
css.push(`}`);
|
|
888
|
+
css.push(`.dark .cux-input:disabled {`);
|
|
889
|
+
css.push(` color: ${config.dark?.disabledColor || "#6c757d"};`);
|
|
890
|
+
css.push(` background: ${config.dark?.disabledBackground || "#222222"};`);
|
|
891
|
+
css.push(` border-color: ${config.dark?.disabledBorderColor || "#495057"};`);
|
|
892
|
+
css.push(`}`);
|
|
893
|
+
css.push(``);
|
|
894
|
+
css.push(`/* Checkbox & Radio */`);
|
|
895
|
+
const checkSize = config.checkRadioSize || 18;
|
|
896
|
+
css.push(`.cux-checkbox,`);
|
|
897
|
+
css.push(`.cux-radio {`);
|
|
898
|
+
css.push(` display: inline-flex;`);
|
|
899
|
+
css.push(` align-items: center;`);
|
|
900
|
+
css.push(` gap: 8px;`);
|
|
901
|
+
css.push(` cursor: pointer;`);
|
|
902
|
+
css.push(`}`);
|
|
903
|
+
css.push(`.cux-checkbox input,`);
|
|
904
|
+
css.push(`.cux-radio input {`);
|
|
905
|
+
css.push(` width: ${checkSize}px;`);
|
|
906
|
+
css.push(` height: ${checkSize}px;`);
|
|
907
|
+
css.push(` accent-color: ${config.checkRadioColor || "#0d6efd"};`);
|
|
908
|
+
css.push(` cursor: pointer;`);
|
|
909
|
+
css.push(`}`);
|
|
910
|
+
css.push(`.dark .cux-checkbox input,`);
|
|
911
|
+
css.push(`.dark .cux-radio input {`);
|
|
912
|
+
css.push(` accent-color: ${config.dark?.checkRadioColor || "#6ea8fe"};`);
|
|
913
|
+
css.push(`}`);
|
|
914
|
+
css.push(`.cux-option-label {`);
|
|
915
|
+
css.push(` font-family: '${config.optionFontFamily || effectiveFontFamily}', sans-serif;`);
|
|
916
|
+
css.push(` color: ${config.optionColor || "#212529"};`);
|
|
917
|
+
if (config.optionFontSize) css.push(` font-size: ${buildFontSize(config.optionFontSize)};`);
|
|
918
|
+
css.push(` font-weight: ${config.optionFontWeight || "400"};`);
|
|
919
|
+
css.push(`}`);
|
|
920
|
+
css.push(`.dark .cux-option-label {`);
|
|
921
|
+
css.push(` color: ${config.dark?.optionColor || "#f8f9fa"};`);
|
|
922
|
+
css.push(`}`);
|
|
923
|
+
const spacingH = config.optionSpacingHorizontal;
|
|
924
|
+
const spacingV = config.optionSpacingVertical;
|
|
925
|
+
css.push(`.cux-option-group {`);
|
|
926
|
+
css.push(` display: flex;`);
|
|
927
|
+
if (config.optionOrientation === "vertical") {
|
|
928
|
+
css.push(` flex-direction: column;`);
|
|
929
|
+
if (spacingV) css.push(` gap: ${buildUnitValue(spacingV)};`);
|
|
930
|
+
} else {
|
|
931
|
+
css.push(` flex-direction: row;`);
|
|
932
|
+
css.push(` flex-wrap: wrap;`);
|
|
933
|
+
if (spacingH) css.push(` gap: ${buildUnitValue(spacingH)};`);
|
|
934
|
+
}
|
|
935
|
+
css.push(`}`);
|
|
936
|
+
css.push(``);
|
|
937
|
+
css.push(`/* Select */`);
|
|
938
|
+
css.push(`.cux-select {`);
|
|
939
|
+
css.push(` width: 100%;`);
|
|
940
|
+
css.push(` font-family: '${effectiveFontFamily}', sans-serif;`);
|
|
941
|
+
css.push(` font-size: ${buildFontSize(config.fontSize || {
|
|
942
|
+
value: 14,
|
|
943
|
+
unit: "px"
|
|
944
|
+
})};`);
|
|
945
|
+
css.push(` color: ${config.color || "#212529"};`);
|
|
946
|
+
css.push(` background: ${config.background || "#ffffff"};`);
|
|
947
|
+
css.push(` border: ${buildBorder(config.border)};`);
|
|
948
|
+
css.push(` border-radius: ${buildBorderRadius(config.borderRadius)};`);
|
|
949
|
+
css.push(` padding: ${buildPadding(config.padding)};`);
|
|
950
|
+
css.push(` cursor: pointer;`);
|
|
951
|
+
css.push(` appearance: none;`);
|
|
952
|
+
css.push(` background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236c757d' d='M6 8L1 3h10z'/%3E%3C/svg%3E");`);
|
|
953
|
+
css.push(` background-repeat: no-repeat;`);
|
|
954
|
+
css.push(` background-position: right 12px center;`);
|
|
955
|
+
css.push(` padding-right: 36px;`);
|
|
956
|
+
css.push(`}`);
|
|
957
|
+
css.push(`.dark .cux-select {`);
|
|
958
|
+
css.push(` color: ${config.dark?.color || "#f8f9fa"};`);
|
|
959
|
+
css.push(` background: ${config.dark?.background || "#222222"};`);
|
|
960
|
+
css.push(` border-color: ${config.dark?.borderColor || "#495057"};`);
|
|
961
|
+
css.push(`}`);
|
|
962
|
+
css.push(``);
|
|
963
|
+
css.push(`/* Textarea */`);
|
|
964
|
+
css.push(`.cux-textarea {`);
|
|
965
|
+
css.push(` width: 100%;`);
|
|
966
|
+
css.push(` min-height: 100px;`);
|
|
967
|
+
css.push(` font-family: '${effectiveFontFamily}', sans-serif;`);
|
|
968
|
+
css.push(` font-size: ${buildFontSize(config.fontSize || {
|
|
969
|
+
value: 14,
|
|
970
|
+
unit: "px"
|
|
971
|
+
})};`);
|
|
972
|
+
css.push(` color: ${config.color || "#212529"};`);
|
|
973
|
+
css.push(` background: ${config.background || "#ffffff"};`);
|
|
974
|
+
css.push(` border: ${buildBorder(config.border)};`);
|
|
975
|
+
css.push(` border-radius: ${buildBorderRadius(config.borderRadius)};`);
|
|
976
|
+
css.push(` padding: ${buildPadding(config.padding)};`);
|
|
977
|
+
css.push(` resize: vertical;`);
|
|
978
|
+
css.push(`}`);
|
|
979
|
+
css.push(`.dark .cux-textarea {`);
|
|
980
|
+
css.push(` color: ${config.dark?.color || "#f8f9fa"};`);
|
|
981
|
+
css.push(` background: ${config.dark?.background || "#222222"};`);
|
|
982
|
+
css.push(` border-color: ${config.dark?.borderColor || "#495057"};`);
|
|
983
|
+
css.push(`}`);
|
|
984
|
+
css.push(``);
|
|
985
|
+
css.push(`/* File / Dropzone */`);
|
|
986
|
+
css.push(`.cux-dropzone {`);
|
|
987
|
+
css.push(` display: flex;`);
|
|
988
|
+
css.push(` flex-direction: column;`);
|
|
989
|
+
css.push(` align-items: center;`);
|
|
990
|
+
css.push(` justify-content: center;`);
|
|
991
|
+
css.push(` padding: ${buildPadding(config.padding)};`);
|
|
992
|
+
css.push(` min-height: 120px;`);
|
|
993
|
+
css.push(` font-family: '${effectiveFontFamily}', sans-serif;`);
|
|
994
|
+
css.push(` background: ${config.dropzoneBackground || "#f8f9fa"};`);
|
|
995
|
+
css.push(` color: ${config.dropzoneColor || "#6c757d"};`);
|
|
996
|
+
if (config.dropzoneBorder) css.push(` border: ${buildBorder(config.dropzoneBorder)};`);
|
|
997
|
+
if (config.dropzoneBorderRadius) css.push(` border-radius: ${buildBorderRadius(config.dropzoneBorderRadius)};`);
|
|
998
|
+
css.push(` cursor: pointer;`);
|
|
999
|
+
css.push(` transition: background-color 0.15s ease, border-color 0.15s ease;`);
|
|
1000
|
+
css.push(`}`);
|
|
1001
|
+
css.push(`.dark .cux-dropzone {`);
|
|
1002
|
+
css.push(` background: ${config.dark?.dropzoneBackground || "#222222"};`);
|
|
1003
|
+
css.push(` color: ${config.dark?.dropzoneColor || "#adb5bd"};`);
|
|
1004
|
+
css.push(` border-color: ${config.dark?.dropzoneBorderColor || "#495057"};`);
|
|
1005
|
+
css.push(`}`);
|
|
1006
|
+
css.push(`.cux-dropzone:hover {`);
|
|
1007
|
+
css.push(` background: ${config.dropzoneBackground || "#f8f9fa"}dd;`);
|
|
1008
|
+
css.push(`}`);
|
|
1009
|
+
return css.join("\n");
|
|
1010
|
+
}
|
|
1011
|
+
//#endregion
|
|
1012
|
+
//#region src/core/button-generator.ts
|
|
1013
|
+
/**
|
|
1014
|
+
* Generate complete CSS for button component
|
|
1015
|
+
*/
|
|
1016
|
+
function generateButtonCSS(variants, globalTypography) {
|
|
1017
|
+
const css = [];
|
|
1018
|
+
css.push(generateButtonBase(globalTypography));
|
|
1019
|
+
variants.forEach((variant) => {
|
|
1020
|
+
const variantName = toKebabCase(variant.name);
|
|
1021
|
+
css.push(generateButtonVariant(variant, variantName, globalTypography));
|
|
1022
|
+
if (variant.dark) {
|
|
1023
|
+
const mergedVariant = deepMerge({ ...variant }, variant.dark);
|
|
1024
|
+
css.push(generateButtonVariantDark(mergedVariant, variantName, globalTypography));
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
1027
|
+
return css.join("\n\n");
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* Generate base button styles
|
|
1031
|
+
*/
|
|
1032
|
+
function generateButtonBase(_globalTypography) {
|
|
1033
|
+
return `/* Button Base Styles */
|
|
1034
|
+
.cux-button {
|
|
1035
|
+
/* CSS Custom Properties (set by variants) */
|
|
1036
|
+
--cux-btn-bg: transparent;
|
|
1037
|
+
--cux-btn-color: inherit;
|
|
1038
|
+
--cux-btn-border: none;
|
|
1039
|
+
--cux-btn-radius: 0;
|
|
1040
|
+
--cux-btn-padding: 0;
|
|
1041
|
+
--cux-btn-font: inherit;
|
|
1042
|
+
--cux-btn-font-size: inherit;
|
|
1043
|
+
--cux-btn-font-weight: inherit;
|
|
1044
|
+
--cux-btn-font-style: inherit;
|
|
1045
|
+
--cux-btn-letter-spacing: inherit;
|
|
1046
|
+
--cux-btn-shadow: none;
|
|
1047
|
+
|
|
1048
|
+
/* Hover state variables */
|
|
1049
|
+
--cux-btn-hover-bg: var(--cux-btn-bg);
|
|
1050
|
+
--cux-btn-hover-color: var(--cux-btn-color);
|
|
1051
|
+
--cux-btn-hover-border: var(--cux-btn-border);
|
|
1052
|
+
|
|
1053
|
+
/* Active state variables */
|
|
1054
|
+
--cux-btn-active-bg: var(--cux-btn-bg);
|
|
1055
|
+
--cux-btn-active-color: var(--cux-btn-color);
|
|
1056
|
+
--cux-btn-active-border: var(--cux-btn-border);
|
|
1057
|
+
|
|
1058
|
+
/* Focus state variables */
|
|
1059
|
+
--cux-btn-focus-color: #3b82f6;
|
|
1060
|
+
--cux-btn-focus-offset: 2px;
|
|
1061
|
+
|
|
1062
|
+
/* Disabled state variables */
|
|
1063
|
+
--cux-btn-disabled-bg: var(--cux-btn-bg);
|
|
1064
|
+
--cux-btn-disabled-color: var(--cux-btn-color);
|
|
1065
|
+
--cux-btn-disabled-border: var(--cux-btn-border);
|
|
1066
|
+
--cux-btn-disabled-opacity: 0.5;
|
|
1067
|
+
|
|
1068
|
+
/* Base styles */
|
|
1069
|
+
background: var(--cux-btn-bg);
|
|
1070
|
+
color: var(--cux-btn-color);
|
|
1071
|
+
border: var(--cux-btn-border);
|
|
1072
|
+
border-radius: var(--cux-btn-radius);
|
|
1073
|
+
padding: var(--cux-btn-padding);
|
|
1074
|
+
font-family: var(--cux-btn-font);
|
|
1075
|
+
font-size: var(--cux-btn-font-size);
|
|
1076
|
+
font-weight: var(--cux-btn-font-weight);
|
|
1077
|
+
font-style: var(--cux-btn-font-style);
|
|
1078
|
+
letter-spacing: var(--cux-btn-letter-spacing);
|
|
1079
|
+
box-shadow: var(--cux-btn-shadow);
|
|
1080
|
+
|
|
1081
|
+
cursor: pointer;
|
|
1082
|
+
display: inline-flex;
|
|
1083
|
+
align-items: center;
|
|
1084
|
+
justify-content: center;
|
|
1085
|
+
gap: 8px;
|
|
1086
|
+
text-decoration: none;
|
|
1087
|
+
transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
/* Hover state */
|
|
1091
|
+
.cux-button:hover:not(:disabled) {
|
|
1092
|
+
background: var(--cux-btn-hover-bg);
|
|
1093
|
+
color: var(--cux-btn-hover-color);
|
|
1094
|
+
border: var(--cux-btn-hover-border);
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
/* Active state */
|
|
1098
|
+
.cux-button:active:not(:disabled) {
|
|
1099
|
+
background: var(--cux-btn-active-bg);
|
|
1100
|
+
color: var(--cux-btn-active-color);
|
|
1101
|
+
border: var(--cux-btn-active-border);
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
/* Focus state */
|
|
1105
|
+
.cux-button:focus-visible {
|
|
1106
|
+
outline: 2px solid var(--cux-btn-focus-color);
|
|
1107
|
+
outline-offset: var(--cux-btn-focus-offset);
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
/* Disabled state */
|
|
1111
|
+
.cux-button:disabled {
|
|
1112
|
+
background: var(--cux-btn-disabled-bg);
|
|
1113
|
+
color: var(--cux-btn-disabled-color);
|
|
1114
|
+
border: var(--cux-btn-disabled-border);
|
|
1115
|
+
opacity: var(--cux-btn-disabled-opacity);
|
|
1116
|
+
cursor: not-allowed;
|
|
1117
|
+
}`;
|
|
1118
|
+
}
|
|
1119
|
+
/**
|
|
1120
|
+
* Generate CSS for a specific button variant
|
|
1121
|
+
*/
|
|
1122
|
+
function generateButtonVariant(variant, variantName, globalTypography) {
|
|
1123
|
+
const lines = [];
|
|
1124
|
+
lines.push(`/* Variant: ${variant.name} */`);
|
|
1125
|
+
lines.push(`.cux-button.--${variantName} {`);
|
|
1126
|
+
lines.push(` --cux-btn-bg: ${variant.background};`);
|
|
1127
|
+
lines.push(` --cux-btn-color: ${variant.color};`);
|
|
1128
|
+
if (variant.border) lines.push(` --cux-btn-border: ${buildBorder(variant.border)};`);
|
|
1129
|
+
if (variant.borderRadius) lines.push(` --cux-btn-radius: ${buildBorderRadius(variant.borderRadius)};`);
|
|
1130
|
+
if (variant.padding) lines.push(` --cux-btn-padding: ${buildPadding(variant.padding)};`);
|
|
1131
|
+
const fontFamily = variant.fontFamily ?? globalTypography?.fontFamily;
|
|
1132
|
+
if (fontFamily) lines.push(` --cux-btn-font: '${fontFamily}', sans-serif;`);
|
|
1133
|
+
if (variant.fontSize) lines.push(` --cux-btn-font-size: ${buildFontSize(variant.fontSize)};`);
|
|
1134
|
+
if (variant.fontWeight) lines.push(` --cux-btn-font-weight: ${variant.fontWeight};`);
|
|
1135
|
+
if (variant.fontStyle) lines.push(` --cux-btn-font-style: ${variant.fontStyle};`);
|
|
1136
|
+
if (variant.letterSpacing) lines.push(` --cux-btn-letter-spacing: ${buildLetterSpacing(variant.letterSpacing)};`);
|
|
1137
|
+
if (variant.shadows) {
|
|
1138
|
+
const shadowValue = buildShadows(variant.shadows);
|
|
1139
|
+
if (shadowValue) lines.push(` --cux-btn-shadow: ${shadowValue};`);
|
|
1140
|
+
}
|
|
1141
|
+
if (variant.hoverBackground) lines.push(` --cux-btn-hover-bg: ${variant.hoverBackground};`);
|
|
1142
|
+
if (variant.hoverColor) lines.push(` --cux-btn-hover-color: ${variant.hoverColor};`);
|
|
1143
|
+
if (variant.hoverBorder) lines.push(` --cux-btn-hover-border: ${buildBorderOptional(variant.hoverBorder)};`);
|
|
1144
|
+
if (variant.activeBackground) lines.push(` --cux-btn-active-bg: ${variant.activeBackground};`);
|
|
1145
|
+
if (variant.activeColor) lines.push(` --cux-btn-active-color: ${variant.activeColor};`);
|
|
1146
|
+
if (variant.activeBorder) lines.push(` --cux-btn-active-border: ${buildBorderOptional(variant.activeBorder)};`);
|
|
1147
|
+
if (variant.focusColor) lines.push(` --cux-btn-focus-color: ${variant.focusColor};`);
|
|
1148
|
+
if (variant.focusOffset !== void 0) lines.push(` --cux-btn-focus-offset: ${buildOffset(variant.focusOffset)};`);
|
|
1149
|
+
if (variant.disabledBackground) lines.push(` --cux-btn-disabled-bg: ${variant.disabledBackground};`);
|
|
1150
|
+
if (variant.disabledColor) lines.push(` --cux-btn-disabled-color: ${variant.disabledColor};`);
|
|
1151
|
+
if (variant.disabledBorder) lines.push(` --cux-btn-disabled-border: ${buildBorderOptional(variant.disabledBorder)};`);
|
|
1152
|
+
if (variant.disabledOpacity !== void 0) lines.push(` --cux-btn-disabled-opacity: ${variant.disabledOpacity};`);
|
|
1153
|
+
lines.push("}");
|
|
1154
|
+
return lines.join("\n");
|
|
1155
|
+
}
|
|
1156
|
+
/**
|
|
1157
|
+
* Generate dark mode CSS for a button variant
|
|
1158
|
+
*/
|
|
1159
|
+
function generateButtonVariantDark(variant, variantName, globalTypography) {
|
|
1160
|
+
const lines = [];
|
|
1161
|
+
lines.push(`/* Dark Mode Variant: ${variant.name} */`);
|
|
1162
|
+
lines.push(`.dark .cux-button.--${variantName} {`);
|
|
1163
|
+
if (variant.background) lines.push(` --cux-btn-bg: ${variant.background};`);
|
|
1164
|
+
if (variant.color) lines.push(` --cux-btn-color: ${variant.color};`);
|
|
1165
|
+
if (variant.border) lines.push(` --cux-btn-border: ${buildBorder(variant.border)};`);
|
|
1166
|
+
const fontFamily = variant.fontFamily ?? globalTypography?.fontFamily;
|
|
1167
|
+
if (fontFamily) lines.push(` --cux-btn-font: '${fontFamily}', sans-serif;`);
|
|
1168
|
+
if (variant.shadows) {
|
|
1169
|
+
const shadowValue = buildShadowsDark(variant.shadows, variant.dark);
|
|
1170
|
+
if (shadowValue) lines.push(` --cux-btn-shadow: ${shadowValue};`);
|
|
1171
|
+
}
|
|
1172
|
+
if (variant.hoverBackground) lines.push(` --cux-btn-hover-bg: ${variant.hoverBackground};`);
|
|
1173
|
+
if (variant.hoverColor) lines.push(` --cux-btn-hover-color: ${variant.hoverColor};`);
|
|
1174
|
+
if (variant.hoverBorder) lines.push(` --cux-btn-hover-border: ${buildBorderOptional(variant.hoverBorder)};`);
|
|
1175
|
+
if (variant.activeBackground) lines.push(` --cux-btn-active-bg: ${variant.activeBackground};`);
|
|
1176
|
+
if (variant.activeColor) lines.push(` --cux-btn-active-color: ${variant.activeColor};`);
|
|
1177
|
+
lines.push("}");
|
|
1178
|
+
return lines.join("\n");
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Build a CSS box-shadow string from ComponentShadows (handles offset, inset, and insetHighlight)
|
|
1182
|
+
*/
|
|
1183
|
+
function buildShadows(shadows) {
|
|
1184
|
+
if (!shadows) return "";
|
|
1185
|
+
const shadowParts = [];
|
|
1186
|
+
if (shadows.offset?.enabled) {
|
|
1187
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.offset;
|
|
1188
|
+
shadowParts.push(`${offsetX}px ${offsetY}px ${blur}px ${spread}px ${color}`);
|
|
1189
|
+
}
|
|
1190
|
+
if (shadows.inset?.enabled) {
|
|
1191
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.inset;
|
|
1192
|
+
shadowParts.push(`inset ${offsetX}px ${offsetY}px ${blur}px ${spread}px ${color}`);
|
|
1193
|
+
}
|
|
1194
|
+
if (shadows.insetHighlight?.enabled) {
|
|
1195
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.insetHighlight;
|
|
1196
|
+
shadowParts.push(`inset ${offsetX}px ${offsetY}px ${blur}px ${spread}px ${color}`);
|
|
1197
|
+
}
|
|
1198
|
+
return shadowParts.join(", ");
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1201
|
+
* Build shadows with dark mode color overrides
|
|
1202
|
+
*/
|
|
1203
|
+
function buildShadowsDark(shadows, dark) {
|
|
1204
|
+
const shadowParts = [];
|
|
1205
|
+
if (shadows.offset?.enabled) {
|
|
1206
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.offset;
|
|
1207
|
+
const darkColor = dark?.shadowColor || color;
|
|
1208
|
+
shadowParts.push(`${offsetX}px ${offsetY}px ${blur}px ${spread}px ${darkColor}`);
|
|
1209
|
+
}
|
|
1210
|
+
if (shadows.inset?.enabled) {
|
|
1211
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.inset;
|
|
1212
|
+
const darkColor = dark?.shadowInsetColor || color;
|
|
1213
|
+
shadowParts.push(`inset ${offsetX}px ${offsetY}px ${blur}px ${spread}px ${darkColor}`);
|
|
1214
|
+
}
|
|
1215
|
+
if (shadows.insetHighlight?.enabled) {
|
|
1216
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.insetHighlight;
|
|
1217
|
+
const darkColor = dark?.shadowInsetHighlightColor || color;
|
|
1218
|
+
shadowParts.push(`inset ${offsetX}px ${offsetY}px ${blur}px ${spread}px ${darkColor}`);
|
|
1219
|
+
}
|
|
1220
|
+
return shadowParts.join(", ");
|
|
1221
|
+
}
|
|
1222
|
+
//#endregion
|
|
1223
|
+
//#region src/core/css-generator-base.ts
|
|
1224
|
+
/**
|
|
1225
|
+
* Generate dark mode border override CSS
|
|
1226
|
+
* Used by: badge, avatar, card, alert, chip, progress generators
|
|
1227
|
+
*/
|
|
1228
|
+
function generateDarkBorderOverride(componentName, border, darkBorderColor) {
|
|
1229
|
+
if (!darkBorderColor || !border) return "";
|
|
1230
|
+
return ` --cux-${componentName}-border: ${border.width}${border.unit} ${border.style} ${darkBorderColor};`;
|
|
1231
|
+
}
|
|
1232
|
+
/**
|
|
1233
|
+
* Generate shadow CSS variable for a component
|
|
1234
|
+
* Returns empty string if no shadow
|
|
1235
|
+
*/
|
|
1236
|
+
function generateShadowVar(componentName, shadows) {
|
|
1237
|
+
if (!shadows) return "";
|
|
1238
|
+
const parts = [];
|
|
1239
|
+
if (shadows.offset?.enabled) {
|
|
1240
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.offset;
|
|
1241
|
+
parts.push(`${offsetX}px ${offsetY}px ${blur}px ${spread}px ${color}`);
|
|
1242
|
+
}
|
|
1243
|
+
if (shadows.inset?.enabled) {
|
|
1244
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.inset;
|
|
1245
|
+
parts.push(`inset ${offsetX}px ${offsetY}px ${blur}px ${spread}px ${color}`);
|
|
1246
|
+
}
|
|
1247
|
+
if (shadows.insetHighlight?.enabled) {
|
|
1248
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.insetHighlight;
|
|
1249
|
+
parts.push(`inset ${offsetX}px ${offsetY}px ${blur}px ${spread}px ${color}`);
|
|
1250
|
+
}
|
|
1251
|
+
return parts.length > 0 ? ` --cux-${componentName}-shadow: ${parts.join(", ")};` : "";
|
|
1252
|
+
}
|
|
1253
|
+
/**
|
|
1254
|
+
* Generate dark mode shadow CSS variable
|
|
1255
|
+
*/
|
|
1256
|
+
function generateDarkShadowVar(componentName, shadows, darkColors) {
|
|
1257
|
+
if (!shadows) return "";
|
|
1258
|
+
const parts = [];
|
|
1259
|
+
if (shadows.offset?.enabled) {
|
|
1260
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.offset;
|
|
1261
|
+
const darkColor = darkColors?.shadowColor || color;
|
|
1262
|
+
parts.push(`${offsetX}px ${offsetY}px ${blur}px ${spread}px ${darkColor}`);
|
|
1263
|
+
}
|
|
1264
|
+
if (shadows.inset?.enabled) {
|
|
1265
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.inset;
|
|
1266
|
+
const darkColor = darkColors?.shadowInsetColor || color;
|
|
1267
|
+
parts.push(`inset ${offsetX}px ${offsetY}px ${blur}px ${spread}px ${darkColor}`);
|
|
1268
|
+
}
|
|
1269
|
+
if (shadows.insetHighlight?.enabled) {
|
|
1270
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.insetHighlight;
|
|
1271
|
+
const darkColor = darkColors?.shadowInsetHighlightColor || color;
|
|
1272
|
+
parts.push(`inset ${offsetX}px ${offsetY}px ${blur}px ${spread}px ${darkColor}`);
|
|
1273
|
+
}
|
|
1274
|
+
return parts.length > 0 ? ` --cux-${componentName}-shadow: ${parts.join(", ")};` : "";
|
|
1275
|
+
}
|
|
1276
|
+
/**
|
|
1277
|
+
* Generate offset shadow for components that separate offset from inset shadows
|
|
1278
|
+
* Used by: card, alert, progress (overlay pattern)
|
|
1279
|
+
*/
|
|
1280
|
+
function generateOffsetShadowVar(componentName, shadows) {
|
|
1281
|
+
if (!shadows?.offset?.enabled) return "";
|
|
1282
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.offset;
|
|
1283
|
+
return ` --cux-${componentName}-shadow: ${offsetX}px ${offsetY}px ${blur}px ${spread}px ${color};`;
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
* Generate inset shadow variable for overlay pattern
|
|
1287
|
+
*/
|
|
1288
|
+
function generateInsetShadowVar(componentName, shadows) {
|
|
1289
|
+
if (!shadows) return "";
|
|
1290
|
+
const parts = [];
|
|
1291
|
+
if (shadows.inset?.enabled) {
|
|
1292
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.inset;
|
|
1293
|
+
parts.push(`inset ${offsetX}px ${offsetY}px ${blur}px ${spread}px ${color}`);
|
|
1294
|
+
}
|
|
1295
|
+
if (shadows.insetHighlight?.enabled) {
|
|
1296
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.insetHighlight;
|
|
1297
|
+
parts.push(`inset ${offsetX}px ${offsetY}px ${blur}px ${spread}px ${color}`);
|
|
1298
|
+
}
|
|
1299
|
+
return parts.length > 0 ? ` --cux-${componentName}-inset-shadow: ${parts.join(", ")};` : "";
|
|
1300
|
+
}
|
|
1301
|
+
/**
|
|
1302
|
+
* Generate dark mode offset shadow
|
|
1303
|
+
*/
|
|
1304
|
+
function generateDarkOffsetShadowVar(componentName, shadows, shadowColor) {
|
|
1305
|
+
if (!shadows?.offset?.enabled) return "";
|
|
1306
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.offset;
|
|
1307
|
+
return ` --cux-${componentName}-shadow: ${offsetX}px ${offsetY}px ${blur}px ${spread}px ${shadowColor || color};`;
|
|
1308
|
+
}
|
|
1309
|
+
/**
|
|
1310
|
+
* Generate dark mode inset shadow
|
|
1311
|
+
*/
|
|
1312
|
+
function generateDarkInsetShadowVar(componentName, shadows, shadowInsetColor, shadowInsetHighlightColor) {
|
|
1313
|
+
if (!shadows) return "";
|
|
1314
|
+
const parts = [];
|
|
1315
|
+
if (shadows.inset?.enabled) {
|
|
1316
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.inset;
|
|
1317
|
+
parts.push(`inset ${offsetX}px ${offsetY}px ${blur}px ${spread}px ${shadowInsetColor || color}`);
|
|
1318
|
+
}
|
|
1319
|
+
if (shadows.insetHighlight?.enabled) {
|
|
1320
|
+
const { offsetX, offsetY, blur, spread, color } = shadows.insetHighlight;
|
|
1321
|
+
parts.push(`inset ${offsetX}px ${offsetY}px ${blur}px ${spread}px ${shadowInsetHighlightColor || color}`);
|
|
1322
|
+
}
|
|
1323
|
+
return parts.length > 0 ? ` --cux-${componentName}-inset-shadow: ${parts.join(", ")};` : "";
|
|
1324
|
+
}
|
|
1325
|
+
/**
|
|
1326
|
+
* Generate typography CSS lines for a component
|
|
1327
|
+
* Returns array of CSS lines (without selector)
|
|
1328
|
+
*/
|
|
1329
|
+
function generateTypographyLines(options, globalConfig) {
|
|
1330
|
+
const lines = [];
|
|
1331
|
+
const effectiveFontFamily = getEffectiveFontFamily$2(options.fontFamily, globalConfig?.fontFamily);
|
|
1332
|
+
if (effectiveFontFamily) lines.push(` font-family: '${effectiveFontFamily}', sans-serif;`);
|
|
1333
|
+
if (options.fontSize) lines.push(` font-size: ${buildFontSize(options.fontSize)};`);
|
|
1334
|
+
if (options.fontWeight) lines.push(` font-weight: ${options.fontWeight};`);
|
|
1335
|
+
if (options.fontStyle) lines.push(` font-style: ${options.fontStyle};`);
|
|
1336
|
+
if (options.letterSpacing) lines.push(` letter-spacing: ${buildLetterSpacing(options.letterSpacing)};`);
|
|
1337
|
+
if (options.textAlign) lines.push(` text-align: ${options.textAlign};`);
|
|
1338
|
+
return lines;
|
|
1339
|
+
}
|
|
1340
|
+
/**
|
|
1341
|
+
* Generate typography CSS block with selector
|
|
1342
|
+
*/
|
|
1343
|
+
function generateTypographyBlock(selector, options, globalConfig) {
|
|
1344
|
+
const lines = generateTypographyLines(options, globalConfig);
|
|
1345
|
+
if (lines.length === 0) return "";
|
|
1346
|
+
return `${selector} {
|
|
1347
|
+
${lines.join("\n")}
|
|
1348
|
+
}`;
|
|
1349
|
+
}
|
|
1350
|
+
/**
|
|
1351
|
+
* Generate base variant CSS properties (background, color, border, radius, padding)
|
|
1352
|
+
*/
|
|
1353
|
+
function generateBaseProperties(componentName, variant) {
|
|
1354
|
+
const lines = [];
|
|
1355
|
+
lines.push(` --cux-${componentName}-bg: ${variant.background};`);
|
|
1356
|
+
lines.push(` --cux-${componentName}-color: ${variant.color};`);
|
|
1357
|
+
if (variant.border) lines.push(` --cux-${componentName}-border: ${buildBorder(variant.border)};`);
|
|
1358
|
+
if (variant.borderRadius) lines.push(` --cux-${componentName}-radius: ${buildBorderRadius(variant.borderRadius)};`);
|
|
1359
|
+
if (variant.padding) lines.push(` --cux-${componentName}-padding: ${buildPadding(variant.padding)};`);
|
|
1360
|
+
return lines;
|
|
1361
|
+
}
|
|
1362
|
+
/**
|
|
1363
|
+
* Generate dark mode base properties
|
|
1364
|
+
*/
|
|
1365
|
+
function generateDarkBaseProperties(componentName, dark) {
|
|
1366
|
+
const lines = [];
|
|
1367
|
+
if (dark.background) lines.push(` --cux-${componentName}-bg: ${dark.background};`);
|
|
1368
|
+
if (dark.color) lines.push(` --cux-${componentName}-color: ${dark.color};`);
|
|
1369
|
+
return lines;
|
|
1370
|
+
}
|
|
1371
|
+
//#endregion
|
|
1372
|
+
//#region src/core/card-generator.ts
|
|
1373
|
+
const COMPONENT$6 = "card";
|
|
1374
|
+
/**
|
|
1375
|
+
* Generate complete CSS for card component
|
|
1376
|
+
*/
|
|
1377
|
+
function generateCardCSS(variants, globalConfig) {
|
|
1378
|
+
const css = [];
|
|
1379
|
+
css.push(generateCardBase());
|
|
1380
|
+
variants.forEach((variant) => {
|
|
1381
|
+
const variantName = toKebabCase(variant.name);
|
|
1382
|
+
css.push(generateCardVariant(variant, variantName, globalConfig));
|
|
1383
|
+
if (variant.dark) css.push(generateCardVariantDark(variant, variantName));
|
|
1384
|
+
});
|
|
1385
|
+
return css.join("\n\n");
|
|
1386
|
+
}
|
|
1387
|
+
/**
|
|
1388
|
+
* Generate base card styles
|
|
1389
|
+
*/
|
|
1390
|
+
function generateCardBase() {
|
|
1391
|
+
return `/* Card Base Styles */
|
|
1392
|
+
.cux-${COMPONENT$6} {
|
|
1393
|
+
--cux-${COMPONENT$6}-bg: #ffffff;
|
|
1394
|
+
--cux-${COMPONENT$6}-color: inherit;
|
|
1395
|
+
--cux-${COMPONENT$6}-border: none;
|
|
1396
|
+
--cux-${COMPONENT$6}-radius: 0;
|
|
1397
|
+
--cux-${COMPONENT$6}-padding: 0;
|
|
1398
|
+
--cux-${COMPONENT$6}-shadow: none;
|
|
1399
|
+
--cux-${COMPONENT$6}-inset-shadow: none;
|
|
1400
|
+
|
|
1401
|
+
/* Header properties */
|
|
1402
|
+
--cux-${COMPONENT$6}-header-bg: transparent;
|
|
1403
|
+
--cux-${COMPONENT$6}-header-color: inherit;
|
|
1404
|
+
--cux-${COMPONENT$6}-header-padding: 0;
|
|
1405
|
+
--cux-${COMPONENT$6}-header-border-bottom: none;
|
|
1406
|
+
|
|
1407
|
+
position: relative;
|
|
1408
|
+
background: var(--cux-${COMPONENT$6}-bg);
|
|
1409
|
+
color: var(--cux-${COMPONENT$6}-color);
|
|
1410
|
+
border: var(--cux-${COMPONENT$6}-border);
|
|
1411
|
+
border-radius: var(--cux-${COMPONENT$6}-radius);
|
|
1412
|
+
box-shadow: var(--cux-${COMPONENT$6}-shadow);
|
|
1413
|
+
overflow: hidden;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
.cux-${COMPONENT$6}-inset-overlay {
|
|
1417
|
+
position: absolute;
|
|
1418
|
+
inset: 0;
|
|
1419
|
+
z-index: 2;
|
|
1420
|
+
border-radius: var(--cux-${COMPONENT$6}-radius);
|
|
1421
|
+
box-shadow: var(--cux-${COMPONENT$6}-inset-shadow);
|
|
1422
|
+
pointer-events: none;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
.cux-${COMPONENT$6}-header {
|
|
1426
|
+
position: relative;
|
|
1427
|
+
z-index: 1;
|
|
1428
|
+
background: var(--cux-${COMPONENT$6}-header-bg);
|
|
1429
|
+
color: var(--cux-${COMPONENT$6}-header-color);
|
|
1430
|
+
padding: var(--cux-${COMPONENT$6}-header-padding);
|
|
1431
|
+
border-bottom: var(--cux-${COMPONENT$6}-header-border-bottom);
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
.cux-${COMPONENT$6}-body {
|
|
1435
|
+
position: relative;
|
|
1436
|
+
z-index: 1;
|
|
1437
|
+
padding: var(--cux-${COMPONENT$6}-padding);
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
.cux-${COMPONENT$6}-footer {
|
|
1441
|
+
position: relative;
|
|
1442
|
+
z-index: 1;
|
|
1443
|
+
padding: var(--cux-${COMPONENT$6}-padding);
|
|
1444
|
+
border-top: var(--cux-${COMPONENT$6}-header-border-bottom);
|
|
1445
|
+
}`;
|
|
1446
|
+
}
|
|
1447
|
+
/**
|
|
1448
|
+
* Generate CSS for a specific card variant
|
|
1449
|
+
*/
|
|
1450
|
+
function generateCardVariant(variant, variantName, globalConfig) {
|
|
1451
|
+
const lines = [];
|
|
1452
|
+
lines.push(`/* Variant: ${variant.name} */`);
|
|
1453
|
+
lines.push(`.cux-${COMPONENT$6}.--${variantName} {`);
|
|
1454
|
+
lines.push(` --cux-${COMPONENT$6}-bg: ${variant.background};`);
|
|
1455
|
+
lines.push(` --cux-${COMPONENT$6}-color: ${variant.color};`);
|
|
1456
|
+
if (variant.border) lines.push(` --cux-${COMPONENT$6}-border: ${buildBorder(variant.border)};`);
|
|
1457
|
+
if (variant.borderRadius) lines.push(` --cux-${COMPONENT$6}-radius: ${variant.borderRadius.tl}${variant.borderRadius.unit};`);
|
|
1458
|
+
if (variant.padding) lines.push(` --cux-${COMPONENT$6}-padding: ${buildPadding(variant.padding)};`);
|
|
1459
|
+
const offsetShadow = generateOffsetShadowVar(COMPONENT$6, variant.shadows);
|
|
1460
|
+
if (offsetShadow) lines.push(offsetShadow);
|
|
1461
|
+
const insetShadow = generateInsetShadowVar(COMPONENT$6, variant.shadows);
|
|
1462
|
+
if (insetShadow) lines.push(insetShadow);
|
|
1463
|
+
lines.push(` --cux-${COMPONENT$6}-header-bg: ${variant.headerBackground};`);
|
|
1464
|
+
lines.push(` --cux-${COMPONENT$6}-header-color: ${variant.headerColor};`);
|
|
1465
|
+
if (variant.headerPadding) lines.push(` --cux-${COMPONENT$6}-header-padding: ${buildPadding(variant.headerPadding)};`);
|
|
1466
|
+
if (variant.headerBorderBottom) lines.push(` --cux-${COMPONENT$6}-header-border-bottom: ${buildBorder(variant.headerBorderBottom)};`);
|
|
1467
|
+
lines.push("}");
|
|
1468
|
+
const bodyTypography = generateTypographyLines({
|
|
1469
|
+
fontFamily: variant.fontFamily,
|
|
1470
|
+
fontSize: variant.fontSize,
|
|
1471
|
+
fontWeight: variant.fontWeight,
|
|
1472
|
+
fontStyle: variant.fontStyle,
|
|
1473
|
+
letterSpacing: variant.letterSpacing,
|
|
1474
|
+
textAlign: variant.textAlign
|
|
1475
|
+
}, globalConfig);
|
|
1476
|
+
if (bodyTypography.length > 0) {
|
|
1477
|
+
lines.push("");
|
|
1478
|
+
lines.push(`.cux-${COMPONENT$6}.--${variantName} .cux-${COMPONENT$6}-body {`);
|
|
1479
|
+
lines.push(...bodyTypography);
|
|
1480
|
+
lines.push("}");
|
|
1481
|
+
}
|
|
1482
|
+
const headerTypography = generateTypographyLines({
|
|
1483
|
+
fontFamily: variant.headerFontFamily,
|
|
1484
|
+
fontSize: variant.headerFontSize,
|
|
1485
|
+
fontWeight: variant.headerFontWeight,
|
|
1486
|
+
fontStyle: variant.headerFontStyle,
|
|
1487
|
+
letterSpacing: variant.headerLetterSpacing,
|
|
1488
|
+
textAlign: variant.headerTextAlign
|
|
1489
|
+
}, globalConfig);
|
|
1490
|
+
if (headerTypography.length > 0) {
|
|
1491
|
+
lines.push("");
|
|
1492
|
+
lines.push(`.cux-${COMPONENT$6}.--${variantName} .cux-${COMPONENT$6}-header {`);
|
|
1493
|
+
lines.push(...headerTypography);
|
|
1494
|
+
lines.push("}");
|
|
1495
|
+
}
|
|
1496
|
+
return lines.join("\n");
|
|
1497
|
+
}
|
|
1498
|
+
/**
|
|
1499
|
+
* Generate dark mode CSS for a card variant
|
|
1500
|
+
*/
|
|
1501
|
+
function generateCardVariantDark(variant, variantName) {
|
|
1502
|
+
const dark = variant.dark;
|
|
1503
|
+
if (!dark) return "";
|
|
1504
|
+
const lines = [];
|
|
1505
|
+
lines.push(`/* Dark Mode Variant: ${variant.name} */`);
|
|
1506
|
+
lines.push(`.dark .cux-${COMPONENT$6}.--${variantName} {`);
|
|
1507
|
+
lines.push(...generateDarkBaseProperties(COMPONENT$6, dark));
|
|
1508
|
+
const borderOverride = generateDarkBorderOverride(COMPONENT$6, variant.border, dark.borderColor);
|
|
1509
|
+
if (borderOverride) lines.push(borderOverride);
|
|
1510
|
+
if (dark.headerBackground) lines.push(` --cux-${COMPONENT$6}-header-bg: ${dark.headerBackground};`);
|
|
1511
|
+
if (dark.headerColor) lines.push(` --cux-${COMPONENT$6}-header-color: ${dark.headerColor};`);
|
|
1512
|
+
if (dark.headerBorderBottomColor && variant.headerBorderBottom) lines.push(` --cux-${COMPONENT$6}-header-border-bottom: ${variant.headerBorderBottom.width}${variant.headerBorderBottom.unit} ${variant.headerBorderBottom.style} ${dark.headerBorderBottomColor};`);
|
|
1513
|
+
const offsetShadow = generateDarkOffsetShadowVar(COMPONENT$6, variant.shadows, dark.shadowColor);
|
|
1514
|
+
if (offsetShadow) lines.push(offsetShadow);
|
|
1515
|
+
const insetShadow = generateDarkInsetShadowVar(COMPONENT$6, variant.shadows, dark.shadowInsetColor, dark.shadowInsetHighlightColor);
|
|
1516
|
+
if (insetShadow) lines.push(insetShadow);
|
|
1517
|
+
lines.push("}");
|
|
1518
|
+
return lines.join("\n");
|
|
1519
|
+
}
|
|
1520
|
+
//#endregion
|
|
1521
|
+
//#region src/core/alert-generator.ts
|
|
1522
|
+
const COMPONENT$5 = "alert";
|
|
1523
|
+
/**
|
|
1524
|
+
* Generate complete CSS for alert component
|
|
1525
|
+
*/
|
|
1526
|
+
function generateAlertCSS(variants, globalConfig) {
|
|
1527
|
+
const css = [];
|
|
1528
|
+
css.push(generateAlertBase());
|
|
1529
|
+
variants.forEach((variant) => {
|
|
1530
|
+
const variantName = toKebabCase(variant.name);
|
|
1531
|
+
css.push(generateAlertVariant(variant, variantName, globalConfig));
|
|
1532
|
+
if (variant.dark) css.push(generateAlertVariantDark(variant, variantName));
|
|
1533
|
+
});
|
|
1534
|
+
return css.join("\n\n");
|
|
1535
|
+
}
|
|
1536
|
+
/**
|
|
1537
|
+
* Generate base alert styles
|
|
1538
|
+
*/
|
|
1539
|
+
function generateAlertBase() {
|
|
1540
|
+
return `/* Alert Base Styles */
|
|
1541
|
+
.cux-${COMPONENT$5} {
|
|
1542
|
+
--cux-${COMPONENT$5}-bg: transparent;
|
|
1543
|
+
--cux-${COMPONENT$5}-color: inherit;
|
|
1544
|
+
--cux-${COMPONENT$5}-border: none;
|
|
1545
|
+
--cux-${COMPONENT$5}-radius: 0;
|
|
1546
|
+
--cux-${COMPONENT$5}-padding: 0;
|
|
1547
|
+
--cux-${COMPONENT$5}-shadow: none;
|
|
1548
|
+
--cux-${COMPONENT$5}-inset-shadow: none;
|
|
1549
|
+
|
|
1550
|
+
/* Header properties */
|
|
1551
|
+
--cux-${COMPONENT$5}-header-bg: transparent;
|
|
1552
|
+
--cux-${COMPONENT$5}-header-color: inherit;
|
|
1553
|
+
--cux-${COMPONENT$5}-header-padding: 0;
|
|
1554
|
+
--cux-${COMPONENT$5}-header-border-bottom: none;
|
|
1555
|
+
|
|
1556
|
+
/* Close button properties */
|
|
1557
|
+
--cux-${COMPONENT$5}-close-size: 20px;
|
|
1558
|
+
--cux-${COMPONENT$5}-close-color: #6c757d;
|
|
1559
|
+
--cux-${COMPONENT$5}-close-hover-color: #495057;
|
|
1560
|
+
--cux-${COMPONENT$5}-close-active-color: #212529;
|
|
1561
|
+
|
|
1562
|
+
/* Layout */
|
|
1563
|
+
--cux-${COMPONENT$5}-max-width: 500px;
|
|
1564
|
+
--cux-${COMPONENT$5}-offset: 16px;
|
|
1565
|
+
|
|
1566
|
+
position: relative;
|
|
1567
|
+
background: var(--cux-${COMPONENT$5}-bg);
|
|
1568
|
+
color: var(--cux-${COMPONENT$5}-color);
|
|
1569
|
+
border: var(--cux-${COMPONENT$5}-border);
|
|
1570
|
+
border-radius: var(--cux-${COMPONENT$5}-radius);
|
|
1571
|
+
box-shadow: var(--cux-${COMPONENT$5}-shadow);
|
|
1572
|
+
max-width: var(--cux-${COMPONENT$5}-max-width);
|
|
1573
|
+
overflow: hidden;
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
.cux-${COMPONENT$5}-inset-overlay {
|
|
1577
|
+
position: absolute;
|
|
1578
|
+
inset: 0;
|
|
1579
|
+
z-index: 2;
|
|
1580
|
+
border-radius: var(--cux-${COMPONENT$5}-radius);
|
|
1581
|
+
box-shadow: var(--cux-${COMPONENT$5}-inset-shadow);
|
|
1582
|
+
pointer-events: none;
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
.cux-${COMPONENT$5}-header {
|
|
1586
|
+
position: relative;
|
|
1587
|
+
z-index: 1;
|
|
1588
|
+
display: flex;
|
|
1589
|
+
align-items: center;
|
|
1590
|
+
justify-content: space-between;
|
|
1591
|
+
gap: 8px;
|
|
1592
|
+
background: var(--cux-${COMPONENT$5}-header-bg);
|
|
1593
|
+
color: var(--cux-${COMPONENT$5}-header-color);
|
|
1594
|
+
padding: var(--cux-${COMPONENT$5}-header-padding);
|
|
1595
|
+
border-bottom: var(--cux-${COMPONENT$5}-header-border-bottom);
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
.cux-${COMPONENT$5}-body {
|
|
1599
|
+
position: relative;
|
|
1600
|
+
z-index: 1;
|
|
1601
|
+
padding: var(--cux-${COMPONENT$5}-padding);
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
.cux-${COMPONENT$5}-close {
|
|
1605
|
+
flex-shrink: 0;
|
|
1606
|
+
width: var(--cux-${COMPONENT$5}-close-size);
|
|
1607
|
+
height: var(--cux-${COMPONENT$5}-close-size);
|
|
1608
|
+
background: transparent;
|
|
1609
|
+
border: none;
|
|
1610
|
+
color: var(--cux-${COMPONENT$5}-close-color);
|
|
1611
|
+
cursor: pointer;
|
|
1612
|
+
display: flex;
|
|
1613
|
+
align-items: center;
|
|
1614
|
+
justify-content: center;
|
|
1615
|
+
padding: 0;
|
|
1616
|
+
border-radius: 4px;
|
|
1617
|
+
transition: color 0.15s ease;
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
.cux-${COMPONENT$5}-close:hover { color: var(--cux-${COMPONENT$5}-close-hover-color); }
|
|
1621
|
+
.cux-${COMPONENT$5}-close:active { color: var(--cux-${COMPONENT$5}-close-active-color); }
|
|
1622
|
+
.cux-${COMPONENT$5}-close svg { width: 100%; height: 100%; }
|
|
1623
|
+
|
|
1624
|
+
/* Position modifiers */
|
|
1625
|
+
.cux-${COMPONENT$5}.--top-left { position: fixed; top: var(--cux-${COMPONENT$5}-offset); left: var(--cux-${COMPONENT$5}-offset); z-index: 9999; }
|
|
1626
|
+
.cux-${COMPONENT$5}.--top-center { position: fixed; top: var(--cux-${COMPONENT$5}-offset); left: 50%; transform: translateX(-50%); z-index: 9999; }
|
|
1627
|
+
.cux-${COMPONENT$5}.--top-right { position: fixed; top: var(--cux-${COMPONENT$5}-offset); right: var(--cux-${COMPONENT$5}-offset); z-index: 9999; }
|
|
1628
|
+
.cux-${COMPONENT$5}.--center-left { position: fixed; top: 50%; left: var(--cux-${COMPONENT$5}-offset); transform: translateY(-50%); z-index: 9999; }
|
|
1629
|
+
.cux-${COMPONENT$5}.--center-center { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 9999; }
|
|
1630
|
+
.cux-${COMPONENT$5}.--center-right { position: fixed; top: 50%; right: var(--cux-${COMPONENT$5}-offset); transform: translateY(-50%); z-index: 9999; }
|
|
1631
|
+
.cux-${COMPONENT$5}.--bottom-left { position: fixed; bottom: var(--cux-${COMPONENT$5}-offset); left: var(--cux-${COMPONENT$5}-offset); z-index: 9999; }
|
|
1632
|
+
.cux-${COMPONENT$5}.--bottom-center { position: fixed; bottom: var(--cux-${COMPONENT$5}-offset); left: 50%; transform: translateX(-50%); z-index: 9999; }
|
|
1633
|
+
.cux-${COMPONENT$5}.--bottom-right { position: fixed; bottom: var(--cux-${COMPONENT$5}-offset); right: var(--cux-${COMPONENT$5}-offset); z-index: 9999; }`;
|
|
1634
|
+
}
|
|
1635
|
+
/**
|
|
1636
|
+
* Generate CSS for a specific alert variant
|
|
1637
|
+
*/
|
|
1638
|
+
function generateAlertVariant(variant, variantName, globalConfig) {
|
|
1639
|
+
const lines = [];
|
|
1640
|
+
lines.push(`/* Variant: ${variant.name} */`);
|
|
1641
|
+
lines.push(`.cux-${COMPONENT$5}.--${variantName} {`);
|
|
1642
|
+
lines.push(` --cux-${COMPONENT$5}-bg: ${variant.background};`);
|
|
1643
|
+
lines.push(` --cux-${COMPONENT$5}-color: ${variant.color};`);
|
|
1644
|
+
if (variant.border) lines.push(` --cux-${COMPONENT$5}-border: ${buildBorder(variant.border)};`);
|
|
1645
|
+
if (variant.borderRadius) lines.push(` --cux-${COMPONENT$5}-radius: ${variant.borderRadius.tl}${variant.borderRadius.unit};`);
|
|
1646
|
+
if (variant.padding) lines.push(` --cux-${COMPONENT$5}-padding: ${buildPadding(variant.padding)};`);
|
|
1647
|
+
const offsetShadow = generateOffsetShadowVar(COMPONENT$5, variant.shadows);
|
|
1648
|
+
if (offsetShadow) lines.push(offsetShadow);
|
|
1649
|
+
const insetShadow = generateInsetShadowVar(COMPONENT$5, variant.shadows);
|
|
1650
|
+
if (insetShadow) lines.push(insetShadow);
|
|
1651
|
+
lines.push(` --cux-${COMPONENT$5}-header-bg: ${variant.headerBackground};`);
|
|
1652
|
+
lines.push(` --cux-${COMPONENT$5}-header-color: ${variant.headerColor};`);
|
|
1653
|
+
if (variant.headerPadding) lines.push(` --cux-${COMPONENT$5}-header-padding: ${buildPadding(variant.headerPadding)};`);
|
|
1654
|
+
if (variant.headerBorderBottom) lines.push(` --cux-${COMPONENT$5}-header-border-bottom: ${buildBorder(variant.headerBorderBottom)};`);
|
|
1655
|
+
if (variant.closeSize) lines.push(` --cux-${COMPONENT$5}-close-size: ${variant.closeSize.value}${variant.closeSize.unit};`);
|
|
1656
|
+
lines.push(` --cux-${COMPONENT$5}-close-color: ${variant.closeColor};`);
|
|
1657
|
+
lines.push(` --cux-${COMPONENT$5}-close-hover-color: ${variant.closeHoverColor};`);
|
|
1658
|
+
lines.push(` --cux-${COMPONENT$5}-close-active-color: ${variant.closeActiveColor};`);
|
|
1659
|
+
lines.push(` --cux-${COMPONENT$5}-max-width: ${variant.maxWidth.value}${variant.maxWidth.unit};`);
|
|
1660
|
+
lines.push(` --cux-${COMPONENT$5}-offset: ${variant.offset.value}${variant.offset.unit};`);
|
|
1661
|
+
lines.push("}");
|
|
1662
|
+
const bodyTypography = generateTypographyLines({
|
|
1663
|
+
fontFamily: variant.fontFamily,
|
|
1664
|
+
fontSize: variant.fontSize,
|
|
1665
|
+
fontWeight: variant.fontWeight,
|
|
1666
|
+
fontStyle: variant.fontStyle,
|
|
1667
|
+
letterSpacing: variant.letterSpacing,
|
|
1668
|
+
textAlign: variant.textAlign
|
|
1669
|
+
}, globalConfig);
|
|
1670
|
+
if (bodyTypography.length > 0) {
|
|
1671
|
+
lines.push("");
|
|
1672
|
+
lines.push(`.cux-${COMPONENT$5}.--${variantName} .cux-${COMPONENT$5}-body {`);
|
|
1673
|
+
lines.push(...bodyTypography);
|
|
1674
|
+
lines.push("}");
|
|
1675
|
+
}
|
|
1676
|
+
const headerTypography = generateTypographyLines({
|
|
1677
|
+
fontFamily: variant.headerFontFamily,
|
|
1678
|
+
fontSize: variant.headerFontSize,
|
|
1679
|
+
fontWeight: variant.headerFontWeight,
|
|
1680
|
+
fontStyle: variant.headerFontStyle,
|
|
1681
|
+
letterSpacing: variant.headerLetterSpacing,
|
|
1682
|
+
textAlign: variant.headerTextAlign
|
|
1683
|
+
}, globalConfig);
|
|
1684
|
+
if (headerTypography.length > 0) {
|
|
1685
|
+
lines.push("");
|
|
1686
|
+
lines.push(`.cux-${COMPONENT$5}.--${variantName} .cux-${COMPONENT$5}-header {`);
|
|
1687
|
+
lines.push(...headerTypography);
|
|
1688
|
+
lines.push("}");
|
|
1689
|
+
}
|
|
1690
|
+
return lines.join("\n");
|
|
1691
|
+
}
|
|
1692
|
+
/**
|
|
1693
|
+
* Generate dark mode CSS for an alert variant
|
|
1694
|
+
*/
|
|
1695
|
+
function generateAlertVariantDark(variant, variantName) {
|
|
1696
|
+
const dark = variant.dark;
|
|
1697
|
+
if (!dark) return "";
|
|
1698
|
+
const lines = [];
|
|
1699
|
+
lines.push(`/* Dark Mode Variant: ${variant.name} */`);
|
|
1700
|
+
lines.push(`.dark .cux-${COMPONENT$5}.--${variantName} {`);
|
|
1701
|
+
lines.push(...generateDarkBaseProperties(COMPONENT$5, dark));
|
|
1702
|
+
const borderOverride = generateDarkBorderOverride(COMPONENT$5, variant.border, dark.borderColor);
|
|
1703
|
+
if (borderOverride) lines.push(borderOverride);
|
|
1704
|
+
if (dark.headerBackground) lines.push(` --cux-${COMPONENT$5}-header-bg: ${dark.headerBackground};`);
|
|
1705
|
+
if (dark.headerColor) lines.push(` --cux-${COMPONENT$5}-header-color: ${dark.headerColor};`);
|
|
1706
|
+
if (dark.headerBorderBottomColor && variant.headerBorderBottom) lines.push(` --cux-${COMPONENT$5}-header-border-bottom: ${variant.headerBorderBottom.width}${variant.headerBorderBottom.unit} ${variant.headerBorderBottom.style} ${dark.headerBorderBottomColor};`);
|
|
1707
|
+
if (dark.closeColor) lines.push(` --cux-${COMPONENT$5}-close-color: ${dark.closeColor};`);
|
|
1708
|
+
if (dark.closeHoverColor) lines.push(` --cux-${COMPONENT$5}-close-hover-color: ${dark.closeHoverColor};`);
|
|
1709
|
+
if (dark.closeActiveColor) lines.push(` --cux-${COMPONENT$5}-close-active-color: ${dark.closeActiveColor};`);
|
|
1710
|
+
const offsetShadow = generateDarkOffsetShadowVar(COMPONENT$5, variant.shadows, dark.shadowColor);
|
|
1711
|
+
if (offsetShadow) lines.push(offsetShadow);
|
|
1712
|
+
const insetShadow = generateDarkInsetShadowVar(COMPONENT$5, variant.shadows, dark.shadowInsetColor, dark.shadowInsetHighlightColor);
|
|
1713
|
+
if (insetShadow) lines.push(insetShadow);
|
|
1714
|
+
lines.push("}");
|
|
1715
|
+
return lines.join("\n");
|
|
1716
|
+
}
|
|
1717
|
+
//#endregion
|
|
1718
|
+
//#region src/core/avatar-generator.ts
|
|
1719
|
+
const COMPONENT$4 = "avatar";
|
|
1720
|
+
/**
|
|
1721
|
+
* Generate complete CSS for avatar component
|
|
1722
|
+
*/
|
|
1723
|
+
function generateAvatarCSS(variants, globalConfig) {
|
|
1724
|
+
const css = [];
|
|
1725
|
+
css.push(generateAvatarBase());
|
|
1726
|
+
variants.forEach((variant) => {
|
|
1727
|
+
const variantName = toKebabCase(variant.name);
|
|
1728
|
+
css.push(generateAvatarVariant(variant, variantName, globalConfig));
|
|
1729
|
+
if (variant.dark) css.push(generateAvatarVariantDark(variant, variantName));
|
|
1730
|
+
});
|
|
1731
|
+
return css.join("\n\n");
|
|
1732
|
+
}
|
|
1733
|
+
/**
|
|
1734
|
+
* Generate base avatar styles
|
|
1735
|
+
*/
|
|
1736
|
+
function generateAvatarBase() {
|
|
1737
|
+
return `/* Avatar Base Styles */
|
|
1738
|
+
.cux-${COMPONENT$4} {
|
|
1739
|
+
--cux-${COMPONENT$4}-bg: transparent;
|
|
1740
|
+
--cux-${COMPONENT$4}-color: inherit;
|
|
1741
|
+
--cux-${COMPONENT$4}-border: none;
|
|
1742
|
+
--cux-${COMPONENT$4}-radius: 50%;
|
|
1743
|
+
--cux-${COMPONENT$4}-padding: 0;
|
|
1744
|
+
--cux-${COMPONENT$4}-shadow: none;
|
|
1745
|
+
|
|
1746
|
+
background: var(--cux-${COMPONENT$4}-bg);
|
|
1747
|
+
color: var(--cux-${COMPONENT$4}-color);
|
|
1748
|
+
border: var(--cux-${COMPONENT$4}-border);
|
|
1749
|
+
border-radius: var(--cux-${COMPONENT$4}-radius);
|
|
1750
|
+
padding: var(--cux-${COMPONENT$4}-padding);
|
|
1751
|
+
box-shadow: var(--cux-${COMPONENT$4}-shadow);
|
|
1752
|
+
display: inline-flex;
|
|
1753
|
+
align-items: center;
|
|
1754
|
+
justify-content: center;
|
|
1755
|
+
overflow: hidden;
|
|
1756
|
+
vertical-align: middle;
|
|
1757
|
+
position: relative;
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
.cux-${COMPONENT$4} img {
|
|
1761
|
+
width: 100%;
|
|
1762
|
+
height: 100%;
|
|
1763
|
+
object-fit: cover;
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
.cux-${COMPONENT$4}-initials {
|
|
1767
|
+
text-transform: uppercase;
|
|
1768
|
+
user-select: none;
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
/* Size modifiers */
|
|
1772
|
+
.cux-${COMPONENT$4}.--xs { width: 24px; height: 24px; }
|
|
1773
|
+
.cux-${COMPONENT$4}.--sm { width: 32px; height: 32px; }
|
|
1774
|
+
.cux-${COMPONENT$4}.--md { width: 40px; height: 40px; }
|
|
1775
|
+
.cux-${COMPONENT$4}.--lg { width: 48px; height: 48px; }
|
|
1776
|
+
.cux-${COMPONENT$4}.--xl { width: 64px; height: 64px; }
|
|
1777
|
+
.cux-${COMPONENT$4}.--xxl { width: 96px; height: 96px; }
|
|
1778
|
+
|
|
1779
|
+
/* Status indicator */
|
|
1780
|
+
.cux-${COMPONENT$4}-status {
|
|
1781
|
+
position: absolute;
|
|
1782
|
+
bottom: 0;
|
|
1783
|
+
right: 0;
|
|
1784
|
+
width: 25%;
|
|
1785
|
+
height: 25%;
|
|
1786
|
+
min-width: 8px;
|
|
1787
|
+
min-height: 8px;
|
|
1788
|
+
border-radius: 50%;
|
|
1789
|
+
border: 2px solid white;
|
|
1790
|
+
background: #6c757d;
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
.cux-${COMPONENT$4}-status.--online { background: #28a745; }
|
|
1794
|
+
.cux-${COMPONENT$4}-status.--offline { background: #6c757d; }
|
|
1795
|
+
.cux-${COMPONENT$4}-status.--busy { background: #dc3545; }
|
|
1796
|
+
.cux-${COMPONENT$4}-status.--away { background: #ffc107; }`;
|
|
1797
|
+
}
|
|
1798
|
+
/**
|
|
1799
|
+
* Generate CSS for a specific avatar variant
|
|
1800
|
+
*/
|
|
1801
|
+
function generateAvatarVariant(variant, variantName, globalConfig) {
|
|
1802
|
+
const lines = [];
|
|
1803
|
+
lines.push(`/* Variant: ${variant.name} */`);
|
|
1804
|
+
lines.push(`.cux-${COMPONENT$4}.--${variantName} {`);
|
|
1805
|
+
lines.push(...generateBaseProperties(COMPONENT$4, variant));
|
|
1806
|
+
const shadowVar = generateShadowVar(COMPONENT$4, variant.shadows);
|
|
1807
|
+
if (shadowVar) lines.push(shadowVar);
|
|
1808
|
+
lines.push("}");
|
|
1809
|
+
const typographyLines = generateTypographyLines({
|
|
1810
|
+
fontFamily: variant.fontFamily,
|
|
1811
|
+
fontSize: variant.fontSize,
|
|
1812
|
+
fontWeight: variant.fontWeight,
|
|
1813
|
+
fontStyle: variant.fontStyle,
|
|
1814
|
+
letterSpacing: variant.letterSpacing
|
|
1815
|
+
}, globalConfig);
|
|
1816
|
+
if (typographyLines.length > 0) {
|
|
1817
|
+
lines.push("");
|
|
1818
|
+
lines.push(`.cux-${COMPONENT$4}.--${variantName} .cux-${COMPONENT$4}-initials {`);
|
|
1819
|
+
lines.push(...typographyLines);
|
|
1820
|
+
lines.push("}");
|
|
1821
|
+
}
|
|
1822
|
+
return lines.join("\n");
|
|
1823
|
+
}
|
|
1824
|
+
/**
|
|
1825
|
+
* Generate dark mode CSS for an avatar variant
|
|
1826
|
+
*/
|
|
1827
|
+
function generateAvatarVariantDark(variant, variantName) {
|
|
1828
|
+
const dark = variant.dark;
|
|
1829
|
+
if (!dark) return "";
|
|
1830
|
+
const lines = [];
|
|
1831
|
+
lines.push(`/* Dark Mode Variant: ${variant.name} */`);
|
|
1832
|
+
lines.push(`.dark .cux-${COMPONENT$4}.--${variantName} {`);
|
|
1833
|
+
lines.push(...generateDarkBaseProperties(COMPONENT$4, dark));
|
|
1834
|
+
const borderOverride = generateDarkBorderOverride(COMPONENT$4, variant.border, dark.borderColor);
|
|
1835
|
+
if (borderOverride) lines.push(borderOverride);
|
|
1836
|
+
const shadowVar = generateDarkShadowVar(COMPONENT$4, variant.shadows, dark);
|
|
1837
|
+
if (shadowVar) lines.push(shadowVar);
|
|
1838
|
+
lines.push("}");
|
|
1839
|
+
return lines.join("\n");
|
|
1840
|
+
}
|
|
1841
|
+
//#endregion
|
|
1842
|
+
//#region src/core/progress-generator.ts
|
|
1843
|
+
const COMPONENT$3 = "progress";
|
|
1844
|
+
/**
|
|
1845
|
+
* Generate complete CSS for progress component
|
|
1846
|
+
*/
|
|
1847
|
+
function generateProgressCSS(variants, globalConfig) {
|
|
1848
|
+
const css = [];
|
|
1849
|
+
css.push(generateProgressBase());
|
|
1850
|
+
variants.forEach((variant) => {
|
|
1851
|
+
const variantName = toKebabCase(variant.name);
|
|
1852
|
+
css.push(generateProgressVariant(variant, variantName, globalConfig));
|
|
1853
|
+
if (variant.dark) css.push(generateProgressVariantDark(variant, variantName));
|
|
1854
|
+
});
|
|
1855
|
+
return css.join("\n\n");
|
|
1856
|
+
}
|
|
1857
|
+
/**
|
|
1858
|
+
* Generate base progress styles
|
|
1859
|
+
*/
|
|
1860
|
+
function generateProgressBase() {
|
|
1861
|
+
return `/* Progress Base Styles */
|
|
1862
|
+
.cux-${COMPONENT$3} {
|
|
1863
|
+
--cux-${COMPONENT$3}-track-color: #e9ecef;
|
|
1864
|
+
--cux-${COMPONENT$3}-fill-color: #0d6efd;
|
|
1865
|
+
--cux-${COMPONENT$3}-stripe-color: rgba(255, 255, 255, 0.15);
|
|
1866
|
+
--cux-${COMPONENT$3}-height: 16px;
|
|
1867
|
+
--cux-${COMPONENT$3}-radius: 4px;
|
|
1868
|
+
--cux-${COMPONENT$3}-border: none;
|
|
1869
|
+
--cux-${COMPONENT$3}-shadow: none;
|
|
1870
|
+
--cux-${COMPONENT$3}-inset-shadow: none;
|
|
1871
|
+
--cux-${COMPONENT$3}-stripe-speed: 1s;
|
|
1872
|
+
|
|
1873
|
+
/* Label properties */
|
|
1874
|
+
--cux-${COMPONENT$3}-label-color: #212529;
|
|
1875
|
+
--cux-${COMPONENT$3}-label-font-size: 12px;
|
|
1876
|
+
|
|
1877
|
+
position: relative;
|
|
1878
|
+
display: flex;
|
|
1879
|
+
align-items: center;
|
|
1880
|
+
justify-content: center;
|
|
1881
|
+
background-color: var(--cux-${COMPONENT$3}-track-color);
|
|
1882
|
+
height: var(--cux-${COMPONENT$3}-height);
|
|
1883
|
+
border-radius: var(--cux-${COMPONENT$3}-radius);
|
|
1884
|
+
border: var(--cux-${COMPONENT$3}-border);
|
|
1885
|
+
box-shadow: var(--cux-${COMPONENT$3}-shadow);
|
|
1886
|
+
overflow: hidden;
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
.cux-${COMPONENT$3}-inset-overlay {
|
|
1890
|
+
position: absolute;
|
|
1891
|
+
inset: 0;
|
|
1892
|
+
z-index: 2;
|
|
1893
|
+
border-radius: var(--cux-${COMPONENT$3}-radius);
|
|
1894
|
+
box-shadow: var(--cux-${COMPONENT$3}-inset-shadow);
|
|
1895
|
+
pointer-events: none;
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
.cux-${COMPONENT$3}-fill {
|
|
1899
|
+
position: absolute;
|
|
1900
|
+
top: 0;
|
|
1901
|
+
left: 0;
|
|
1902
|
+
bottom: 0;
|
|
1903
|
+
height: 100%;
|
|
1904
|
+
background-color: var(--cux-${COMPONENT$3}-fill-color);
|
|
1905
|
+
transition: width 0.3s ease;
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
.cux-${COMPONENT$3}-fill.--striped {
|
|
1909
|
+
background-image: linear-gradient(
|
|
1910
|
+
45deg,
|
|
1911
|
+
var(--cux-${COMPONENT$3}-stripe-color) 25%,
|
|
1912
|
+
transparent 25%,
|
|
1913
|
+
transparent 50%,
|
|
1914
|
+
var(--cux-${COMPONENT$3}-stripe-color) 50%,
|
|
1915
|
+
var(--cux-${COMPONENT$3}-stripe-color) 75%,
|
|
1916
|
+
transparent 75%,
|
|
1917
|
+
transparent
|
|
1918
|
+
);
|
|
1919
|
+
background-size: calc(var(--cux-${COMPONENT$3}-height) * 2) calc(var(--cux-${COMPONENT$3}-height) * 2);
|
|
1920
|
+
background-color: var(--cux-${COMPONENT$3}-fill-color);
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
.cux-${COMPONENT$3}-fill.--animated {
|
|
1924
|
+
animation: cux-${COMPONENT$3}-stripes var(--cux-${COMPONENT$3}-stripe-speed) linear infinite;
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
@keyframes cux-${COMPONENT$3}-stripes {
|
|
1928
|
+
0% { background-position: 0 0; }
|
|
1929
|
+
100% { background-position: calc(var(--cux-${COMPONENT$3}-height) * -2) 0; }
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
.cux-${COMPONENT$3}-label {
|
|
1933
|
+
position: absolute;
|
|
1934
|
+
top: 50%;
|
|
1935
|
+
left: 50%;
|
|
1936
|
+
transform: translate(-50%, -50%);
|
|
1937
|
+
z-index: 10;
|
|
1938
|
+
color: var(--cux-${COMPONENT$3}-label-color);
|
|
1939
|
+
font-size: var(--cux-${COMPONENT$3}-label-font-size);
|
|
1940
|
+
pointer-events: none;
|
|
1941
|
+
}`;
|
|
1942
|
+
}
|
|
1943
|
+
/**
|
|
1944
|
+
* Generate CSS for a specific progress variant
|
|
1945
|
+
*/
|
|
1946
|
+
function generateProgressVariant(variant, variantName, globalConfig) {
|
|
1947
|
+
const lines = [];
|
|
1948
|
+
lines.push(`/* Variant: ${variant.name} */`);
|
|
1949
|
+
lines.push(`.cux-${COMPONENT$3}.--${variantName} {`);
|
|
1950
|
+
lines.push(` --cux-${COMPONENT$3}-track-color: ${variant.trackColor};`);
|
|
1951
|
+
lines.push(` --cux-${COMPONENT$3}-fill-color: ${variant.fillColor};`);
|
|
1952
|
+
lines.push(` --cux-${COMPONENT$3}-stripe-color: ${variant.stripeColor};`);
|
|
1953
|
+
if (variant.height) lines.push(` --cux-${COMPONENT$3}-height: ${variant.height.value}${variant.height.unit};`);
|
|
1954
|
+
if (variant.borderRadius) lines.push(` --cux-${COMPONENT$3}-radius: ${buildBorderRadius(variant.borderRadius)};`);
|
|
1955
|
+
if (variant.border) lines.push(` --cux-${COMPONENT$3}-border: ${buildBorder(variant.border)};`);
|
|
1956
|
+
lines.push(` --cux-${COMPONENT$3}-stripe-speed: ${variant.speed}s;`);
|
|
1957
|
+
const offsetShadow = generateOffsetShadowVar(COMPONENT$3, variant.shadows);
|
|
1958
|
+
if (offsetShadow) lines.push(offsetShadow);
|
|
1959
|
+
const insetShadow = generateInsetShadowVar(COMPONENT$3, variant.shadows);
|
|
1960
|
+
if (insetShadow) lines.push(insetShadow);
|
|
1961
|
+
lines.push("}");
|
|
1962
|
+
lines.push("");
|
|
1963
|
+
lines.push(`.cux-${COMPONENT$3}.--${variantName} .cux-${COMPONENT$3}-label {`);
|
|
1964
|
+
const labelTypography = generateTypographyLines({
|
|
1965
|
+
fontFamily: variant.fontFamily,
|
|
1966
|
+
fontSize: variant.labelFontSize,
|
|
1967
|
+
fontWeight: variant.fontWeight,
|
|
1968
|
+
fontStyle: variant.fontStyle
|
|
1969
|
+
}, globalConfig);
|
|
1970
|
+
lines.push(` color: ${variant.labelColor};`);
|
|
1971
|
+
lines.push(` font-size: ${buildFontSize(variant.labelFontSize)};`);
|
|
1972
|
+
lines.push(...labelTypography.filter((l) => !l.includes("font-size")));
|
|
1973
|
+
lines.push(` display: ${variant.showLabel ? "block" : "none"};`);
|
|
1974
|
+
lines.push("}");
|
|
1975
|
+
return lines.join("\n");
|
|
1976
|
+
}
|
|
1977
|
+
/**
|
|
1978
|
+
* Generate dark mode CSS for a progress variant
|
|
1979
|
+
*/
|
|
1980
|
+
function generateProgressVariantDark(variant, variantName) {
|
|
1981
|
+
const dark = variant.dark;
|
|
1982
|
+
if (!dark) return "";
|
|
1983
|
+
const lines = [];
|
|
1984
|
+
lines.push(`/* Dark Mode Variant: ${variant.name} */`);
|
|
1985
|
+
lines.push(`.dark .cux-${COMPONENT$3}.--${variantName} {`);
|
|
1986
|
+
if (dark.trackColor) lines.push(` --cux-${COMPONENT$3}-track-color: ${dark.trackColor};`);
|
|
1987
|
+
if (dark.fillColor) lines.push(` --cux-${COMPONENT$3}-fill-color: ${dark.fillColor};`);
|
|
1988
|
+
if (dark.stripeColor) lines.push(` --cux-${COMPONENT$3}-stripe-color: ${dark.stripeColor};`);
|
|
1989
|
+
const borderOverride = generateDarkBorderOverride(COMPONENT$3, variant.border, dark.borderColor);
|
|
1990
|
+
if (borderOverride) lines.push(borderOverride);
|
|
1991
|
+
const offsetShadow = generateDarkOffsetShadowVar(COMPONENT$3, variant.shadows, dark.shadowColor);
|
|
1992
|
+
if (offsetShadow) lines.push(offsetShadow);
|
|
1993
|
+
const insetShadow = generateDarkInsetShadowVar(COMPONENT$3, variant.shadows, dark.shadowInsetColor, dark.shadowInsetHighlightColor);
|
|
1994
|
+
if (insetShadow) lines.push(insetShadow);
|
|
1995
|
+
lines.push("}");
|
|
1996
|
+
if (dark.labelColor) {
|
|
1997
|
+
lines.push("");
|
|
1998
|
+
lines.push(`.dark .cux-${COMPONENT$3}.--${variantName} .cux-${COMPONENT$3}-label {`);
|
|
1999
|
+
lines.push(` color: ${dark.labelColor};`);
|
|
2000
|
+
lines.push("}");
|
|
2001
|
+
}
|
|
2002
|
+
return lines.join("\n");
|
|
2003
|
+
}
|
|
2004
|
+
//#endregion
|
|
2005
|
+
//#region src/core/spinner-generator.ts
|
|
2006
|
+
const COMPONENT$2 = "spinner";
|
|
2007
|
+
/**
|
|
2008
|
+
* Generate complete CSS for spinner component
|
|
2009
|
+
*/
|
|
2010
|
+
function generateSpinnerCSS(variants) {
|
|
2011
|
+
const css = [];
|
|
2012
|
+
css.push(generateSpinnerBase());
|
|
2013
|
+
css.push(generateSpinnerAnimations());
|
|
2014
|
+
variants.forEach((variant) => {
|
|
2015
|
+
const variantName = toKebabCase(variant.name);
|
|
2016
|
+
css.push(generateSpinnerVariant(variant, variantName));
|
|
2017
|
+
if (variant.dark) css.push(generateSpinnerVariantDark(variant, variantName));
|
|
2018
|
+
});
|
|
2019
|
+
return css.join("\n\n");
|
|
2020
|
+
}
|
|
2021
|
+
/**
|
|
2022
|
+
* Generate base spinner styles (shared across all types)
|
|
2023
|
+
*/
|
|
2024
|
+
function generateSpinnerBase() {
|
|
2025
|
+
return `/* Spinner Base Styles */
|
|
2026
|
+
.cux-${COMPONENT$2} {
|
|
2027
|
+
--cux-${COMPONENT$2}-color: #0d6efd;
|
|
2028
|
+
--cux-${COMPONENT$2}-track: #95b6d8;
|
|
2029
|
+
--cux-${COMPONENT$2}-size: 40px;
|
|
2030
|
+
--cux-${COMPONENT$2}-speed: 1s;
|
|
2031
|
+
--cux-${COMPONENT$2}-delay2: 0.2s;
|
|
2032
|
+
--cux-${COMPONENT$2}-delay3: 0.4s;
|
|
2033
|
+
--cux-${COMPONENT$2}-delay4: 0.6s;
|
|
2034
|
+
--cux-${COMPONENT$2}-delay5: 0.8s;
|
|
2035
|
+
|
|
2036
|
+
display: inline-flex;
|
|
2037
|
+
align-items: center;
|
|
2038
|
+
justify-content: center;
|
|
2039
|
+
}`;
|
|
2040
|
+
}
|
|
2041
|
+
/**
|
|
2042
|
+
* Generate all spinner animations
|
|
2043
|
+
*/
|
|
2044
|
+
function generateSpinnerAnimations() {
|
|
2045
|
+
return `/* Spinner Animations */
|
|
2046
|
+
@keyframes cux-${COMPONENT$2}-ring-spin {
|
|
2047
|
+
to { transform: rotate(360deg); }
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
@keyframes cux-${COMPONENT$2}-pulse-scale {
|
|
2051
|
+
0%, 100% {
|
|
2052
|
+
transform: scale(0.5);
|
|
2053
|
+
opacity: 0.3;
|
|
2054
|
+
}
|
|
2055
|
+
50% {
|
|
2056
|
+
transform: scale(1);
|
|
2057
|
+
opacity: 1;
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
@keyframes cux-${COMPONENT$2}-dots-bounce {
|
|
2062
|
+
0%, 100% {
|
|
2063
|
+
transform: translateY(0);
|
|
2064
|
+
opacity: 0.3;
|
|
2065
|
+
}
|
|
2066
|
+
50% {
|
|
2067
|
+
transform: translateY(calc(var(--cux-${COMPONENT$2}-size) * -0.25));
|
|
2068
|
+
opacity: 1;
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
@keyframes cux-${COMPONENT$2}-bars-stretch {
|
|
2073
|
+
0%, 100% {
|
|
2074
|
+
transform: scaleY(0.3);
|
|
2075
|
+
opacity: 0.3;
|
|
2076
|
+
}
|
|
2077
|
+
50% {
|
|
2078
|
+
transform: scaleY(1);
|
|
2079
|
+
opacity: 1;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
@keyframes cux-${COMPONENT$2}-dual-spin {
|
|
2084
|
+
to { transform: rotate(360deg); }
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
/* Ring Spinner */
|
|
2088
|
+
.cux-${COMPONENT$2}-ring {
|
|
2089
|
+
width: var(--cux-${COMPONENT$2}-size);
|
|
2090
|
+
height: var(--cux-${COMPONENT$2}-size);
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
.cux-${COMPONENT$2}-ring-track {
|
|
2094
|
+
stroke: var(--cux-${COMPONENT$2}-track);
|
|
2095
|
+
fill: none;
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
.cux-${COMPONENT$2}-ring-arc {
|
|
2099
|
+
stroke: var(--cux-${COMPONENT$2}-color);
|
|
2100
|
+
fill: none;
|
|
2101
|
+
stroke-linecap: round;
|
|
2102
|
+
animation: cux-${COMPONENT$2}-ring-spin var(--cux-${COMPONENT$2}-speed) linear infinite;
|
|
2103
|
+
transform-origin: center;
|
|
2104
|
+
transform-box: fill-box;
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
/* Pulse Spinner */
|
|
2108
|
+
.cux-${COMPONENT$2}-pulse {
|
|
2109
|
+
width: var(--cux-${COMPONENT$2}-size);
|
|
2110
|
+
height: var(--cux-${COMPONENT$2}-size);
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
.cux-${COMPONENT$2}-pulse-bg {
|
|
2114
|
+
fill: var(--cux-${COMPONENT$2}-track);
|
|
2115
|
+
opacity: 0.3;
|
|
2116
|
+
animation: cux-${COMPONENT$2}-pulse-scale var(--cux-${COMPONENT$2}-speed) ease-in-out infinite;
|
|
2117
|
+
transform-origin: center;
|
|
2118
|
+
transform-box: fill-box;
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
.cux-${COMPONENT$2}-pulse-fg {
|
|
2122
|
+
fill: var(--cux-${COMPONENT$2}-color);
|
|
2123
|
+
animation: cux-${COMPONENT$2}-pulse-scale var(--cux-${COMPONENT$2}-speed) ease-in-out infinite reverse;
|
|
2124
|
+
transform-origin: center;
|
|
2125
|
+
transform-box: fill-box;
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2128
|
+
/* Dots Spinner */
|
|
2129
|
+
.cux-${COMPONENT$2}-dots {
|
|
2130
|
+
display: flex;
|
|
2131
|
+
gap: calc(var(--cux-${COMPONENT$2}-size) * 0.15);
|
|
2132
|
+
align-items: center;
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
.cux-${COMPONENT$2}-dot {
|
|
2136
|
+
width: calc(var(--cux-${COMPONENT$2}-size) * 0.2);
|
|
2137
|
+
height: calc(var(--cux-${COMPONENT$2}-size) * 0.2);
|
|
2138
|
+
background: var(--cux-${COMPONENT$2}-color);
|
|
2139
|
+
border-radius: 50%;
|
|
2140
|
+
animation: cux-${COMPONENT$2}-dots-bounce var(--cux-${COMPONENT$2}-speed) ease-in-out infinite;
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
.cux-${COMPONENT$2}-dot:nth-child(1) { animation-delay: 0s; }
|
|
2144
|
+
.cux-${COMPONENT$2}-dot:nth-child(2) { animation-delay: var(--cux-${COMPONENT$2}-delay2); }
|
|
2145
|
+
.cux-${COMPONENT$2}-dot:nth-child(3) { animation-delay: var(--cux-${COMPONENT$2}-delay3); }
|
|
2146
|
+
|
|
2147
|
+
/* Bars Spinner */
|
|
2148
|
+
.cux-${COMPONENT$2}-bars {
|
|
2149
|
+
display: flex;
|
|
2150
|
+
gap: calc(var(--cux-${COMPONENT$2}-size) * 0.1);
|
|
2151
|
+
align-items: center;
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
.cux-${COMPONENT$2}-bar {
|
|
2155
|
+
width: calc(var(--cux-${COMPONENT$2}-size) * 0.15);
|
|
2156
|
+
height: calc(var(--cux-${COMPONENT$2}-size) * 0.4);
|
|
2157
|
+
background: var(--cux-${COMPONENT$2}-color);
|
|
2158
|
+
border-radius: 2px;
|
|
2159
|
+
animation: cux-${COMPONENT$2}-bars-stretch var(--cux-${COMPONENT$2}-speed) ease-in-out infinite;
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
.cux-${COMPONENT$2}-bar:nth-child(1) { animation-delay: 0s; }
|
|
2163
|
+
.cux-${COMPONENT$2}-bar:nth-child(2) { animation-delay: var(--cux-${COMPONENT$2}-delay2); }
|
|
2164
|
+
.cux-${COMPONENT$2}-bar:nth-child(3) { animation-delay: var(--cux-${COMPONENT$2}-delay3); }
|
|
2165
|
+
.cux-${COMPONENT$2}-bar:nth-child(4) { animation-delay: var(--cux-${COMPONENT$2}-delay4); }
|
|
2166
|
+
.cux-${COMPONENT$2}-bar:nth-child(5) { animation-delay: var(--cux-${COMPONENT$2}-delay5); }
|
|
2167
|
+
|
|
2168
|
+
/* Dual Spinner */
|
|
2169
|
+
.cux-${COMPONENT$2}-dual {
|
|
2170
|
+
width: var(--cux-${COMPONENT$2}-size);
|
|
2171
|
+
height: var(--cux-${COMPONENT$2}-size);
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
.cux-${COMPONENT$2}-dual-outer,
|
|
2175
|
+
.cux-${COMPONENT$2}-dual-inner {
|
|
2176
|
+
animation: cux-${COMPONENT$2}-dual-spin var(--cux-${COMPONENT$2}-speed) linear infinite;
|
|
2177
|
+
transform-origin: center;
|
|
2178
|
+
transform-box: fill-box;
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2181
|
+
.cux-${COMPONENT$2}-dual-outer circle {
|
|
2182
|
+
stroke: var(--cux-${COMPONENT$2}-color);
|
|
2183
|
+
fill: none;
|
|
2184
|
+
stroke-linecap: round;
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
.cux-${COMPONENT$2}-dual-inner circle {
|
|
2188
|
+
stroke: var(--cux-${COMPONENT$2}-track);
|
|
2189
|
+
fill: none;
|
|
2190
|
+
stroke-linecap: round;
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
.cux-${COMPONENT$2}-dual-inner {
|
|
2194
|
+
animation-direction: reverse;
|
|
2195
|
+
opacity: 0.6;
|
|
2196
|
+
}`;
|
|
2197
|
+
}
|
|
2198
|
+
/**
|
|
2199
|
+
* Generate CSS for a specific spinner variant
|
|
2200
|
+
*/
|
|
2201
|
+
function generateSpinnerVariant(variant, variantName) {
|
|
2202
|
+
const size = variant.size ? `${variant.size.value}${variant.size.unit}` : "40px";
|
|
2203
|
+
const speed = `${variant.speed}s`;
|
|
2204
|
+
const delay2 = `${Math.round(variant.speed * .2 * 100) / 100}s`;
|
|
2205
|
+
const delay3 = `${Math.round(variant.speed * .4 * 100) / 100}s`;
|
|
2206
|
+
const delay4 = `${Math.round(variant.speed * .6 * 100) / 100}s`;
|
|
2207
|
+
const delay5 = `${Math.round(variant.speed * .8 * 100) / 100}s`;
|
|
2208
|
+
const lines = [];
|
|
2209
|
+
lines.push(`/* Variant: ${variant.name} */`);
|
|
2210
|
+
lines.push(`.cux-${COMPONENT$2}.--${variantName} {`);
|
|
2211
|
+
lines.push(` --cux-${COMPONENT$2}-color: ${variant.color};`);
|
|
2212
|
+
lines.push(` --cux-${COMPONENT$2}-track: ${variant.trackColor};`);
|
|
2213
|
+
lines.push(` --cux-${COMPONENT$2}-size: ${size};`);
|
|
2214
|
+
lines.push(` --cux-${COMPONENT$2}-speed: ${speed};`);
|
|
2215
|
+
lines.push(` --cux-${COMPONENT$2}-delay2: ${delay2};`);
|
|
2216
|
+
lines.push(` --cux-${COMPONENT$2}-delay3: ${delay3};`);
|
|
2217
|
+
lines.push(` --cux-${COMPONENT$2}-delay4: ${delay4};`);
|
|
2218
|
+
lines.push(` --cux-${COMPONENT$2}-delay5: ${delay5};`);
|
|
2219
|
+
lines.push("}");
|
|
2220
|
+
return lines.join("\n");
|
|
2221
|
+
}
|
|
2222
|
+
/**
|
|
2223
|
+
* Generate dark mode CSS for a spinner variant
|
|
2224
|
+
*/
|
|
2225
|
+
function generateSpinnerVariantDark(variant, variantName) {
|
|
2226
|
+
const dark = variant.dark;
|
|
2227
|
+
if (!dark) return "";
|
|
2228
|
+
const lines = [];
|
|
2229
|
+
lines.push(`/* Dark Mode Variant: ${variant.name} */`);
|
|
2230
|
+
lines.push(`.dark .cux-${COMPONENT$2}.--${variantName} {`);
|
|
2231
|
+
if (dark.color) lines.push(` --cux-${COMPONENT$2}-color: ${dark.color};`);
|
|
2232
|
+
if (dark.trackColor) lines.push(` --cux-${COMPONENT$2}-track: ${dark.trackColor};`);
|
|
2233
|
+
lines.push("}");
|
|
2234
|
+
return lines.join("\n");
|
|
2235
|
+
}
|
|
2236
|
+
//#endregion
|
|
2237
|
+
//#region src/core/badge-generator.ts
|
|
2238
|
+
const COMPONENT$1 = "badge";
|
|
2239
|
+
/**
|
|
2240
|
+
* Generate complete CSS for badge component
|
|
2241
|
+
*/
|
|
2242
|
+
function generateBadgeCSS(variants, globalConfig) {
|
|
2243
|
+
const css = [];
|
|
2244
|
+
css.push(generateBadgeBase());
|
|
2245
|
+
variants.forEach((variant) => {
|
|
2246
|
+
const variantName = toKebabCase(variant.name);
|
|
2247
|
+
css.push(generateBadgeVariant(variant, variantName, globalConfig));
|
|
2248
|
+
if (variant.dark) css.push(generateBadgeVariantDark(variant, variantName));
|
|
2249
|
+
});
|
|
2250
|
+
return css.join("\n\n");
|
|
2251
|
+
}
|
|
2252
|
+
/**
|
|
2253
|
+
* Generate base badge styles
|
|
2254
|
+
*/
|
|
2255
|
+
function generateBadgeBase() {
|
|
2256
|
+
return `/* Badge Base Styles */
|
|
2257
|
+
.cux-${COMPONENT$1} {
|
|
2258
|
+
--cux-${COMPONENT$1}-bg: #6c757d;
|
|
2259
|
+
--cux-${COMPONENT$1}-color: #ffffff;
|
|
2260
|
+
--cux-${COMPONENT$1}-border: none;
|
|
2261
|
+
--cux-${COMPONENT$1}-radius: 4px;
|
|
2262
|
+
--cux-${COMPONENT$1}-padding: 4px 8px;
|
|
2263
|
+
--cux-${COMPONENT$1}-shadow: none;
|
|
2264
|
+
|
|
2265
|
+
display: inline-flex;
|
|
2266
|
+
align-items: center;
|
|
2267
|
+
justify-content: center;
|
|
2268
|
+
background: var(--cux-${COMPONENT$1}-bg);
|
|
2269
|
+
color: var(--cux-${COMPONENT$1}-color);
|
|
2270
|
+
border: var(--cux-${COMPONENT$1}-border);
|
|
2271
|
+
border-radius: var(--cux-${COMPONENT$1}-radius);
|
|
2272
|
+
padding: var(--cux-${COMPONENT$1}-padding);
|
|
2273
|
+
box-shadow: var(--cux-${COMPONENT$1}-shadow);
|
|
2274
|
+
white-space: nowrap;
|
|
2275
|
+
vertical-align: middle;
|
|
2276
|
+
}`;
|
|
2277
|
+
}
|
|
2278
|
+
/**
|
|
2279
|
+
* Generate CSS for a specific badge variant
|
|
2280
|
+
*/
|
|
2281
|
+
function generateBadgeVariant(variant, variantName, globalConfig) {
|
|
2282
|
+
const lines = [];
|
|
2283
|
+
lines.push(`/* Variant: ${variant.name} */`);
|
|
2284
|
+
lines.push(`.cux-${COMPONENT$1}.--${variantName} {`);
|
|
2285
|
+
lines.push(...generateBaseProperties(COMPONENT$1, variant));
|
|
2286
|
+
const shadowVar = generateShadowVar(COMPONENT$1, variant.shadows);
|
|
2287
|
+
if (shadowVar) lines.push(shadowVar);
|
|
2288
|
+
lines.push("}");
|
|
2289
|
+
const typographyBlock = generateTypographyBlock(`.cux-${COMPONENT$1}.--${variantName}`, {
|
|
2290
|
+
fontFamily: variant.fontFamily,
|
|
2291
|
+
fontSize: variant.fontSize,
|
|
2292
|
+
fontWeight: variant.fontWeight,
|
|
2293
|
+
fontStyle: variant.fontStyle,
|
|
2294
|
+
letterSpacing: variant.letterSpacing
|
|
2295
|
+
}, globalConfig);
|
|
2296
|
+
if (typographyBlock) {
|
|
2297
|
+
lines.push("");
|
|
2298
|
+
lines.push(typographyBlock);
|
|
2299
|
+
}
|
|
2300
|
+
return lines.join("\n");
|
|
2301
|
+
}
|
|
2302
|
+
/**
|
|
2303
|
+
* Generate dark mode CSS for a badge variant
|
|
2304
|
+
*/
|
|
2305
|
+
function generateBadgeVariantDark(variant, variantName) {
|
|
2306
|
+
const dark = variant.dark;
|
|
2307
|
+
if (!dark) return "";
|
|
2308
|
+
const lines = [];
|
|
2309
|
+
lines.push(`/* Dark Mode Variant: ${variant.name} */`);
|
|
2310
|
+
lines.push(`.dark .cux-${COMPONENT$1}.--${variantName} {`);
|
|
2311
|
+
lines.push(...generateDarkBaseProperties(COMPONENT$1, dark));
|
|
2312
|
+
const borderOverride = generateDarkBorderOverride(COMPONENT$1, variant.border, dark.borderColor);
|
|
2313
|
+
if (borderOverride) lines.push(borderOverride);
|
|
2314
|
+
const shadowVar = generateDarkShadowVar(COMPONENT$1, variant.shadows, dark);
|
|
2315
|
+
if (shadowVar) lines.push(shadowVar);
|
|
2316
|
+
lines.push("}");
|
|
2317
|
+
return lines.join("\n");
|
|
2318
|
+
}
|
|
2319
|
+
//#endregion
|
|
2320
|
+
//#region src/core/chip-generator.ts
|
|
2321
|
+
const COMPONENT = "chip";
|
|
2322
|
+
/**
|
|
2323
|
+
* Generate complete CSS for chip component
|
|
2324
|
+
*/
|
|
2325
|
+
function generateChipCSS(variants, globalConfig) {
|
|
2326
|
+
const css = [];
|
|
2327
|
+
css.push(generateChipBase());
|
|
2328
|
+
variants.forEach((variant) => {
|
|
2329
|
+
const variantName = toKebabCase(variant.name);
|
|
2330
|
+
css.push(generateChipVariant(variant, variantName, globalConfig));
|
|
2331
|
+
if (variant.dark) css.push(generateChipVariantDark(variant, variantName));
|
|
2332
|
+
});
|
|
2333
|
+
return css.join("\n\n");
|
|
2334
|
+
}
|
|
2335
|
+
/**
|
|
2336
|
+
* Generate base chip styles
|
|
2337
|
+
*/
|
|
2338
|
+
function generateChipBase() {
|
|
2339
|
+
return `/* Chip Base Styles */
|
|
2340
|
+
.cux-${COMPONENT} {
|
|
2341
|
+
--cux-${COMPONENT}-bg: #e9ecef;
|
|
2342
|
+
--cux-${COMPONENT}-color: #212529;
|
|
2343
|
+
--cux-${COMPONENT}-border: none;
|
|
2344
|
+
--cux-${COMPONENT}-radius: 16px;
|
|
2345
|
+
--cux-${COMPONENT}-padding: 4px 12px;
|
|
2346
|
+
--cux-${COMPONENT}-shadow: none;
|
|
2347
|
+
|
|
2348
|
+
/* Close button properties */
|
|
2349
|
+
--cux-${COMPONENT}-close-size: 16px;
|
|
2350
|
+
--cux-${COMPONENT}-close-color: #495057;
|
|
2351
|
+
--cux-${COMPONENT}-close-hover-color: #212529;
|
|
2352
|
+
--cux-${COMPONENT}-close-active-color: #000000;
|
|
2353
|
+
|
|
2354
|
+
display: inline-flex;
|
|
2355
|
+
align-items: center;
|
|
2356
|
+
justify-content: center;
|
|
2357
|
+
gap: 6px;
|
|
2358
|
+
background: var(--cux-${COMPONENT}-bg);
|
|
2359
|
+
color: var(--cux-${COMPONENT}-color);
|
|
2360
|
+
border: var(--cux-${COMPONENT}-border);
|
|
2361
|
+
border-radius: var(--cux-${COMPONENT}-radius);
|
|
2362
|
+
padding: var(--cux-${COMPONENT}-padding);
|
|
2363
|
+
box-shadow: var(--cux-${COMPONENT}-shadow);
|
|
2364
|
+
white-space: nowrap;
|
|
2365
|
+
vertical-align: middle;
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
.cux-${COMPONENT}-close {
|
|
2369
|
+
display: inline-flex;
|
|
2370
|
+
align-items: center;
|
|
2371
|
+
justify-content: center;
|
|
2372
|
+
width: var(--cux-${COMPONENT}-close-size);
|
|
2373
|
+
height: var(--cux-${COMPONENT}-close-size);
|
|
2374
|
+
background: transparent;
|
|
2375
|
+
border: none;
|
|
2376
|
+
color: var(--cux-${COMPONENT}-close-color);
|
|
2377
|
+
cursor: pointer;
|
|
2378
|
+
border-radius: 4px;
|
|
2379
|
+
transition: color 0.15s ease;
|
|
2380
|
+
padding: 0;
|
|
2381
|
+
flex-shrink: 0;
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
.cux-${COMPONENT}-close:hover {
|
|
2385
|
+
color: var(--cux-${COMPONENT}-close-hover-color);
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
.cux-${COMPONENT}-close:active {
|
|
2389
|
+
color: var(--cux-${COMPONENT}-close-active-color);
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2392
|
+
.cux-${COMPONENT}-close svg {
|
|
2393
|
+
width: 100%;
|
|
2394
|
+
height: 100%;
|
|
2395
|
+
}`;
|
|
2396
|
+
}
|
|
2397
|
+
/**
|
|
2398
|
+
* Generate CSS for a specific chip variant
|
|
2399
|
+
*/
|
|
2400
|
+
function generateChipVariant(variant, variantName, globalConfig) {
|
|
2401
|
+
const lines = [];
|
|
2402
|
+
lines.push(`/* Variant: ${variant.name} */`);
|
|
2403
|
+
lines.push(`.cux-${COMPONENT}.--${variantName} {`);
|
|
2404
|
+
lines.push(...generateBaseProperties(COMPONENT, variant));
|
|
2405
|
+
const shadowVar = generateShadowVar(COMPONENT, variant.shadows);
|
|
2406
|
+
if (shadowVar) lines.push(shadowVar);
|
|
2407
|
+
if (variant.closeSize) lines.push(` --cux-${COMPONENT}-close-size: ${variant.closeSize.value}${variant.closeSize.unit};`);
|
|
2408
|
+
lines.push(` --cux-${COMPONENT}-close-color: ${variant.closeColor};`);
|
|
2409
|
+
lines.push(` --cux-${COMPONENT}-close-hover-color: ${variant.closeHoverColor};`);
|
|
2410
|
+
lines.push(` --cux-${COMPONENT}-close-active-color: ${variant.closeActiveColor};`);
|
|
2411
|
+
lines.push("}");
|
|
2412
|
+
const typographyLines = generateTypographyLines({
|
|
2413
|
+
fontFamily: variant.fontFamily,
|
|
2414
|
+
fontSize: variant.fontSize,
|
|
2415
|
+
fontWeight: variant.fontWeight,
|
|
2416
|
+
fontStyle: variant.fontStyle,
|
|
2417
|
+
letterSpacing: variant.letterSpacing
|
|
2418
|
+
}, globalConfig);
|
|
2419
|
+
if (typographyLines.length > 0) {
|
|
2420
|
+
lines.push("");
|
|
2421
|
+
lines.push(`.cux-${COMPONENT}.--${variantName} {`);
|
|
2422
|
+
lines.push(...typographyLines);
|
|
2423
|
+
lines.push("}");
|
|
2424
|
+
}
|
|
2425
|
+
return lines.join("\n");
|
|
2426
|
+
}
|
|
2427
|
+
/**
|
|
2428
|
+
* Generate dark mode CSS for a chip variant
|
|
2429
|
+
*/
|
|
2430
|
+
function generateChipVariantDark(variant, variantName) {
|
|
2431
|
+
const dark = variant.dark;
|
|
2432
|
+
if (!dark) return "";
|
|
2433
|
+
const lines = [];
|
|
2434
|
+
lines.push(`/* Dark Mode Variant: ${variant.name} */`);
|
|
2435
|
+
lines.push(`.dark .cux-${COMPONENT}.--${variantName} {`);
|
|
2436
|
+
lines.push(...generateDarkBaseProperties(COMPONENT, dark));
|
|
2437
|
+
const borderOverride = generateDarkBorderOverride(COMPONENT, variant.border, dark.borderColor);
|
|
2438
|
+
if (borderOverride) lines.push(borderOverride);
|
|
2439
|
+
if (dark.closeColor) lines.push(` --cux-${COMPONENT}-close-color: ${dark.closeColor};`);
|
|
2440
|
+
if (dark.closeHoverColor) lines.push(` --cux-${COMPONENT}-close-hover-color: ${dark.closeHoverColor};`);
|
|
2441
|
+
if (dark.closeActiveColor) lines.push(` --cux-${COMPONENT}-close-active-color: ${dark.closeActiveColor};`);
|
|
2442
|
+
const shadowVar = generateDarkShadowVar(COMPONENT, variant.shadows, dark);
|
|
2443
|
+
if (shadowVar) lines.push(shadowVar);
|
|
2444
|
+
lines.push("}");
|
|
2445
|
+
return lines.join("\n");
|
|
2446
|
+
}
|
|
2447
|
+
//#endregion
|
|
2448
|
+
//#region src/combo-ux.ts
|
|
2449
|
+
var ComboUX = class {
|
|
2450
|
+
options;
|
|
2451
|
+
darkMode;
|
|
2452
|
+
cssInjector;
|
|
2453
|
+
themeLoader;
|
|
2454
|
+
themeSync = null;
|
|
2455
|
+
currentTheme = null;
|
|
2456
|
+
constructor(options) {
|
|
2457
|
+
this.options = {
|
|
2458
|
+
theme: options.theme,
|
|
2459
|
+
darkMode: options.darkMode ?? "auto",
|
|
2460
|
+
persistDarkMode: options.persistDarkMode ?? true,
|
|
2461
|
+
darkModeStorageKey: options.darkModeStorageKey ?? "cux-dark-mode"
|
|
2462
|
+
};
|
|
2463
|
+
this.darkMode = new DarkMode({
|
|
2464
|
+
persist: this.options.persistDarkMode,
|
|
2465
|
+
storageKey: this.options.darkModeStorageKey
|
|
2466
|
+
});
|
|
2467
|
+
this.cssInjector = new CSSInjector();
|
|
2468
|
+
this.themeLoader = new ThemeLoader();
|
|
2469
|
+
if (options.ws && options.ws !== false) this.themeSync = new ThemeSync((theme) => this.updateTheme(theme), typeof options.ws === "string" ? { url: options.ws } : options.ws);
|
|
2470
|
+
}
|
|
2471
|
+
/**
|
|
2472
|
+
* Initialize the library (must be called manually or via composable)
|
|
2473
|
+
*/
|
|
2474
|
+
async init() {
|
|
2475
|
+
injectBasscss();
|
|
2476
|
+
this.darkMode.init(this.options.darkMode);
|
|
2477
|
+
try {
|
|
2478
|
+
await this.loadTheme(this.options.theme);
|
|
2479
|
+
} catch (error) {
|
|
2480
|
+
console.error("Failed to load theme:", error);
|
|
2481
|
+
}
|
|
2482
|
+
if (this.themeSync) this.themeSync.connect();
|
|
2483
|
+
}
|
|
2484
|
+
/**
|
|
2485
|
+
* Inject base styles with theme colors
|
|
2486
|
+
*/
|
|
2487
|
+
injectBaseStylesFromTheme(theme) {
|
|
2488
|
+
const backgroundColor = theme.typography?.globalConfig?.backgroundColor;
|
|
2489
|
+
const darkBackgroundColor = theme.typography?.globalConfig?.dark?.backgroundColor;
|
|
2490
|
+
const textColor = theme.typography?.globalConfig?.color;
|
|
2491
|
+
const darkTextColor = theme.typography?.globalConfig?.dark?.color;
|
|
2492
|
+
if (backgroundColor || darkBackgroundColor || textColor || darkTextColor) updateBaseStyles({
|
|
2493
|
+
backgroundColor,
|
|
2494
|
+
darkBackgroundColor,
|
|
2495
|
+
textColor,
|
|
2496
|
+
darkTextColor
|
|
2497
|
+
});
|
|
2498
|
+
else injectBaseStyles();
|
|
2499
|
+
}
|
|
2500
|
+
/**
|
|
2501
|
+
* Load theme from URL or object
|
|
2502
|
+
*/
|
|
2503
|
+
async loadTheme(theme) {
|
|
2504
|
+
const themeData = await this.themeLoader.load(theme);
|
|
2505
|
+
this.currentTheme = themeData;
|
|
2506
|
+
this.applyTheme(themeData);
|
|
2507
|
+
}
|
|
2508
|
+
/**
|
|
2509
|
+
* Apply theme by generating and injecting CSS
|
|
2510
|
+
*/
|
|
2511
|
+
applyTheme(theme) {
|
|
2512
|
+
this.injectBaseStylesFromTheme(theme);
|
|
2513
|
+
const cssParts = [];
|
|
2514
|
+
if (theme.typography) {
|
|
2515
|
+
loadFontsFromTypography(theme.typography);
|
|
2516
|
+
const typographyCSS = generateTypographyCSS(theme.typography);
|
|
2517
|
+
if (typographyCSS) cssParts.push(typographyCSS);
|
|
2518
|
+
}
|
|
2519
|
+
if (theme.forms?.globalConfig) {
|
|
2520
|
+
loadFontsFromForms(theme.forms);
|
|
2521
|
+
const formsCSS = generateFormsCSS(theme.forms, theme.typography);
|
|
2522
|
+
if (formsCSS) cssParts.push(formsCSS);
|
|
2523
|
+
}
|
|
2524
|
+
if (theme.buttons?.variants?.length) {
|
|
2525
|
+
loadFontsFromButtonVariants(theme.buttons.variants);
|
|
2526
|
+
cssParts.push(generateButtonCSS(theme.buttons.variants, theme.typography?.globalConfig));
|
|
2527
|
+
}
|
|
2528
|
+
if (theme.cards?.variants?.length) cssParts.push(generateCardCSS(theme.cards.variants, theme.typography?.globalConfig));
|
|
2529
|
+
if (theme.alerts?.variants?.length) cssParts.push(generateAlertCSS(theme.alerts.variants, theme.typography?.globalConfig));
|
|
2530
|
+
if (theme.avatars?.variants?.length) {
|
|
2531
|
+
loadFontsFromAvatarVariants(theme.avatars.variants);
|
|
2532
|
+
cssParts.push(generateAvatarCSS(theme.avatars.variants, theme.typography?.globalConfig));
|
|
2533
|
+
}
|
|
2534
|
+
if (theme.progress?.variants?.length) cssParts.push(generateProgressCSS(theme.progress.variants, theme.typography?.globalConfig));
|
|
2535
|
+
if (theme.spinners?.variants?.length) cssParts.push(generateSpinnerCSS(theme.spinners.variants));
|
|
2536
|
+
if (theme.badges?.variants?.length) cssParts.push(generateBadgeCSS(theme.badges.variants, theme.typography?.globalConfig));
|
|
2537
|
+
if (theme.chips?.variants?.length) cssParts.push(generateChipCSS(theme.chips.variants, theme.typography?.globalConfig));
|
|
2538
|
+
if (cssParts.length > 0) this.cssInjector.inject(cssParts.join("\n\n"));
|
|
2539
|
+
}
|
|
2540
|
+
/**
|
|
2541
|
+
* Update theme (for real-time updates via websockets)
|
|
2542
|
+
*/
|
|
2543
|
+
updateTheme(theme) {
|
|
2544
|
+
this.currentTheme = theme;
|
|
2545
|
+
this.applyTheme(theme);
|
|
2546
|
+
}
|
|
2547
|
+
/**
|
|
2548
|
+
* Update a specific button variant
|
|
2549
|
+
*/
|
|
2550
|
+
updateButtonVariant(variantName, updates) {
|
|
2551
|
+
if (!this.currentTheme?.buttons?.variants) return;
|
|
2552
|
+
const variant = this.currentTheme.buttons.variants.find((v) => v.name.toLowerCase() === variantName.toLowerCase());
|
|
2553
|
+
if (variant) {
|
|
2554
|
+
Object.assign(variant, updates);
|
|
2555
|
+
this.applyTheme(this.currentTheme);
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
/** Check if dark mode is active */
|
|
2559
|
+
get isDark() {
|
|
2560
|
+
return this.darkMode.isDark;
|
|
2561
|
+
}
|
|
2562
|
+
/** Set dark mode */
|
|
2563
|
+
setDarkMode(value) {
|
|
2564
|
+
this.darkMode.setDarkMode(value);
|
|
2565
|
+
}
|
|
2566
|
+
/** Toggle dark mode */
|
|
2567
|
+
toggleDarkMode() {
|
|
2568
|
+
this.darkMode.toggle();
|
|
2569
|
+
}
|
|
2570
|
+
/** Register callback for dark mode changes */
|
|
2571
|
+
onDarkModeChange(callback) {
|
|
2572
|
+
return this.darkMode.onChange(callback);
|
|
2573
|
+
}
|
|
2574
|
+
/** Check if WebSocket is connected */
|
|
2575
|
+
get isSyncConnected() {
|
|
2576
|
+
return this.themeSync?.isConnected ?? false;
|
|
2577
|
+
}
|
|
2578
|
+
/** Connect to WebSocket server */
|
|
2579
|
+
connectSync() {
|
|
2580
|
+
this.themeSync?.connect();
|
|
2581
|
+
}
|
|
2582
|
+
/** Disconnect from WebSocket server */
|
|
2583
|
+
disconnectSync() {
|
|
2584
|
+
this.themeSync?.disconnect();
|
|
2585
|
+
}
|
|
2586
|
+
/** Register callback for sync connection */
|
|
2587
|
+
onSyncConnect(callback) {
|
|
2588
|
+
if (!this.themeSync) return () => {};
|
|
2589
|
+
return this.themeSync.onConnect(callback);
|
|
2590
|
+
}
|
|
2591
|
+
/** Register callback for sync disconnection */
|
|
2592
|
+
onSyncDisconnect(callback) {
|
|
2593
|
+
if (!this.themeSync) return () => {};
|
|
2594
|
+
return this.themeSync.onDisconnect(callback);
|
|
2595
|
+
}
|
|
2596
|
+
/** Register callback for sync errors */
|
|
2597
|
+
onSyncError(callback) {
|
|
2598
|
+
if (!this.themeSync) return () => {};
|
|
2599
|
+
return this.themeSync.onError(callback);
|
|
2600
|
+
}
|
|
2601
|
+
/** Register callback for theme updates from sync */
|
|
2602
|
+
onSyncThemeUpdate(callback) {
|
|
2603
|
+
if (!this.themeSync) return () => {};
|
|
2604
|
+
return this.themeSync.onThemeUpdate(callback);
|
|
2605
|
+
}
|
|
2606
|
+
/** Register callback for theme load events */
|
|
2607
|
+
onThemeLoad(callback) {
|
|
2608
|
+
return this.themeLoader.onLoad(callback);
|
|
2609
|
+
}
|
|
2610
|
+
/** Destroy instance and clean up */
|
|
2611
|
+
destroy() {
|
|
2612
|
+
this.darkMode.destroy();
|
|
2613
|
+
this.cssInjector.destroy();
|
|
2614
|
+
this.themeLoader.destroy();
|
|
2615
|
+
if (this.themeSync) {
|
|
2616
|
+
this.themeSync.destroy();
|
|
2617
|
+
this.themeSync = null;
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
};
|
|
2621
|
+
//#endregion
|
|
2622
|
+
//#region src/composables/useComboUX.ts
|
|
2623
|
+
/**
|
|
2624
|
+
* Vue composable for ComboUX
|
|
2625
|
+
*/
|
|
2626
|
+
let comboUXInstance = null;
|
|
2627
|
+
const isInitialized = ref(false);
|
|
2628
|
+
const isDark = ref(false);
|
|
2629
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
2630
|
+
function notifySubscribers() {
|
|
2631
|
+
subscribers.forEach((cb) => cb(isDark.value));
|
|
2632
|
+
}
|
|
2633
|
+
/**
|
|
2634
|
+
* Initialize ComboUX with options
|
|
2635
|
+
* Should be called once in your app entry point
|
|
2636
|
+
*/
|
|
2637
|
+
async function initComboUX(options) {
|
|
2638
|
+
if (comboUXInstance) {
|
|
2639
|
+
console.warn("[ComboUX] Already initialized, returning existing instance");
|
|
2640
|
+
return comboUXInstance;
|
|
2641
|
+
}
|
|
2642
|
+
comboUXInstance = new ComboUX(options);
|
|
2643
|
+
await comboUXInstance.init();
|
|
2644
|
+
isInitialized.value = true;
|
|
2645
|
+
isDark.value = comboUXInstance.isDark;
|
|
2646
|
+
comboUXInstance.onDarkModeChange((dark) => {
|
|
2647
|
+
isDark.value = dark;
|
|
2648
|
+
notifySubscribers();
|
|
2649
|
+
});
|
|
2650
|
+
return comboUXInstance;
|
|
2651
|
+
}
|
|
2652
|
+
/**
|
|
2653
|
+
* Get the current ComboUX instance
|
|
2654
|
+
*/
|
|
2655
|
+
function getComboUX() {
|
|
2656
|
+
return comboUXInstance;
|
|
2657
|
+
}
|
|
2658
|
+
/**
|
|
2659
|
+
* Vue composable to use ComboUX in components
|
|
2660
|
+
*/
|
|
2661
|
+
function useComboUX() {
|
|
2662
|
+
onMounted(() => {
|
|
2663
|
+
subscribers.add(() => {});
|
|
2664
|
+
});
|
|
2665
|
+
onUnmounted(() => {
|
|
2666
|
+
subscribers.delete(() => {});
|
|
2667
|
+
});
|
|
2668
|
+
return {
|
|
2669
|
+
isInitialized: readonly(isInitialized),
|
|
2670
|
+
isDark: readonly(isDark),
|
|
2671
|
+
instance: comboUXInstance,
|
|
2672
|
+
toggleDarkMode: () => comboUXInstance?.toggleDarkMode(),
|
|
2673
|
+
setDarkMode: (value) => comboUXInstance?.setDarkMode(value),
|
|
2674
|
+
updateTheme: (theme) => comboUXInstance?.updateTheme(theme)
|
|
2675
|
+
};
|
|
2676
|
+
}
|
|
2677
|
+
/**
|
|
2678
|
+
* Destroy the ComboUX instance
|
|
2679
|
+
*/
|
|
2680
|
+
function destroyComboUX() {
|
|
2681
|
+
if (comboUXInstance) {
|
|
2682
|
+
comboUXInstance.destroy();
|
|
2683
|
+
comboUXInstance = null;
|
|
2684
|
+
isInitialized.value = false;
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
//#endregion
|
|
2688
|
+
//#region src/index.ts
|
|
2689
|
+
const ComboUXPlugin = { async install(app, options) {
|
|
2690
|
+
if (options.autoInit !== false) await initComboUX(options);
|
|
2691
|
+
} };
|
|
2692
|
+
//#endregion
|
|
2693
|
+
export { ComboUX, ComboUXPlugin, ComboUXPlugin as default, destroyComboUX, getComboUX, initComboUX, useComboUX };
|