@shohojdhara/atomix 0.3.6 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +3 -3
  2. package/dist/atomix.css +77 -0
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +77 -0
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/charts.js +50 -142
  7. package/dist/charts.js.map +1 -1
  8. package/dist/core.d.ts +2 -2
  9. package/dist/core.js +179 -274
  10. package/dist/core.js.map +1 -1
  11. package/dist/forms.js +50 -142
  12. package/dist/forms.js.map +1 -1
  13. package/dist/heavy.js +179 -274
  14. package/dist/heavy.js.map +1 -1
  15. package/dist/index.d.ts +1255 -1226
  16. package/dist/index.esm.js +2806 -2958
  17. package/dist/index.esm.js.map +1 -1
  18. package/dist/index.js +3113 -3269
  19. package/dist/index.js.map +1 -1
  20. package/dist/index.min.js +1 -1
  21. package/dist/index.min.js.map +1 -1
  22. package/dist/theme.d.ts +313 -667
  23. package/dist/theme.js +1818 -2589
  24. package/dist/theme.js.map +1 -1
  25. package/package.json +1 -1
  26. package/src/components/AtomixGlass/AtomixGlass.tsx +128 -356
  27. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +1 -1
  28. package/src/components/Button/Button.tsx +85 -167
  29. package/src/components/DataTable/DataTable.stories.tsx +238 -0
  30. package/src/components/DataTable/DataTable.test.tsx +450 -0
  31. package/src/components/DataTable/DataTable.tsx +384 -61
  32. package/src/components/DatePicker/DatePicker.tsx +29 -38
  33. package/src/components/Upload/Upload.tsx +539 -40
  34. package/src/lib/composables/useAtomixGlass.ts +7 -7
  35. package/src/lib/composables/useDataTable.ts +355 -15
  36. package/src/lib/composables/useDatePicker.ts +19 -0
  37. package/src/lib/config/loader.ts +2 -3
  38. package/src/lib/constants/components.ts +17 -0
  39. package/src/lib/hooks/usePerformanceMonitor.ts +1 -1
  40. package/src/lib/theme/adapters/cssVariableMapper.ts +29 -14
  41. package/src/lib/theme/adapters/index.ts +1 -4
  42. package/src/lib/theme/config/configLoader.ts +82 -223
  43. package/src/lib/theme/config/loader.ts +15 -21
  44. package/src/lib/theme/constants/constants.ts +1 -1
  45. package/src/lib/theme/core/ThemeRegistry.ts +75 -279
  46. package/src/lib/theme/core/composeTheme.ts +30 -88
  47. package/src/lib/theme/core/createTheme.ts +88 -51
  48. package/src/lib/theme/core/createThemeObject.ts +2 -2
  49. package/src/lib/theme/core/index.ts +15 -2
  50. package/src/lib/theme/errors/errors.ts +1 -1
  51. package/src/lib/theme/generators/generateCSSNested.ts +131 -0
  52. package/src/lib/theme/generators/generateCSSVariables.ts +24 -16
  53. package/src/lib/theme/generators/index.ts +6 -0
  54. package/src/lib/theme/index.ts +45 -27
  55. package/src/lib/theme/runtime/ThemeApplicator.ts +6 -109
  56. package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +1 -1
  57. package/src/lib/theme/runtime/ThemeProvider.tsx +393 -544
  58. package/src/lib/theme/runtime/index.ts +1 -0
  59. package/src/lib/theme/runtime/useTheme.ts +1 -1
  60. package/src/lib/theme/runtime/useThemeTokens.ts +122 -0
  61. package/src/lib/theme/test/testTheme.ts +2 -1
  62. package/src/lib/theme/types.ts +14 -14
  63. package/src/lib/theme/utils/componentTheming.ts +140 -0
  64. package/src/lib/theme/utils/domUtils.ts +57 -15
  65. package/src/lib/theme/utils/injectCSS.ts +0 -1
  66. package/src/lib/theme/utils/naming.ts +100 -0
  67. package/src/lib/theme/utils/themeHelpers.ts +1 -39
  68. package/src/lib/theme/utils/themeUtils.ts +1 -170
  69. package/src/lib/types/components.ts +145 -0
  70. package/src/lib/utils/componentUtils.ts +1 -1
  71. package/src/lib/utils/dataTableExport.ts +143 -0
  72. package/src/lib/utils/memoryMonitor.ts +3 -3
  73. package/src/lib/utils/themeNaming.ts +135 -0
  74. package/src/styles/06-components/_components.data-table.scss +95 -0
package/dist/theme.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { loadAtomixConfig } from "../lib/config/loader";
2
+
1
3
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
4
 
3
5
  import { createContext, useRef, useEffect, useCallback, useMemo, useState, useContext, Component } from "react";
@@ -319,6 +321,14 @@ import { createContext, useRef, useEffect, useCallback, useMemo, useState, useCo
319
321
  };
320
322
  }
321
323
 
324
+ const tokens = Object.freeze( Object.defineProperty({
325
+ __proto__: null,
326
+ createTokens: createTokens,
327
+ defaultTokens: defaultTokens
328
+ }, Symbol.toStringTag, {
329
+ value: "Module"
330
+ }));
331
+
322
332
  /**
323
333
  * CSS Variable Generator
324
334
  *
@@ -375,1521 +385,842 @@ import { createContext, useRef, useEffect, useCallback, useMemo, useState, useCo
375
385
  });
376
386
  }
377
387
 
378
- var commonjsGlobal = "undefined" != typeof globalThis ? globalThis : "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof self ? self : {};
388
+ /**
389
+ * Theme System Error Handling
390
+ *
391
+ * Centralized error handling for the Atomix theme system.
392
+ * Provides custom error classes and logging utilities.
393
+ */
394
+ /**
395
+ * Theme error codes
396
+ */ var ThemeErrorCode, LogLevel;
379
397
 
380
- function getDefaultExportFromCjs(x) {
381
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x.default : x;
382
- }
398
+ !function(ThemeErrorCode) {
399
+ /** Theme not found in registry */
400
+ ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
401
+ /** Theme failed to load */
402
+ ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
403
+ /** Theme validation failed */
404
+ ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
405
+ /** Configuration loading failed */
406
+ ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
407
+ /** Configuration validation failed */
408
+ ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
409
+ /** Circular dependency detected */
410
+ ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
411
+ /** Missing dependency */
412
+ ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
413
+ /** Storage operation failed */
414
+ ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
415
+ /** Invalid theme name */
416
+ ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
417
+ /** CSS injection failed */
418
+ ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
419
+ /** Unknown error */
420
+ ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
421
+ }(ThemeErrorCode || (ThemeErrorCode = {}));
383
422
 
384
- var fails$9 = function(exec) {
385
- try {
386
- return !!exec();
387
- } catch (error) {
388
- return !0;
423
+ /**
424
+ * Custom error class for theme-related errors
425
+ */
426
+ class ThemeError extends Error {
427
+ constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
428
+ super(message), this.name = "ThemeError", this.code = code, this.context = context,
429
+ this.timestamp = Date.now(),
430
+ // Maintains proper stack trace for where our error was thrown (only available on V8)
431
+ Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
389
432
  }
390
- }, functionBindNative = !fails$9((function() {
391
- // eslint-disable-next-line es/no-function-prototype-bind -- safe
392
- var test = function() {/* empty */}.bind();
393
- // eslint-disable-next-line no-prototype-builtins -- safe
394
- return "function" != typeof test || test.hasOwnProperty("prototype");
395
- })), NATIVE_BIND$3 = functionBindNative, FunctionPrototype$1 = Function.prototype, call$5 = FunctionPrototype$1.call, uncurryThisWithBind = NATIVE_BIND$3 && FunctionPrototype$1.bind.bind(call$5, call$5), functionUncurryThis = NATIVE_BIND$3 ? uncurryThisWithBind : function(fn) {
396
- return function() {
397
- return call$5.apply(fn, arguments);
398
- };
399
- }, objectIsPrototypeOf = functionUncurryThis({}.isPrototypeOf), check = function(it) {
400
- return it && it.Math === Math && it;
401
- }, globalThis_1 =
402
- // eslint-disable-next-line es/no-global-this -- safe
403
- check("object" == typeof globalThis && globalThis) || check("object" == typeof window && window) ||
404
- // eslint-disable-next-line no-restricted-globals -- safe
405
- check("object" == typeof self && self) || check("object" == typeof commonjsGlobal && commonjsGlobal) || check("object" == typeof commonjsGlobal && commonjsGlobal) ||
406
- // eslint-disable-next-line no-new-func -- fallback
407
- function() {
408
- return this;
409
- }() || Function("return this")(), NATIVE_BIND$2 = functionBindNative, FunctionPrototype = Function.prototype, apply$1 = FunctionPrototype.apply, call$4 = FunctionPrototype.call, functionApply = "object" == typeof Reflect && Reflect.apply || (NATIVE_BIND$2 ? call$4.bind(apply$1) : function() {
410
- return call$4.apply(apply$1, arguments);
411
- }), uncurryThis$7 = functionUncurryThis, toString$3 = uncurryThis$7({}.toString), stringSlice = uncurryThis$7("".slice), classofRaw$2 = function(it) {
412
- return stringSlice(toString$3(it), 8, -1);
413
- }, classofRaw$1 = classofRaw$2, uncurryThis$6 = functionUncurryThis, functionUncurryThisClause = function(fn) {
414
- // Nashorn bug:
415
- // https://github.com/zloirock/core-js/issues/1128
416
- // https://github.com/zloirock/core-js/issues/1130
417
- if ("Function" === classofRaw$1(fn)) return uncurryThis$6(fn);
418
- }, documentAll = "object" == typeof document && document.all, isCallable$8 = void 0 === documentAll && void 0 !== documentAll ? function(argument) {
419
- return "function" == typeof argument || argument === documentAll;
420
- } : function(argument) {
421
- return "function" == typeof argument;
422
- }, objectGetOwnPropertyDescriptor = {}, descriptors = !fails$9((function() {
423
- // eslint-disable-next-line es/no-object-defineproperty -- required for testing
424
- return 7 !== Object.defineProperty({}, 1, {
425
- get: function() {
426
- return 7;
427
- }
428
- })[1];
429
- })), NATIVE_BIND$1 = functionBindNative, call$3 = Function.prototype.call, functionCall = NATIVE_BIND$1 ? call$3.bind(call$3) : function() {
430
- return call$3.apply(call$3, arguments);
431
- }, objectPropertyIsEnumerable = {}, $propertyIsEnumerable = {}.propertyIsEnumerable, getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor, NASHORN_BUG = getOwnPropertyDescriptor$1 && !$propertyIsEnumerable.call({
432
- 1: 2
433
- }, 1);
434
-
435
- // `Object.prototype.propertyIsEnumerable` method implementation
436
- // https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
437
- objectPropertyIsEnumerable.f = NASHORN_BUG ? function(V) {
438
- var descriptor = getOwnPropertyDescriptor$1(this, V);
439
- return !!descriptor && descriptor.enumerable;
440
- } : $propertyIsEnumerable;
441
-
442
- var match, version, createPropertyDescriptor$2 = function(bitmap, value) {
443
- return {
444
- enumerable: !(1 & bitmap),
445
- configurable: !(2 & bitmap),
446
- writable: !(4 & bitmap),
447
- value: value
448
- };
449
- }, fails$6 = fails$9, classof$4 = classofRaw$2, $Object$3 = Object, split = functionUncurryThis("".split), indexedObject = fails$6((function() {
450
- // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
451
- // eslint-disable-next-line no-prototype-builtins -- safe
452
- return !$Object$3("z").propertyIsEnumerable(0);
453
- })) ? function(it) {
454
- return "String" === classof$4(it) ? split(it, "") : $Object$3(it);
455
- } : $Object$3, isNullOrUndefined$2 = function(it) {
456
- return null == it;
457
- }, isNullOrUndefined$1 = isNullOrUndefined$2, $TypeError$7 = TypeError, requireObjectCoercible$3 = function(it) {
458
- if (isNullOrUndefined$1(it)) throw new $TypeError$7("Can't call method on " + it);
459
- return it;
460
- }, IndexedObject$1 = indexedObject, requireObjectCoercible$2 = requireObjectCoercible$3, toIndexedObject$2 = function(it) {
461
- return IndexedObject$1(requireObjectCoercible$2(it));
462
- }, isCallable$7 = isCallable$8, isObject$6 = function(it) {
463
- return "object" == typeof it ? null !== it : isCallable$7(it);
464
- }, path$3 = {}, path$2 = path$3, globalThis$b = globalThis_1, isCallable$6 = isCallable$8, aFunction = function(variable) {
465
- return isCallable$6(variable) ? variable : void 0;
466
- }, navigator$1 = globalThis_1.navigator, userAgent$2 = navigator$1 && navigator$1.userAgent, environmentUserAgent = userAgent$2 ? String(userAgent$2) : "", globalThis$9 = globalThis_1, userAgent$1 = environmentUserAgent, process$1 = globalThis$9.process, Deno$1 = globalThis$9.Deno, versions = process$1 && process$1.versions || Deno$1 && Deno$1.version, v8 = versions && versions.v8;
433
+ /**
434
+ * Convert error to JSON for logging
435
+ */ toJSON() {
436
+ return {
437
+ name: this.name,
438
+ message: this.message,
439
+ code: this.code,
440
+ context: this.context,
441
+ timestamp: this.timestamp,
442
+ stack: this.stack
443
+ };
444
+ }
445
+ }
467
446
 
468
- v8 && (
469
- // in old Chrome, versions of V8 isn't V8 = Chrome / 10
470
- // but their correct versions are not interesting for us
471
- version = (match = v8.split("."))[0] > 0 && match[0] < 4 ? 1 : +(match[0] + match[1])),
472
- // BrowserFS NodeJS `process` polyfill incorrectly set `.v8` to `0.0`
473
- // so check `userAgent` even if `.v8` exists, but 0
474
- !version && userAgent$1 && (!(match = userAgent$1.match(/Edge\/(\d+)/)) || match[1] >= 74) && (match = userAgent$1.match(/Chrome\/(\d+)/)) && (version = +match[1]);
447
+ /**
448
+ * Log level
449
+ */ !function(LogLevel) {
450
+ LogLevel[LogLevel.ERROR = 0] = "ERROR", LogLevel[LogLevel.WARN = 1] = "WARN", LogLevel[LogLevel.INFO = 2] = "INFO",
451
+ LogLevel[LogLevel.DEBUG = 3] = "DEBUG";
452
+ }(LogLevel || (LogLevel = {}));
475
453
 
476
- var environmentV8Version = version, V8_VERSION = environmentV8Version, fails$5 = fails$9, $String$3 = globalThis_1.String, symbolConstructorDetection = !!Object.getOwnPropertySymbols && !fails$5((function() {
477
- var symbol = Symbol("symbol detection");
478
- // Chrome 38 Symbol has incorrect toString conversion
479
- // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances
480
- // nb: Do not call `String` directly to avoid this being optimized out to `symbol+''` which will,
481
- // of course, fail.
482
- return !$String$3(symbol) || !(Object(symbol) instanceof Symbol) ||
483
- // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances
484
- !Symbol.sham && V8_VERSION && V8_VERSION < 41;
485
- })), useSymbolAsUid = symbolConstructorDetection && !Symbol.sham && "symbol" == typeof Symbol.iterator, isCallable$5 = isCallable$8, isPrototypeOf$2 = objectIsPrototypeOf, $Object$2 = Object, isSymbol$2 = useSymbolAsUid ? function(it) {
486
- return "symbol" == typeof it;
487
- } : function(it) {
488
- var $Symbol = function(namespace, method) {
489
- return arguments.length < 2 ? aFunction(path$2[namespace]) || aFunction(globalThis$b[namespace]) : path$2[namespace] && path$2[namespace][method] || globalThis$b[namespace] && globalThis$b[namespace][method];
490
- }("Symbol");
491
- return isCallable$5($Symbol) && isPrototypeOf$2($Symbol.prototype, $Object$2(it));
492
- }, $String$2 = String, isCallable$4 = isCallable$8, $TypeError$6 = TypeError, aCallable$3 = function(argument) {
493
- if (isCallable$4(argument)) return argument;
494
- throw new $TypeError$6(function(argument) {
495
- try {
496
- return $String$2(argument);
497
- } catch (error) {
498
- return "Object";
499
- }
500
- }(argument) + " is not a function");
501
- }, aCallable$2 = aCallable$3, isNullOrUndefined = isNullOrUndefined$2, call$2 = functionCall, isCallable$3 = isCallable$8, isObject$5 = isObject$6, $TypeError$5 = TypeError, sharedStore = {
502
- exports: {}
503
- }, globalThis$7 = globalThis_1, defineProperty = Object.defineProperty, globalThis$6 = globalThis_1, store$1 = sharedStore.exports = globalThis$6["__core-js_shared__"] || function(key, value) {
504
- try {
505
- defineProperty(globalThis$7, key, {
506
- value: value,
507
- configurable: !0,
508
- writable: !0
509
- });
510
- } catch (error) {
511
- globalThis$7[key] = value;
454
+ /**
455
+ * Theme Logger
456
+ *
457
+ * Centralized logging for the theme system.
458
+ * Replaces console statements with structured logging.
459
+ */
460
+ class ThemeLogger {
461
+ constructor(config = {}) {
462
+ this.config = {
463
+ level: config.level ?? ("undefined" != typeof process && "production" === process.env?.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
464
+ enableConsole: config.enableConsole ?? !0,
465
+ onError: config.onError,
466
+ onWarn: config.onWarn,
467
+ onInfo: config.onInfo,
468
+ onDebug: config.onDebug
469
+ };
512
470
  }
513
- return value;
514
- }("__core-js_shared__", {});
471
+ /**
472
+ * Log an error
473
+ */ error(message, error, context) {
474
+ if (this.config.level < LogLevel.ERROR) return;
475
+ const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
476
+ this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
477
+ error: errorObj,
478
+ context: {
479
+ ...context,
480
+ ...themeError.context
481
+ },
482
+ code: themeError.code
483
+ }), this.config.onError?.(themeError, context);
484
+ }
485
+ /**
486
+ * Log a warning
487
+ */ warn(message, context) {
488
+ this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
489
+ this.config.onWarn?.(message, context));
490
+ }
491
+ /**
492
+ * Log an info message
493
+ */ info(message, context) {
494
+ this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
495
+ this.config.onInfo?.(message, context));
496
+ }
497
+ /**
498
+ * Log a debug message
499
+ */ debug(message, context) {
500
+ this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
501
+ }
502
+ }
515
503
 
516
- /* eslint-disable es/no-symbol -- required for testing */ (store$1.versions || (store$1.versions = [])).push({
517
- version: "3.43.0",
518
- mode: "pure",
519
- copyright: "© 2014-2025 Denis Pushkarev (zloirock.ru)",
520
- license: "https://github.com/zloirock/core-js/blob/v3.43.0/LICENSE",
521
- source: "https://github.com/zloirock/core-js"
522
- });
504
+ /**
505
+ * Default logger instance
506
+ */ let defaultLogger = null;
523
507
 
524
- var key, value, store = sharedStore.exports, requireObjectCoercible$1 = requireObjectCoercible$3, $Object$1 = Object, toObject$2 = function(argument) {
525
- return $Object$1(requireObjectCoercible$1(argument));
526
- }, toObject$1 = toObject$2, hasOwnProperty = functionUncurryThis({}.hasOwnProperty), hasOwnProperty_1 = Object.hasOwn || function(it, key) {
527
- return hasOwnProperty(toObject$1(it), key);
528
- }, uncurryThis$3 = functionUncurryThis, id = 0, postfix = Math.random(), toString$2 = uncurryThis$3(1.1.toString), hasOwn$2 = hasOwnProperty_1, NATIVE_SYMBOL = symbolConstructorDetection, USE_SYMBOL_AS_UID = useSymbolAsUid, Symbol$1 = globalThis_1.Symbol, WellKnownSymbolsStore = store[key = "wks"] || (store[key] = value || {}), createWellKnownSymbol = USE_SYMBOL_AS_UID ? Symbol$1.for || Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || function(key) {
529
- return "Symbol(" + (void 0 === key ? "" : key) + ")_" + toString$2(++id + postfix, 36);
530
- }, wellKnownSymbol$5 = function(name) {
531
- return hasOwn$2(WellKnownSymbolsStore, name) || (WellKnownSymbolsStore[name] = NATIVE_SYMBOL && hasOwn$2(Symbol$1, name) ? Symbol$1[name] : createWellKnownSymbol("Symbol." + name)),
532
- WellKnownSymbolsStore[name];
533
- }, call$1 = functionCall, isObject$4 = isObject$6, isSymbol$1 = isSymbol$2, $TypeError$4 = TypeError, TO_PRIMITIVE = wellKnownSymbol$5("toPrimitive"), toPrimitive = function(input, pref) {
534
- if (!isObject$4(input) || isSymbol$1(input)) return input;
535
- var result, func, exoticToPrim = (func = input[TO_PRIMITIVE], isNullOrUndefined(func) ? void 0 : aCallable$2(func));
536
- if (exoticToPrim) {
537
- if (void 0 === pref && (pref = "default"), result = call$1(exoticToPrim, input, pref),
538
- !isObject$4(result) || isSymbol$1(result)) return result;
539
- throw new $TypeError$4("Can't convert object to primitive value");
540
- }
541
- return void 0 === pref && (pref = "number"), function(input, pref) {
542
- var fn, val;
543
- if ("string" === pref && isCallable$3(fn = input.toString) && !isObject$5(val = call$2(fn, input))) return val;
544
- if (isCallable$3(fn = input.valueOf) && !isObject$5(val = call$2(fn, input))) return val;
545
- if ("string" !== pref && isCallable$3(fn = input.toString) && !isObject$5(val = call$2(fn, input))) return val;
546
- throw new $TypeError$5("Can't convert object to primitive value");
547
- }(input, pref);
548
- }, isSymbol = isSymbol$2, toPropertyKey$2 = function(argument) {
549
- var key = toPrimitive(argument, "string");
550
- return isSymbol(key) ? key : key + "";
551
- }, isObject$3 = isObject$6, document$1 = globalThis_1.document, EXISTS = isObject$3(document$1) && isObject$3(document$1.createElement), ie8DomDefine = !descriptors && !fails$9((function() {
552
- // eslint-disable-next-line es/no-object-defineproperty -- required for testing
553
- return 7 !== Object.defineProperty((it = "div", EXISTS ? document$1.createElement(it) : {}), "a", {
554
- get: function() {
555
- return 7;
556
- }
557
- }).a;
558
- var it;
559
- })), DESCRIPTORS$3 = descriptors, call = functionCall, propertyIsEnumerableModule = objectPropertyIsEnumerable, createPropertyDescriptor$1 = createPropertyDescriptor$2, toIndexedObject$1 = toIndexedObject$2, toPropertyKey$1 = toPropertyKey$2, hasOwn$1 = hasOwnProperty_1, IE8_DOM_DEFINE$1 = ie8DomDefine, $getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor;
560
-
561
- // `Object.getOwnPropertyDescriptor` method
562
- // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
563
- objectGetOwnPropertyDescriptor.f = DESCRIPTORS$3 ? $getOwnPropertyDescriptor$1 : function(O, P) {
564
- if (O = toIndexedObject$1(O), P = toPropertyKey$1(P), IE8_DOM_DEFINE$1) try {
565
- return $getOwnPropertyDescriptor$1(O, P);
566
- } catch (error) {/* empty */}
567
- if (hasOwn$1(O, P)) return createPropertyDescriptor$1(!call(propertyIsEnumerableModule.f, O, P), O[P]);
568
- };
569
-
570
- var fails$3 = fails$9, isCallable$2 = isCallable$8, replacement = /#|\.prototype\./, isForced$1 = function(feature, detection) {
571
- var value = data[normalize(feature)];
572
- return value === POLYFILL || value !== NATIVE && (isCallable$2(detection) ? fails$3(detection) : !!detection);
573
- }, normalize = isForced$1.normalize = function(string) {
574
- return String(string).replace(replacement, ".").toLowerCase();
575
- }, data = isForced$1.data = {}, NATIVE = isForced$1.NATIVE = "N", POLYFILL = isForced$1.POLYFILL = "P", isForced_1 = isForced$1, aCallable$1 = aCallable$3, NATIVE_BIND = functionBindNative, bind$1 = functionUncurryThisClause(functionUncurryThisClause.bind), objectDefineProperty = {}, v8PrototypeDefineBug = descriptors && fails$9((function() {
576
- // eslint-disable-next-line es/no-object-defineproperty -- required for testing
577
- return 42 !== Object.defineProperty((function() {/* empty */}), "prototype", {
578
- value: 42,
579
- writable: !1
580
- }).prototype;
581
- })), isObject$2 = isObject$6, $String$1 = String, $TypeError$3 = TypeError, DESCRIPTORS$1 = descriptors, IE8_DOM_DEFINE = ie8DomDefine, V8_PROTOTYPE_DEFINE_BUG = v8PrototypeDefineBug, anObject = function(argument) {
582
- if (isObject$2(argument)) return argument;
583
- throw new $TypeError$3($String$1(argument) + " is not an object");
584
- }, toPropertyKey = toPropertyKey$2, $TypeError$2 = TypeError, $defineProperty = Object.defineProperty, $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
508
+ /**
509
+ * Get or create default logger
510
+ */ function getLogger() {
511
+ return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
512
+ }
585
513
 
586
- // `Object.defineProperty` method
587
- // https://tc39.es/ecma262/#sec-object.defineproperty
588
- objectDefineProperty.f = DESCRIPTORS$1 ? V8_PROTOTYPE_DEFINE_BUG ? function(O, P, Attributes) {
589
- if (anObject(O), P = toPropertyKey(P), anObject(Attributes), "function" == typeof O && "prototype" === P && "value" in Attributes && "writable" in Attributes && !Attributes.writable) {
590
- var current = $getOwnPropertyDescriptor(O, P);
591
- current && current.writable && (O[P] = Attributes.value, Attributes = {
592
- configurable: "configurable" in Attributes ? Attributes.configurable : current.configurable,
593
- enumerable: "enumerable" in Attributes ? Attributes.enumerable : current.enumerable,
594
- writable: !1
514
+ /**
515
+ * Core Theme Functions
516
+ *
517
+ * Simplified theme system using DesignTokens only.
518
+ * Config-first approach: loads from atomix.config.ts when no input is provided.
519
+ */
520
+ /**
521
+ * Create theme CSS from DesignTokens
522
+ *
523
+ * **Config-First Approach**: If no input is provided, loads from `atomix.config.ts`.
524
+ *
525
+ * @param input - DesignTokens (partial) or undefined (loads from config)
526
+ * @param options - CSS generation options (prefix is automatically read from config if not provided)
527
+ * @returns CSS string with custom properties
528
+ * @throws Error if config loading fails when no input is provided
529
+ *
530
+ * @example
531
+ * ```typescript
532
+ * // Loads from atomix.config.ts
533
+ * const css = createTheme();
534
+ *
535
+ * // Using DesignTokens
536
+ * const css = createTheme({
537
+ * 'primary': '#7c3aed',
538
+ * 'spacing-4': '1rem',
539
+ * });
540
+ *
541
+ * // With custom options
542
+ * const css = createTheme(undefined, { prefix: 'myapp', selector: ':root' });
543
+ * ```
544
+ */ function createTheme(input, options) {
545
+ // Validate options if provided
546
+ if (options?.prefix) {
547
+ const prefixPattern = /^[a-z][a-z0-9-]*$/;
548
+ if (!prefixPattern.test(options.prefix)) throw new ThemeError(`Invalid CSS variable prefix: "${options.prefix}". Prefix must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens (e.g., "atomix", "my-app").`, ThemeErrorCode.THEME_VALIDATION_FAILED, {
549
+ prefix: options.prefix,
550
+ pattern: prefixPattern.toString()
595
551
  });
596
552
  }
597
- return $defineProperty(O, P, Attributes);
598
- } : $defineProperty : function(O, P, Attributes) {
599
- if (anObject(O), P = toPropertyKey(P), anObject(Attributes), IE8_DOM_DEFINE) try {
600
- return $defineProperty(O, P, Attributes);
601
- } catch (error) {/* empty */}
602
- if ("get" in Attributes || "set" in Attributes) throw new $TypeError$2("Accessors not supported");
603
- return "value" in Attributes && (O[P] = Attributes.value), O;
604
- };
605
-
606
- var definePropertyModule = objectDefineProperty, createPropertyDescriptor = createPropertyDescriptor$2, createNonEnumerableProperty$1 = descriptors ? function(object, key, value) {
607
- return definePropertyModule.f(object, key, createPropertyDescriptor(1, value));
608
- } : function(object, key, value) {
609
- return object[key] = value, object;
610
- }, globalThis$3 = globalThis_1, apply = functionApply, uncurryThis$1 = functionUncurryThisClause, isCallable$1 = isCallable$8, getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f, isForced = isForced_1, path$1 = path$3, bind = function(fn, that) {
611
- return aCallable$1(fn), void 0 === that ? fn : NATIVE_BIND ? bind$1(fn, that) : function() {
612
- return fn.apply(that, arguments);
613
- };
614
- }, createNonEnumerableProperty = createNonEnumerableProperty$1, hasOwn = hasOwnProperty_1, wrapConstructor = function(NativeConstructor) {
615
- var Wrapper = function(a, b, c) {
616
- if (this instanceof Wrapper) {
617
- switch (arguments.length) {
618
- case 0:
619
- return new NativeConstructor;
620
-
621
- case 1:
622
- return new NativeConstructor(a);
623
-
624
- case 2:
625
- return new NativeConstructor(a, b);
626
- }
627
- return new NativeConstructor(a, b, c);
628
- }
629
- return apply(NativeConstructor, this, arguments);
630
- };
631
- return Wrapper.prototype = NativeConstructor.prototype, Wrapper;
632
- }, _export = function(options, source) {
633
- var FORCED, USE_NATIVE, VIRTUAL_PROTOTYPE, key, sourceProperty, targetProperty, nativeProperty, resultProperty, descriptor, TARGET = options.target, GLOBAL = options.global, STATIC = options.stat, PROTO = options.proto, nativeSource = GLOBAL ? globalThis$3 : STATIC ? globalThis$3[TARGET] : globalThis$3[TARGET] && globalThis$3[TARGET].prototype, target = GLOBAL ? path$1 : path$1[TARGET] || createNonEnumerableProperty(path$1, TARGET, {})[TARGET], targetPrototype = target.prototype;
634
- for (key in source)
635
- // contains in native
636
- USE_NATIVE = !(FORCED = isForced(GLOBAL ? key : TARGET + (STATIC ? "." : "#") + key, options.forced)) && nativeSource && hasOwn(nativeSource, key),
637
- targetProperty = target[key], USE_NATIVE && (nativeProperty = options.dontCallGetSet ? (descriptor = getOwnPropertyDescriptor(nativeSource, key)) && descriptor.value : nativeSource[key]),
638
- // export native or implementation
639
- sourceProperty = USE_NATIVE && nativeProperty ? nativeProperty : source[key], (FORCED || PROTO || typeof targetProperty != typeof sourceProperty) && (
640
- // bind methods to global for calling from export context
641
- resultProperty = options.bind && USE_NATIVE ? bind(sourceProperty, globalThis$3) : options.wrap && USE_NATIVE ? wrapConstructor(sourceProperty) : PROTO && isCallable$1(sourceProperty) ? uncurryThis$1(sourceProperty) : sourceProperty,
642
- // add a flag to not completely full polyfills
643
- (options.sham || sourceProperty && sourceProperty.sham || targetProperty && targetProperty.sham) && createNonEnumerableProperty(resultProperty, "sham", !0),
644
- createNonEnumerableProperty(target, key, resultProperty), PROTO && (hasOwn(path$1, VIRTUAL_PROTOTYPE = TARGET + "Prototype") || createNonEnumerableProperty(path$1, VIRTUAL_PROTOTYPE, {}),
645
- // export virtual prototype methods
646
- createNonEnumerableProperty(path$1[VIRTUAL_PROTOTYPE], key, sourceProperty),
647
- // export real prototype methods
648
- options.real && targetPrototype && (FORCED || !targetPrototype[key]) && createNonEnumerableProperty(targetPrototype, key, sourceProperty)));
649
- }, ceil = Math.ceil, floor = Math.floor, trunc = Math.trunc || function(x) {
650
- var n = +x;
651
- return (n > 0 ? floor : ceil)(n);
652
- }, toIntegerOrInfinity$2 = function(argument) {
653
- var number = +argument;
654
- // eslint-disable-next-line no-self-compare -- NaN check
655
- return number != number || 0 === number ? 0 : trunc(number);
656
- }, toIntegerOrInfinity$1 = toIntegerOrInfinity$2, max = Math.max, min$1 = Math.min, toIntegerOrInfinity = toIntegerOrInfinity$2, min = Math.min, lengthOfArrayLike$2 = function(obj) {
657
- return argument = obj.length, (len = toIntegerOrInfinity(argument)) > 0 ? min(len, 9007199254740991) : 0;
658
- var argument, len;
659
- }, toIndexedObject = toIndexedObject$2, lengthOfArrayLike$1 = lengthOfArrayLike$2, createMethod$1 = function(IS_INCLUDES) {
660
- return function($this, el, fromIndex) {
661
- var O = toIndexedObject($this), length = lengthOfArrayLike$1(O);
662
- if (0 === length) return !IS_INCLUDES && -1;
663
- var value, index = function(index, length) {
664
- var integer = toIntegerOrInfinity$1(index);
665
- return integer < 0 ? max(integer + length, 0) : min$1(integer, length);
666
- }(fromIndex, length);
667
- // Array#includes uses SameValueZero equality algorithm
668
- // eslint-disable-next-line no-self-compare -- NaN check
669
- if (IS_INCLUDES && el != el) {
670
- for (;length > index; )
671
- // eslint-disable-next-line no-self-compare -- NaN check
672
- if ((value = O[index++]) != value) return !0;
673
- // Array#indexOf ignores holes, Array#includes - not
674
- } else for (;length > index; index++) if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
675
- return !IS_INCLUDES && -1;
676
- };
677
- }, $includes = [ createMethod$1(!0), createMethod$1(!1) ][0];
678
-
679
- // `Array.prototype.includes` method
680
- // https://tc39.es/ecma262/#sec-array.prototype.includes
681
- _export({
682
- target: "Array",
683
- proto: !0,
684
- forced: fails$9((function() {
685
- // eslint-disable-next-line es/no-array-prototype-includes -- detection
686
- return !Array(1).includes();
687
- }))
688
- }, {
689
- includes: function(el /* , fromIndex = 0 */) {
690
- return $includes(this, el, arguments.length > 1 ? arguments[1] : void 0);
553
+ // Validate selector if provided
554
+ if (options?.selector && ("string" != typeof options.selector || 0 === options.selector.trim().length)) throw new ThemeError(`Invalid CSS selector: "${options.selector}". Selector must be a non-empty string (e.g., ":root", ".my-theme").`, ThemeErrorCode.THEME_VALIDATION_FAILED, {
555
+ selector: options.selector
556
+ });
557
+ // Determine tokens based on input
558
+ let tokens;
559
+ if (input) {
560
+ // Validate input tokens structure
561
+ if ("object" != typeof input || null === input || Array.isArray(input)) throw new ThemeError(`Invalid tokens input. Expected an object with DesignTokens, but received: ${typeof input}.`, ThemeErrorCode.THEME_VALIDATION_FAILED, {
562
+ inputType: typeof input
563
+ });
564
+ // Use DesignTokens directly
565
+ tokens = input;
691
566
  }
692
- });
693
-
694
- var globalThis$2 = globalThis_1, path = path$3, getBuiltInPrototypeMethod$3 = function(CONSTRUCTOR, METHOD) {
695
- var Namespace = path[CONSTRUCTOR + "Prototype"], pureMethod = Namespace && Namespace[METHOD];
696
- if (pureMethod) return pureMethod;
697
- var NativeConstructor = globalThis$2[CONSTRUCTOR], NativePrototype = NativeConstructor && NativeConstructor.prototype;
698
- return NativePrototype && NativePrototype[METHOD];
699
- }, includes$4 = getBuiltInPrototypeMethod$3("Array", "includes"), isObject$1 = isObject$6, classof$3 = classofRaw$2, MATCH$1 = wellKnownSymbol$5("match"), $TypeError$1 = TypeError, test = {};
700
-
701
- test[wellKnownSymbol$5("toStringTag")] = "z";
702
-
703
- var TO_STRING_TAG_SUPPORT = "[object z]" === String(test), isCallable = isCallable$8, classofRaw = classofRaw$2, TO_STRING_TAG = wellKnownSymbol$5("toStringTag"), $Object = Object, CORRECT_ARGUMENTS = "Arguments" === classofRaw(function() {
704
- return arguments;
705
- }()), classof$1 = TO_STRING_TAG_SUPPORT ? classofRaw : function(it) {
706
- var O, tag, result;
707
- return void 0 === it ? "Undefined" : null === it ? "Null" : "string" == typeof (tag = function(it, key) {
708
- try {
709
- return it[key];
710
- } catch (error) {/* empty */}
711
- }(O = $Object(it), TO_STRING_TAG)) ? tag : CORRECT_ARGUMENTS ? classofRaw(O) : "Object" === (result = classofRaw(O)) && isCallable(O.callee) ? "Arguments" : result;
712
- }, $String = String, MATCH = wellKnownSymbol$5("match"), $$1 = _export, notARegExp = function(it) {
713
- if (function(it) {
714
- var isRegExp;
715
- return isObject$1(it) && (void 0 !== (isRegExp = it[MATCH$1]) ? !!isRegExp : "RegExp" === classof$3(it));
716
- }(it)) throw new $TypeError$1("The method doesn't accept regular expressions");
717
- return it;
718
- }, requireObjectCoercible = requireObjectCoercible$3, toString = function(argument) {
719
- if ("Symbol" === classof$1(argument)) throw new TypeError("Cannot convert a Symbol value to a string");
720
- return $String(argument);
721
- }, stringIndexOf = functionUncurryThis("".indexOf);
722
-
723
- // `String.prototype.includes` method
724
- // https://tc39.es/ecma262/#sec-string.prototype.includes
725
- $$1({
726
- target: "String",
727
- proto: !0,
728
- forced: !function(METHOD_NAME) {
729
- var regexp = /./;
567
+ // Merge with defaults and generate CSS
568
+ else {
569
+ // Check if we're in a browser environment
570
+ if ("undefined" != typeof window) throw new ThemeError("No input provided and config loading is not available in browser environment. Please provide tokens explicitly or use Node.js/SSR environment.", ThemeErrorCode.CONFIG_LOAD_FAILED, {
571
+ environment: "browser"
572
+ });
573
+ // Load from config when no input provided
574
+ let loadThemeFromConfigSync, loadAtomixConfig;
730
575
  try {
731
- "/./"[METHOD_NAME](regexp);
732
- } catch (error1) {
733
- try {
734
- return regexp[MATCH] = !1, "/./"[METHOD_NAME](regexp);
735
- } catch (error2) {/* empty */}
576
+ const configLoaderModule = require("../config/configLoader"), loaderModule = require("../../config/loader");
577
+ // Get prefix from config if needed
578
+ if (loadThemeFromConfigSync = configLoaderModule.loadThemeFromConfigSync, loadAtomixConfig = loaderModule.loadAtomixConfig,
579
+ tokens = loadThemeFromConfigSync(), !options?.prefix) try {
580
+ const config = loadAtomixConfig({
581
+ configPath: "atomix.config.ts",
582
+ required: !1
583
+ });
584
+ options = {
585
+ ...options,
586
+ prefix: config?.prefix || "atomix"
587
+ };
588
+ } catch (error) {
589
+ // If config loading fails, use default prefix
590
+ options = {
591
+ ...options,
592
+ prefix: "atomix"
593
+ };
594
+ }
595
+ } catch (error) {
596
+ throw new ThemeError("No input provided and config loading is not available in this environment. Please provide tokens explicitly.", ThemeErrorCode.CONFIG_LOAD_FAILED, {
597
+ error: error instanceof Error ? error.message : String(error)
598
+ });
736
599
  }
737
- return !1;
738
- }("includes")
739
- }, {
740
- includes: function(searchString /* , position = 0 */) {
741
- return !!~stringIndexOf(toString(requireObjectCoercible(this)), toString(notARegExp(searchString)), arguments.length > 1 ? arguments[1] : void 0);
742
600
  }
743
- });
744
-
745
- var includes$3 = getBuiltInPrototypeMethod$3("String", "includes"), isPrototypeOf$1 = objectIsPrototypeOf, arrayMethod = includes$4, stringMethod = includes$3, ArrayPrototype$1 = Array.prototype, StringPrototype = String.prototype;
746
-
747
- const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
748
- var own = it.includes;
749
- return it === ArrayPrototype$1 || isPrototypeOf$1(ArrayPrototype$1, it) && own === ArrayPrototype$1.includes ? arrayMethod : "string" == typeof it || it === StringPrototype || isPrototypeOf$1(StringPrototype, it) && own === StringPrototype.includes ? stringMethod : own;
750
- }));
601
+ const allTokens = createTokens(tokens), prefix = options?.prefix ?? "atomix";
602
+ // Get prefix from options or use default
603
+ return generateCSSVariables$1(allTokens, {
604
+ ...options,
605
+ prefix: prefix
606
+ });
607
+ }
751
608
 
752
609
  /**
753
- * Theme Utilities
610
+ * Theme Composition Utilities
754
611
  *
755
- * Helper utilities for working with themes, including color manipulation,
756
- * spacing helpers, and theme value accessors.
612
+ * Simplified utilities for composing and merging DesignTokens.
757
613
  */
758
614
  // ============================================================================
759
- // Color Manipulation Utilities
615
+ // Deep Merge Utility
760
616
  // ============================================================================
761
617
  /**
762
- * Convert hex color to RGB object
763
- */ function hexToRgb(hex) {
764
- const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
765
- return result ? {
766
- r: parseInt(result[1], 16),
767
- g: parseInt(result[2], 16),
768
- b: parseInt(result[3], 16)
769
- } : null;
618
+ * Check if value is an object
619
+ */ function isObject$6(item) {
620
+ return item && "object" == typeof item && !Array.isArray(item) && "function" != typeof item;
770
621
  }
771
622
 
772
623
  /**
773
- * Convert RGB to hex color
774
- */ function rgbToHex(r, g, b) {
775
- const toHex = val => Math.round(Math.max(0, Math.min(255, val))).toString(16).padStart(2, "0");
776
- return `#${toHex(r ?? 0)}${toHex(g ?? 0)}${toHex(b ?? 0)}`;
624
+ * Deep merge multiple objects
625
+ * Later objects override earlier ones
626
+ */ function deepMerge(...objects) {
627
+ if (0 === objects.length) return {};
628
+ if (1 === objects.length) return objects[0];
629
+ const [target, ...sources] = objects, result = {
630
+ ...target
631
+ };
632
+ for (const source of sources) if (source) for (const key in source) {
633
+ if (!Object.prototype.hasOwnProperty.call(source, key)) continue;
634
+ const targetValue = result[key], sourceValue = source[key];
635
+ isObject$6(targetValue) && isObject$6(sourceValue) ?
636
+ // Recursively merge objects
637
+ result[key] = deepMerge(targetValue, sourceValue) :
638
+ // Override with source value
639
+ result[key] = sourceValue;
640
+ }
641
+ return result;
777
642
  }
778
643
 
779
644
  /**
780
- * Calculate relative luminance of a color
781
- * Used for determining contrast ratios
782
- */ function getLuminance(color) {
783
- const rgb = hexToRgb(color);
784
- if (!rgb) return 0;
785
- const {r: r, g: g, b: b} = rgb, [rs, gs, bs] = [ r ?? 0, g ?? 0, b ?? 0 ].map((c => {
786
- const val = c / 255;
787
- return val <= .03928 ? val / 12.92 : Math.pow((val + .055) / 1.055, 2.4);
788
- }));
789
- return .2126 * (rs ?? 0) + .7152 * (gs ?? 0) + .0722 * (bs ?? 0);
645
+ * Merge multiple DesignTokens objects into a single DesignTokens object
646
+ *
647
+ * @param tokens - DesignTokens objects to merge
648
+ * @returns Merged DesignTokens object
649
+ *
650
+ * @example
651
+ * ```typescript
652
+ * const baseTokens = { 'primary': '#000', 'spacing-4': '1rem' };
653
+ * const customTokens = { 'secondary': '#fff', 'spacing-4': '1.5rem' };
654
+ * const merged = mergeTheme(baseTokens, customTokens);
655
+ * // Returns: { 'primary': '#000', 'secondary': '#fff', 'spacing-4': '1.5rem' }
656
+ * ```
657
+ */ function mergeTheme(...tokens) {
658
+ return deepMerge({}, ...tokens);
790
659
  }
791
660
 
792
661
  /**
793
- * Calculate contrast ratio between two colors
794
- */ function getContrastRatio(foreground, background) {
795
- const lumA = getLuminance(foreground), lumB = getLuminance(background);
796
- return (Math.max(lumA, lumB) + .05) / (Math.min(lumA, lumB) + .05);
662
+ * Extend DesignTokens with additional tokens
663
+ *
664
+ * @param baseTokens - Base DesignTokens to extend
665
+ * @param extension - Additional DesignTokens to merge
666
+ * @returns Extended DesignTokens object
667
+ *
668
+ * @example
669
+ * ```typescript
670
+ * const base = { 'primary': '#000' };
671
+ * const extended = extendTheme(base, { 'secondary': '#fff' });
672
+ * // Returns: { 'primary': '#000', 'secondary': '#fff' }
673
+ * ```
674
+ */ function extendTheme(baseTokens, extension) {
675
+ return mergeTheme(baseTokens, extension);
797
676
  }
798
677
 
799
678
  /**
800
- * Get appropriate contrast text color (black or white) for a background color
801
- */ function getContrastText(background, threshold = 3) {
802
- const contrastWithWhite = getContrastRatio("#FFFFFF", background), contrastWithBlack = getContrastRatio("#000000", background);
803
- return contrastWithWhite >= threshold ? "#FFFFFF" : contrastWithBlack >= threshold ? "#000000" : contrastWithWhite > contrastWithBlack ? "#FFFFFF" : "#000000";
679
+ * Create a new theme registry
680
+ */ function createThemeRegistry() {
681
+ return {};
804
682
  }
805
683
 
806
684
  /**
807
- * Lighten a color by a given amount
808
- *
809
- * @param color - Hex color string
810
- * @param amount - Amount to lighten (0-1), default 0.2
811
- * @returns Lightened hex color
812
- */ function lighten(color, amount = .2) {
813
- const rgb = hexToRgb(color);
814
- if (!rgb) return color;
815
- const {r: r, g: g, b: b} = rgb, lightenValue = val => Math.min(255, Math.round(val + (255 - val) * amount));
816
- return rgbToHex(lightenValue(r), lightenValue(g), lightenValue(b));
685
+ * Register a theme
686
+ * @param registry - Theme registry object
687
+ * @param id - Theme identifier
688
+ * @param metadata - Theme metadata
689
+ */ function registerTheme(registry, id, metadata) {
690
+ registry[id] = metadata;
817
691
  }
818
692
 
819
693
  /**
820
- * Darken a color by a given amount
821
- *
822
- * @param color - Hex color string
823
- * @param amount - Amount to darken (0-1), default 0.2
824
- * @returns Darkened hex color
825
- */ function darken(color, amount = .2) {
826
- const rgb = hexToRgb(color);
827
- if (!rgb) return color;
828
- const {r: r, g: g, b: b} = rgb, darkenValue = val => Math.max(0, Math.round(val * (1 - amount)));
829
- return rgbToHex(darkenValue(r), darkenValue(g), darkenValue(b));
694
+ * Unregister a theme
695
+ * @param registry - Theme registry object
696
+ * @param id - Theme identifier
697
+ */ function unregisterTheme(registry, id) {
698
+ const exists = id in registry;
699
+ return delete registry[id], exists;
830
700
  }
831
701
 
832
702
  /**
833
- * Add alpha (opacity) to a color
834
- *
835
- * @param color - Hex color string
836
- * @param opacity - Opacity value (0-1)
837
- * @returns RGBA color string
838
- */ function alpha(color, opacity) {
839
- const rgb = hexToRgb(color);
840
- if (!rgb) return color;
841
- const {r: r, g: g, b: b} = rgb;
842
- return `rgba(${r}, ${g}, ${b}, ${Math.max(0, Math.min(1, opacity))})`;
703
+ * Check if a theme is registered
704
+ * @param registry - Theme registry object
705
+ * @param id - Theme identifier
706
+ */ function hasTheme(registry, id) {
707
+ return id in registry;
843
708
  }
844
709
 
845
710
  /**
846
- * Emphasize a color (lighten if dark, darken if light)
847
- *
848
- * @param color - Hex color string
849
- * @param coefficient - Amount to emphasize (0-1), default 0.15
850
- * @returns Emphasized hex color
851
- */
852
- /**
853
- * Check if a theme is a JS theme (created with createTheme)
854
- */
855
- function isJSTheme(theme) {
856
- return theme && "object" == typeof theme && !0 === theme.__isJSTheme;
711
+ * Get theme metadata
712
+ * @param registry - Theme registry object
713
+ * @param id - Theme identifier
714
+ */ function getTheme(registry, id) {
715
+ return registry[id];
857
716
  }
858
717
 
859
718
  /**
860
- * Theme Adapter
861
- *
862
- * Converts between Theme objects and DesignTokens.
863
- */
719
+ * Get all registered theme metadata
720
+ * @param registry - Theme registry object
721
+ */ function getAllThemes(registry) {
722
+ return Object.values(registry);
723
+ }
724
+
864
725
  /**
865
- * Convert Theme object to DesignTokens
866
- *
867
- * Extracts values from a Theme object and converts them to flat DesignTokens format.
868
- *
869
- * @param theme - Theme object to convert
870
- * @returns Partial DesignTokens object
871
- *
872
- * @example
873
- * ```typescript
874
- * const theme = createTheme({ palette: { primary: { main: '#7c3aed' } } });
875
- * const tokens = themeToDesignTokens(theme);
876
- * // Returns: { 'primary': '#7c3aed', ... }
877
- * ```
878
- */ function themeToDesignTokens(theme) {
879
- const tokens = {};
880
- // Convert palette colors
881
- if (theme.palette) {
882
- // Primary colors
883
- if (theme.palette.primary && (tokens.primary = theme.palette.primary.main, theme.palette.primary.light && (tokens["primary-3"] = theme.palette.primary.light),
884
- theme.palette.primary.dark && (tokens["primary-9"] = theme.palette.primary.dark),
885
- theme.palette.primary.main)) {
886
- const rgb = hexToRgb(theme.palette.primary.main);
887
- rgb && (tokens["primary-rgb"] = `${rgb.r}, ${rgb.g}, ${rgb.b}`);
888
- }
889
- // Secondary colors
890
- if (theme.palette.secondary) {
891
- tokens.secondary = theme.palette.secondary.main, theme.palette.secondary.light && (tokens["gray-1"] = theme.palette.secondary.light),
892
- theme.palette.secondary.dark && (tokens["gray-3"] = theme.palette.secondary.dark);
893
- const rgb = hexToRgb(theme.palette.secondary.main);
894
- rgb && (tokens["secondary-rgb"] = `${rgb.r}, ${rgb.g}, ${rgb.b}`);
895
- }
896
- // Error colors
897
- if (theme.palette.error) {
898
- tokens.error = theme.palette.error.main, tokens["red-6"] = theme.palette.error.main,
899
- theme.palette.error.light && (tokens["red-4"] = theme.palette.error.light), theme.palette.error.dark && (tokens["red-9"] = theme.palette.error.dark);
900
- const rgb = hexToRgb(theme.palette.error.main);
901
- rgb && (tokens["error-rgb"] = `${rgb.r}, ${rgb.g}, ${rgb.b}`);
902
- }
903
- // Success colors
904
- if (theme.palette.success) {
905
- tokens.success = theme.palette.success.main, tokens["green-6"] = theme.palette.success.main,
906
- theme.palette.success.light && (tokens["green-4"] = theme.palette.success.light),
907
- theme.palette.success.dark && (tokens["green-9"] = theme.palette.success.dark);
908
- const rgb = hexToRgb(theme.palette.success.main);
909
- rgb && (tokens["success-rgb"] = `${rgb.r}, ${rgb.g}, ${rgb.b}`);
910
- }
911
- // Warning colors
912
- if (theme.palette.warning) {
913
- tokens.warning = theme.palette.warning.main, tokens["yellow-6"] = theme.palette.warning.main,
914
- theme.palette.warning.light && (tokens["yellow-4"] = theme.palette.warning.light),
915
- theme.palette.warning.dark && (tokens["yellow-9"] = theme.palette.warning.dark);
916
- const rgb = hexToRgb(theme.palette.warning.main);
917
- rgb && (tokens["warning-rgb"] = `${rgb.r}, ${rgb.g}, ${rgb.b}`);
918
- }
919
- // Info colors
920
- if (theme.palette.info) {
921
- tokens.info = theme.palette.info.main, tokens["blue-6"] = theme.palette.info.main,
922
- theme.palette.info.light && (tokens["blue-4"] = theme.palette.info.light), theme.palette.info.dark && (tokens["blue-9"] = theme.palette.info.dark);
923
- const rgb = hexToRgb(theme.palette.info.main);
924
- rgb && (tokens["info-rgb"] = `${rgb.r}, ${rgb.g}, ${rgb.b}`);
925
- }
926
- // Background colors
927
- theme.palette.background && (tokens["body-bg"] = theme.palette.background.default,
928
- tokens["primary-bg-subtle"] = theme.palette.background.default, tokens["secondary-bg-subtle"] = theme.palette.background.paper,
929
- tokens["tertiary-bg-subtle"] = theme.palette.background.subtle),
930
- // Text colors
931
- theme.palette.text && (tokens["body-color"] = theme.palette.text.primary, tokens["heading-color"] = theme.palette.text.primary,
932
- tokens["primary-text-emphasis"] = theme.palette.text.primary, tokens["secondary-text-emphasis"] = theme.palette.text.secondary,
933
- tokens["disabled-text-emphasis"] = theme.palette.text.disabled);
934
- }
935
- // Convert typography
936
- // Convert spacing (if available as object)
937
- if (theme.typography && (tokens["body-font-family"] = theme.typography.fontFamily,
938
- tokens["font-sans-serif"] = theme.typography.fontFamily, tokens["body-font-size"] = `${theme.typography.fontSize}px`,
939
- tokens["body-font-weight"] = String(theme.typography.fontWeightRegular),
940
- // Font weights
941
- tokens["font-weight-light"] = String(theme.typography.fontWeightLight), tokens["font-weight-normal"] = String(theme.typography.fontWeightRegular),
942
- tokens["font-weight-medium"] = String(theme.typography.fontWeightMedium), tokens["font-weight-semibold"] = String(theme.typography.fontWeightSemiBold),
943
- tokens["font-weight-bold"] = String(theme.typography.fontWeightBold),
944
- // Line heights
945
- theme.typography.h1?.lineHeight && (tokens["line-height-base"] = String(theme.typography.h1.lineHeight))),
946
- theme.spacing && "object" == typeof theme.spacing && !("__isSpacingFunction" in theme.spacing)) {
947
- const spacing = theme.spacing;
948
- Object.entries(spacing).forEach((([key, value]) => {
949
- tokens[`spacing-${key}`] = String(value);
950
- }));
951
- }
952
- // Convert border radius
953
- return theme.borderRadius && Object.entries(theme.borderRadius).forEach((([key, value]) => {
954
- tokens["sm" === key ? "border-radius-sm" : "md" === key ? "border-radius" : "lg" === key ? "border-radius-lg" : "xl" === key ? "border-radius-xl" : "xxl" === key ? "border-radius-xxl" : `border-radius-${key}`] = String(value);
955
- })),
956
- // Convert shadows
957
- theme.shadows && Object.entries(theme.shadows).forEach((([key, value]) => {
958
- tokens["xs" === key ? "box-shadow-xs" : "sm" === key ? "box-shadow-sm" : "md" === key ? "box-shadow" : "lg" === key ? "box-shadow-lg" : "xl" === key ? "box-shadow-xl" : `box-shadow-${key}`] = String(value);
959
- })),
960
- // Convert z-index
961
- theme.zIndex && Object.entries(theme.zIndex).forEach((([key, value]) => {
962
- tokens[`z-${key}`] = String(value);
963
- })),
964
- // Convert transitions
965
- theme.transitions && (theme.transitions.duration && Object.entries(theme.transitions.duration).forEach((([key, value]) => {
966
- tokens[`transition-duration-${key}`] = String(value);
967
- })), theme.transitions.easing && Object.entries(theme.transitions.easing).forEach((([key, value]) => {
968
- tokens[`easing-${key}`] = String(value);
969
- }))),
970
- // Convert breakpoints
971
- theme.breakpoints?.values && Object.entries(theme.breakpoints.values).forEach((([key, value]) => {
972
- tokens[`breakpoint-${key}`] = String(value);
973
- })),
974
- // Merge any existing cssVars from theme
975
- theme.cssVars && Object.entries(theme.cssVars).forEach((([key, value]) => {
976
- // Remove --atomix- prefix if present
977
- const cleanKey = key.replace(/^--atomix-/, "").replace(/^--/, "");
978
- tokens[cleanKey] = String(value);
979
- })), tokens;
726
+ * Get all registered theme IDs
727
+ * @param registry - Theme registry object
728
+ */ function getThemeIds(registry) {
729
+ return Object.keys(registry);
980
730
  }
981
731
 
982
732
  /**
983
- * Convert DesignTokens to Theme-compatible CSS variables
984
- *
985
- * @param tokens - DesignTokens object
986
- * @returns CSS variables object compatible with Theme.cssVars
987
- */ function designTokensToCSSVars(tokens) {
988
- const cssVars = {};
989
- return Object.entries(tokens).forEach((([key, value]) => {
990
- void 0 !== value && (cssVars[`--atomix-${key}`] = String(value));
991
- })), cssVars;
733
+ * Clear all registered themes
734
+ * @param registry - Theme registry object
735
+ */ function clearThemes(registry) {
736
+ Object.keys(registry).forEach((key => delete registry[key]));
992
737
  }
993
738
 
994
739
  /**
995
- * Create DesignTokens from Theme with defaults
996
- *
997
- * Converts a Theme to DesignTokens and merges with default tokens.
998
- *
999
- * @param theme - Theme object to convert
1000
- * @returns Complete DesignTokens object
1001
- */ function createDesignTokensFromTheme(theme) {
1002
- return createTokens(themeToDesignTokens(theme));
740
+ * Get the number of registered themes
741
+ * @param registry - Theme registry object
742
+ */ function getThemeCount(registry) {
743
+ return Object.keys(registry).length;
1003
744
  }
1004
745
 
1005
746
  /**
1006
- * Create a minimal Theme object from DesignTokens
747
+ * Core Theme Engine
1007
748
  *
1008
- * @param tokens - DesignTokens to convert
1009
- * @returns Minimal Theme object with cssVars populated
1010
- */ function designTokensToTheme(tokens) {
1011
- return {
1012
- name: "Design Tokens Theme",
1013
- cssVars: designTokensToCSSVars(tokens),
1014
- __isJSTheme: !0
1015
- };
1016
- }
749
+ * Core theme creation, composition, and registry functionality
750
+ */ const index = Object.freeze( Object.defineProperty({
751
+ __proto__: null,
752
+ clearThemes: clearThemes,
753
+ createTheme: createTheme,
754
+ createThemeRegistry: createThemeRegistry,
755
+ deepMerge: deepMerge,
756
+ extendTheme: extendTheme,
757
+ getAllThemes: getAllThemes,
758
+ getTheme: getTheme,
759
+ getThemeCount: getThemeCount,
760
+ getThemeIds: getThemeIds,
761
+ hasTheme: hasTheme,
762
+ mergeTheme: mergeTheme,
763
+ registerTheme: registerTheme,
764
+ unregisterTheme: unregisterTheme
765
+ }, Symbol.toStringTag, {
766
+ value: "Module"
767
+ }));
1017
768
 
1018
769
  /**
1019
- * Config Loader
770
+ * CSS Injection Utilities
1020
771
  *
1021
- * Load design tokens from atomix.config.ts and convert to flat token format.
772
+ * Inject CSS into HTML head via <style> element.
1022
773
  */
1023
774
  /**
1024
- * Convert nested config tokens to flat DesignTokens format
1025
- *
1026
- * Handles conversion from atomix.config.ts structure to flat tokens.
1027
- * Maps config structure to actual DesignTokens key names.
1028
- */ function flattenConfigTokens(tokens, prefix = "atomix") {
1029
- const flat = {};
1030
- // Colors
1031
- return tokens.colors && Object.entries(tokens.colors).forEach((([key, value]) => {
1032
- var _context;
1033
- // Simple color: 'primary': '#7AFFD7'
1034
- // Map directly to DesignTokens keys (e.g., 'primary', 'secondary', 'error')
1035
- // Only map if it's a valid semantic color key
1036
- if ("string" == typeof value) _includesInstanceProperty(_context = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ]).call(_context, key) && (flat[key] = value); else if (value && "object" == typeof value)
1037
- // Color scale or palette
1038
- if ("main" in value) {
1039
- var _context2;
1040
- // PaletteColorOptions: { main: '#7AFFD7', light?: '#...', dark?: '#...' }
1041
- const palette = value, baseKey = key;
1042
- // Map main to base color (e.g., primary, secondary, error)
1043
- _includesInstanceProperty(_context2 = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ]).call(_context2, key) && (flat[baseKey] = palette.main,
1044
- // Map light/dark to appropriate scale values
1045
- // light typically maps to step 3, dark to step 9
1046
- palette.light && (flat[`${key}-3`] = palette.light), palette.dark && (flat[`${key}-9`] = palette.dark));
1047
- } else
1048
- // Color scale: { 1: '#fff', 2: '#eee', ..., 6: '#main', ... }
1049
- // Or full scale: { 1: '#...', 2: '#...', ..., 10: '#...' }
1050
- Object.entries(value).forEach((([scaleKey, scaleValue]) => {
1051
- if ("string" == typeof scaleValue)
1052
- // Map scale keys to DesignTokens format
1053
- if ("main" === scaleKey || "6" === scaleKey) {
1054
- var _context3, _context4;
1055
- // Main color maps to base key (e.g., 'primary')
1056
- _includesInstanceProperty(_context3 = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ]).call(_context3, key) && (flat[key] = scaleValue),
1057
- // Also map to step 6 if it's a scale color
1058
- _includesInstanceProperty(_context4 = [ "primary", "red", "green", "blue", "yellow", "gray" ]).call(_context4, key) && (flat[`${key}-6`] = scaleValue);
1059
- } else {
1060
- // Map scale numbers (1-10) to DesignTokens format
1061
- const scaleNum = parseInt(scaleKey, 10);
1062
- !isNaN(scaleNum) && scaleNum >= 1 && scaleNum <= 10 && (flat[`${key}-${scaleKey}`] = scaleValue);
1063
- }
1064
- }));
1065
- })),
1066
- // Spacing
1067
- tokens.spacing && Object.entries(tokens.spacing).forEach((([key, value]) => {
1068
- flat[`spacing-${key}`] = String(value);
1069
- })),
1070
- // Border Radius
1071
- tokens.borderRadius && Object.entries(tokens.borderRadius).forEach((([key, value]) => {
1072
- // Map to DesignTokens format
1073
- "sm" === key || "base" === key || "" === key ? flat["border-radius-sm"] = String(value) : "md" === key || "default" === key ? flat["border-radius"] = String(value) : "lg" === key ? flat["border-radius-lg"] = String(value) : flat[`border-radius-${key}`] = String(value);
1074
- })),
1075
- // Typography
1076
- tokens.typography && (
1077
- // Font Families
1078
- tokens.typography.fontFamilies && Object.entries(tokens.typography.fontFamilies).forEach((([key, value]) => {
1079
- // Map to DesignTokens format
1080
- "sans" === key || "base" === key ? (flat["font-sans-serif"] = String(value), flat["body-font-family"] = String(value)) : "mono" === key ? flat["font-monospace"] = String(value) : flat[`font-family-${key}`] = String(value);
1081
- })),
1082
- // Font Sizes
1083
- tokens.typography.fontSizes && Object.entries(tokens.typography.fontSizes).forEach((([key, value]) => {
1084
- flat[`font-size-${key}`] = String(value);
1085
- })),
1086
- // Font Weights
1087
- tokens.typography.fontWeights && Object.entries(tokens.typography.fontWeights).forEach((([key, value]) => {
1088
- flat[`font-weight-${key}`] = String(value);
1089
- })),
1090
- // Line Heights
1091
- tokens.typography.lineHeights && Object.entries(tokens.typography.lineHeights).forEach((([key, value]) => {
1092
- "base" === key || "default" === key ? flat["line-height-base"] = String(value) : flat[`line-height-${key}`] = String(value);
1093
- }))),
1094
- // Shadows
1095
- tokens.shadows && Object.entries(tokens.shadows).forEach((([key, value]) => {
1096
- flat[`shadow-${key}`] = String(value);
1097
- })),
1098
- // Z-Index
1099
- tokens.zIndex && Object.entries(tokens.zIndex).forEach((([key, value]) => {
1100
- flat[`z-index-${key}`] = String(value);
1101
- })),
1102
- // Transitions
1103
- tokens.transitions && tokens.transitions.durations && Object.entries(tokens.transitions.durations).forEach((([key, value]) => {
1104
- flat[`transition-${key}`] = String(value);
1105
- })), flat;
775
+ * Check if running in browser environment
776
+ */ function isBrowser$1() {
777
+ return "undefined" != typeof document;
1106
778
  }
1107
779
 
1108
780
  /**
1109
- * Load theme tokens from atomix.config.ts
781
+ * Inject CSS into HTML head via <style> element
1110
782
  *
1111
- * Loads atomix.config.ts and extracts theme tokens.
1112
- * Config file is required - throws error if not found.
783
+ * Creates or updates a style element in the document head.
784
+ * If an element with the same ID exists, it will be updated.
1113
785
  *
1114
- * @param configPath - Optional custom config path (default: 'atomix.config.ts')
1115
- * @returns Partial DesignTokens from config
1116
- * @throws Error if config file is not found or cannot be loaded
786
+ * @param css - CSS string to inject
787
+ * @param id - Style element ID (default: 'atomix-theme')
1117
788
  *
1118
789
  * @example
1119
790
  * ```typescript
1120
- * const tokens = await loadThemeFromConfig();
1121
- * const css = createTheme(tokens);
1122
- * injectTheme(css);
791
+ * const css = ':root { --atomix-color-primary: #7AFFD7; }';
792
+ * injectCSS(css);
793
+ *
794
+ * // With custom ID
795
+ * injectCSS(css, 'my-custom-theme');
1123
796
  * ```
1124
- */ async function loadThemeFromConfig(configPath = "atomix.config.ts") {
1125
- // In browser environments, config loading is not supported
1126
- if ("undefined" != typeof window) throw new Error("loadThemeFromConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.");
1127
- // Load config using the existing loader (required)
1128
- const {loadAtomixConfig: loadAtomixConfig} = await Promise.resolve().then((() => loader)), config = loadAtomixConfig({
1129
- configPath: configPath,
1130
- required: !0
1131
- });
1132
- if (!config || !config.theme) throw new Error(`Config file ${configPath} does not contain theme configuration.`);
1133
- // Extract tokens from config
1134
- const tokens = config.theme.tokens || config.theme.extend || {};
1135
- if (0 === Object.keys(tokens).length) throw new Error(`Config file ${configPath} has empty theme configuration.`);
1136
- // Convert nested structure to flat tokens
1137
- return flattenConfigTokens(tokens, config.prefix || "atomix");
797
+ */ function injectCSS$1(css, id = "atomix-theme") {
798
+ if (!isBrowser$1()) return;
799
+ let styleElement = document.getElementById(id);
800
+ styleElement || (styleElement = document.createElement("style"), styleElement.id = id,
801
+ styleElement.setAttribute("data-atomix-theme", "true"), document.head.appendChild(styleElement)),
802
+ styleElement.textContent = css;
1138
803
  }
1139
804
 
1140
805
  /**
1141
- * Load theme tokens from atomix.config.ts (synchronous version)
806
+ * Remove injected CSS from DOM
807
+ *
808
+ * Removes the style element with the given ID from the document head.
1142
809
  *
1143
- * Synchronous version that uses require() instead of dynamic import.
1144
- * Only works in Node.js environment.
1145
- * Config file is required - throws error if not found.
810
+ * @param id - Style element ID to remove (default: 'atomix-theme')
1146
811
  *
1147
- * @param configPath - Optional custom config path
1148
- * @returns Partial DesignTokens from config
1149
- * @throws Error if config file is not found or cannot be loaded
1150
- */ function loadThemeFromConfigSync(configPath = "atomix.config.ts") {
1151
- // In browser environments, config loading is not supported
1152
- if ("undefined" != typeof window) throw new Error("loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.");
1153
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1154
- const {loadAtomixConfig: loadAtomixConfig} = require("../../config/loader"), config = loadAtomixConfig({
1155
- configPath: configPath,
1156
- required: !0
1157
- });
1158
- if (!config || !config.theme) throw new Error(`Config file ${configPath} does not contain theme configuration.`);
1159
- // Extract tokens from config
1160
- const tokens = config.theme.tokens || config.theme.extend || {};
1161
- if (0 === Object.keys(tokens).length) throw new Error(`Config file ${configPath} has empty theme configuration.`);
1162
- // Convert nested structure to flat tokens
1163
- return flattenConfigTokens(tokens, config.prefix || "atomix");
812
+ * @example
813
+ * ```typescript
814
+ * removeCSS(); // Removes default 'atomix-theme'
815
+ * removeCSS('my-custom-theme'); // Removes custom ID
816
+ * ```
817
+ */ function removeCSS(id = "atomix-theme") {
818
+ if (!isBrowser$1()) return;
819
+ const styleElement = document.getElementById(id);
820
+ styleElement && styleElement.remove();
1164
821
  }
1165
822
 
1166
823
  /**
1167
- * Core Theme Functions
824
+ * Check if CSS is already injected
1168
825
  *
1169
- * Unified theme system that handles both DesignTokens and Theme objects.
1170
- * Config-first approach: loads from atomix.config.ts when no input is provided.
1171
- * Config file is required for automatic loading.
826
+ * @param id - Style element ID to check (default: 'atomix-theme')
827
+ * @returns True if style element exists
828
+ */ function isCSSInjected(id = "atomix-theme") {
829
+ return !!isBrowser$1() && null !== document.getElementById(id);
830
+ }
831
+
832
+ /**
833
+ * CSS File Utilities
834
+ *
835
+ * Save CSS to file system (Node.js only).
1172
836
  */
1173
837
  /**
1174
- * Create theme CSS from tokens or Theme object
838
+ * Save CSS to file
1175
839
  *
1176
- * **Config-First Approach**: If no input is provided, loads from `atomix.config.ts`.
1177
- * Config file is required for automatic loading.
840
+ * Writes CSS string to a file. Only works in Node.js environment.
1178
841
  *
1179
- * @param input - DesignTokens (partial), Theme object, or undefined (loads from config)
1180
- * @param options - CSS generation options (prefix is automatically read from config if not provided)
1181
- * @returns CSS string with custom properties
1182
- * @throws Error if config loading fails when no input is provided
842
+ * @param css - CSS string to save
843
+ * @param filePath - Output file path
844
+ * @throws Error if called in browser environment
1183
845
  *
1184
846
  * @example
1185
847
  * ```typescript
1186
- * // Loads from atomix.config.ts (config file required)
1187
- * const css = createTheme();
1188
- *
1189
- * // Using DesignTokens
1190
- * const css = createTheme({
1191
- * 'primary': '#7c3aed',
1192
- * 'spacing-4': '1rem',
1193
- * });
1194
- *
1195
- * // Using Theme object
1196
- * const theme = createThemeObject({ palette: { primary: { main: '#7c3aed' } } });
1197
- * const css = createTheme(theme);
1198
- *
1199
- * // With custom options
1200
- * const css = createTheme(undefined, { prefix: 'myapp', selector: ':root' });
848
+ * const css = ':root { --atomix-color-primary: #7AFFD7; }';
849
+ * await saveCSSFile(css, './themes/custom.css');
1201
850
  * ```
1202
- */ function createTheme(input, options) {
1203
- let tokens, configPrefix;
1204
- // If no input provided, load from config (required)
1205
- if (input)
1206
- // Convert Theme to DesignTokens
1207
- tokens = !0 === input.__isJSTheme || input.palette && input.typography ? themeToDesignTokens(input) : input; else {
1208
- const configTokens = loadThemeFromConfigSync();
1209
- // Get prefix from config
1210
- try {
1211
- // eslint-disable-next-line @typescript-eslint/no-require-imports
1212
- const {loadAtomixConfig: loadAtomixConfig} = require("../../config/loader"), config = loadAtomixConfig({
1213
- configPath: "atomix.config.ts",
1214
- required: !0
1215
- });
1216
- configPrefix = config?.prefix;
1217
- } catch (error) {
1218
- // Prefix loading failed, but tokens were loaded, so continue
1219
- }
1220
- tokens = configTokens;
1221
- }
1222
- // Merge with defaults and generate CSS
1223
- return generateCSSVariables$1(createTokens(tokens), {
1224
- ...options,
1225
- prefix: options?.prefix ?? configPrefix ?? "atomix"
1226
- });
851
+ */ var commonjsGlobal = "undefined" != typeof globalThis ? globalThis : "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof self ? self : {};
852
+
853
+ function getDefaultExportFromCjs(x) {
854
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x.default : x;
1227
855
  }
1228
856
 
1229
- var aCallable = aCallable$3, toObject = toObject$2, IndexedObject = indexedObject, lengthOfArrayLike = lengthOfArrayLike$2, $TypeError = TypeError, REDUCE_EMPTY = "Reduce of empty array with no initial value", createMethod = function(IS_RIGHT) {
1230
- return function(that, callbackfn, argumentsLength, memo) {
1231
- var O = toObject(that), self = IndexedObject(O), length = lengthOfArrayLike(O);
1232
- if (aCallable(callbackfn), 0 === length && argumentsLength < 2) throw new $TypeError(REDUCE_EMPTY);
1233
- var index = IS_RIGHT ? length - 1 : 0, i = IS_RIGHT ? -1 : 1;
1234
- if (argumentsLength < 2) for (;;) {
1235
- if (index in self) {
1236
- memo = self[index], index += i;
1237
- break;
1238
- }
1239
- if (index += i, IS_RIGHT ? index < 0 : length <= index) throw new $TypeError(REDUCE_EMPTY);
1240
- }
1241
- for (;IS_RIGHT ? index >= 0 : length > index; index += i) index in self && (memo = callbackfn(memo, self[index], index, O));
1242
- return memo;
1243
- };
1244
- }, arrayReduce = {
1245
- // `Array.prototype.reduce` method
1246
- // https://tc39.es/ecma262/#sec-array.prototype.reduce
1247
- left: createMethod(!1),
1248
- // `Array.prototype.reduceRight` method
1249
- // https://tc39.es/ecma262/#sec-array.prototype.reduceright
1250
- right: createMethod(!0)
1251
- }, fails = fails$9, globalThis$1 = globalThis_1, userAgent = environmentUserAgent, classof = classofRaw$2, userAgentStartsWith = function(string) {
1252
- return userAgent.slice(0, string.length) === string;
1253
- }, environment = userAgentStartsWith("Bun/") ? "BUN" : userAgentStartsWith("Cloudflare-Workers") ? "CLOUDFLARE" : userAgentStartsWith("Deno/") ? "DENO" : userAgentStartsWith("Node.js/") ? "NODE" : globalThis$1.Bun && "string" == typeof Bun.version ? "BUN" : globalThis$1.Deno && "object" == typeof Deno.version ? "DENO" : "process" === classof(globalThis$1.process) ? "NODE" : globalThis$1.window && globalThis$1.document ? "BROWSER" : "REST", $reduce = arrayReduce.left;
1254
-
1255
- // `Array.prototype.reduce` method
1256
- // https://tc39.es/ecma262/#sec-array.prototype.reduce
1257
- _export({
1258
- target: "Array",
1259
- proto: !0,
1260
- forced: !("NODE" === environment) && environmentV8Version > 79 && environmentV8Version < 83 || !function(METHOD_NAME, argument) {
1261
- var method = [][METHOD_NAME];
1262
- return !!method && fails((function() {
1263
- // eslint-disable-next-line no-useless-call -- required for testing
1264
- method.call(null, argument || function() {
1265
- return 1;
1266
- }, 1);
1267
- }));
1268
- }("reduce")
1269
- }, {
1270
- reduce: function(callbackfn /* , initialValue */) {
1271
- var length = arguments.length;
1272
- return $reduce(this, callbackfn, length, length > 1 ? arguments[1] : void 0);
857
+ var fails$9 = function(exec) {
858
+ try {
859
+ return !!exec();
860
+ } catch (error) {
861
+ return !0;
1273
862
  }
1274
- });
863
+ }, functionBindNative = !fails$9((function() {
864
+ // eslint-disable-next-line es/no-function-prototype-bind -- safe
865
+ var test = function() {/* empty */}.bind();
866
+ // eslint-disable-next-line no-prototype-builtins -- safe
867
+ return "function" != typeof test || test.hasOwnProperty("prototype");
868
+ })), NATIVE_BIND$3 = functionBindNative, FunctionPrototype$1 = Function.prototype, call$5 = FunctionPrototype$1.call, uncurryThisWithBind = NATIVE_BIND$3 && FunctionPrototype$1.bind.bind(call$5, call$5), functionUncurryThis = NATIVE_BIND$3 ? uncurryThisWithBind : function(fn) {
869
+ return function() {
870
+ return call$5.apply(fn, arguments);
871
+ };
872
+ }, objectIsPrototypeOf = functionUncurryThis({}.isPrototypeOf), check = function(it) {
873
+ return it && it.Math === Math && it;
874
+ }, globalThis_1 =
875
+ // eslint-disable-next-line es/no-global-this -- safe
876
+ check("object" == typeof globalThis && globalThis) || check("object" == typeof window && window) ||
877
+ // eslint-disable-next-line no-restricted-globals -- safe
878
+ check("object" == typeof self && self) || check("object" == typeof commonjsGlobal && commonjsGlobal) || check("object" == typeof commonjsGlobal && commonjsGlobal) ||
879
+ // eslint-disable-next-line no-new-func -- fallback
880
+ function() {
881
+ return this;
882
+ }() || Function("return this")(), NATIVE_BIND$2 = functionBindNative, FunctionPrototype = Function.prototype, apply$1 = FunctionPrototype.apply, call$4 = FunctionPrototype.call, functionApply = "object" == typeof Reflect && Reflect.apply || (NATIVE_BIND$2 ? call$4.bind(apply$1) : function() {
883
+ return call$4.apply(apply$1, arguments);
884
+ }), uncurryThis$7 = functionUncurryThis, toString$3 = uncurryThis$7({}.toString), stringSlice = uncurryThis$7("".slice), classofRaw$2 = function(it) {
885
+ return stringSlice(toString$3(it), 8, -1);
886
+ }, classofRaw$1 = classofRaw$2, uncurryThis$6 = functionUncurryThis, functionUncurryThisClause = function(fn) {
887
+ // Nashorn bug:
888
+ // https://github.com/zloirock/core-js/issues/1128
889
+ // https://github.com/zloirock/core-js/issues/1130
890
+ if ("Function" === classofRaw$1(fn)) return uncurryThis$6(fn);
891
+ }, documentAll = "object" == typeof document && document.all, isCallable$8 = void 0 === documentAll && void 0 !== documentAll ? function(argument) {
892
+ return "function" == typeof argument || argument === documentAll;
893
+ } : function(argument) {
894
+ return "function" == typeof argument;
895
+ }, objectGetOwnPropertyDescriptor = {}, descriptors = !fails$9((function() {
896
+ // eslint-disable-next-line es/no-object-defineproperty -- required for testing
897
+ return 7 !== Object.defineProperty({}, 1, {
898
+ get: function() {
899
+ return 7;
900
+ }
901
+ })[1];
902
+ })), NATIVE_BIND$1 = functionBindNative, call$3 = Function.prototype.call, functionCall = NATIVE_BIND$1 ? call$3.bind(call$3) : function() {
903
+ return call$3.apply(call$3, arguments);
904
+ }, objectPropertyIsEnumerable = {}, $propertyIsEnumerable = {}.propertyIsEnumerable, getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor, NASHORN_BUG = getOwnPropertyDescriptor$1 && !$propertyIsEnumerable.call({
905
+ 1: 2
906
+ }, 1);
1275
907
 
1276
- var reduce$3 = getBuiltInPrototypeMethod$3("Array", "reduce"), isPrototypeOf = objectIsPrototypeOf, method = reduce$3, ArrayPrototype = Array.prototype;
908
+ // `Object.prototype.propertyIsEnumerable` method implementation
909
+ // https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
910
+ objectPropertyIsEnumerable.f = NASHORN_BUG ? function(V) {
911
+ var descriptor = getOwnPropertyDescriptor$1(this, V);
912
+ return !!descriptor && descriptor.enumerable;
913
+ } : $propertyIsEnumerable;
1277
914
 
1278
- const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
1279
- var own = it.reduce;
1280
- return it === ArrayPrototype || isPrototypeOf(ArrayPrototype, it) && own === ArrayPrototype.reduce ? method : own;
1281
- }));
915
+ var match, version, createPropertyDescriptor$2 = function(bitmap, value) {
916
+ return {
917
+ enumerable: !(1 & bitmap),
918
+ configurable: !(2 & bitmap),
919
+ writable: !(4 & bitmap),
920
+ value: value
921
+ };
922
+ }, fails$6 = fails$9, classof$4 = classofRaw$2, $Object$3 = Object, split = functionUncurryThis("".split), indexedObject = fails$6((function() {
923
+ // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
924
+ // eslint-disable-next-line no-prototype-builtins -- safe
925
+ return !$Object$3("z").propertyIsEnumerable(0);
926
+ })) ? function(it) {
927
+ return "String" === classof$4(it) ? split(it, "") : $Object$3(it);
928
+ } : $Object$3, isNullOrUndefined$2 = function(it) {
929
+ return null == it;
930
+ }, isNullOrUndefined$1 = isNullOrUndefined$2, $TypeError$7 = TypeError, requireObjectCoercible$3 = function(it) {
931
+ if (isNullOrUndefined$1(it)) throw new $TypeError$7("Can't call method on " + it);
932
+ return it;
933
+ }, IndexedObject$1 = indexedObject, requireObjectCoercible$2 = requireObjectCoercible$3, toIndexedObject$2 = function(it) {
934
+ return IndexedObject$1(requireObjectCoercible$2(it));
935
+ }, isCallable$7 = isCallable$8, isObject$5 = function(it) {
936
+ return "object" == typeof it ? null !== it : isCallable$7(it);
937
+ }, path$3 = {}, path$2 = path$3, globalThis$b = globalThis_1, isCallable$6 = isCallable$8, aFunction = function(variable) {
938
+ return isCallable$6(variable) ? variable : void 0;
939
+ }, navigator$1 = globalThis_1.navigator, userAgent$2 = navigator$1 && navigator$1.userAgent, environmentUserAgent = userAgent$2 ? String(userAgent$2) : "", globalThis$9 = globalThis_1, userAgent$1 = environmentUserAgent, process$1 = globalThis$9.process, Deno$1 = globalThis$9.Deno, versions = process$1 && process$1.versions || Deno$1 && Deno$1.version, v8 = versions && versions.v8;
1282
940
 
1283
- /**
1284
- * Theme Composition Utilities
1285
- *
1286
- * Utilities for composing, merging, and extending themes.
1287
- */
1288
- // ============================================================================
1289
- // Deep Merge Utility
1290
- // ============================================================================
1291
- /**
1292
- * Check if value is an object
1293
- */ function isObject(item) {
1294
- return item && "object" == typeof item && !Array.isArray(item) && "function" != typeof item;
1295
- }
941
+ v8 && (
942
+ // in old Chrome, versions of V8 isn't V8 = Chrome / 10
943
+ // but their correct versions are not interesting for us
944
+ version = (match = v8.split("."))[0] > 0 && match[0] < 4 ? 1 : +(match[0] + match[1])),
945
+ // BrowserFS NodeJS `process` polyfill incorrectly set `.v8` to `0.0`
946
+ // so check `userAgent` even if `.v8` exists, but 0
947
+ !version && userAgent$1 && (!(match = userAgent$1.match(/Edge\/(\d+)/)) || match[1] >= 74) && (match = userAgent$1.match(/Chrome\/(\d+)/)) && (version = +match[1]);
1296
948
 
1297
- /**
1298
- * Deep merge multiple objects
1299
- * Later objects override earlier ones
1300
- */ function deepMerge(...objects) {
1301
- if (0 === objects.length) return {};
1302
- if (1 === objects.length) return objects[0];
1303
- const [target, ...sources] = objects, result = {
1304
- ...target
1305
- };
1306
- for (const source of sources) if (source) for (const key in source) {
1307
- if (!Object.prototype.hasOwnProperty.call(source, key)) continue;
1308
- const targetValue = result[key], sourceValue = source[key];
1309
- isObject(targetValue) && isObject(sourceValue) ?
1310
- // Recursively merge objects
1311
- result[key] = deepMerge(targetValue, sourceValue) :
1312
- // Override with source value
1313
- result[key] = sourceValue;
949
+ var environmentV8Version = version, V8_VERSION = environmentV8Version, fails$5 = fails$9, $String$3 = globalThis_1.String, symbolConstructorDetection = !!Object.getOwnPropertySymbols && !fails$5((function() {
950
+ var symbol = Symbol("symbol detection");
951
+ // Chrome 38 Symbol has incorrect toString conversion
952
+ // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances
953
+ // nb: Do not call `String` directly to avoid this being optimized out to `symbol+''` which will,
954
+ // of course, fail.
955
+ return !$String$3(symbol) || !(Object(symbol) instanceof Symbol) ||
956
+ // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances
957
+ !Symbol.sham && V8_VERSION && V8_VERSION < 41;
958
+ })), useSymbolAsUid = symbolConstructorDetection && !Symbol.sham && "symbol" == typeof Symbol.iterator, isCallable$5 = isCallable$8, isPrototypeOf$2 = objectIsPrototypeOf, $Object$2 = Object, isSymbol$2 = useSymbolAsUid ? function(it) {
959
+ return "symbol" == typeof it;
960
+ } : function(it) {
961
+ var $Symbol = function(namespace, method) {
962
+ return arguments.length < 2 ? aFunction(path$2[namespace]) || aFunction(globalThis$b[namespace]) : path$2[namespace] && path$2[namespace][method] || globalThis$b[namespace] && globalThis$b[namespace][method];
963
+ }("Symbol");
964
+ return isCallable$5($Symbol) && isPrototypeOf$2($Symbol.prototype, $Object$2(it));
965
+ }, $String$2 = String, isCallable$4 = isCallable$8, $TypeError$6 = TypeError, aCallable$3 = function(argument) {
966
+ if (isCallable$4(argument)) return argument;
967
+ throw new $TypeError$6(function(argument) {
968
+ try {
969
+ return $String$2(argument);
970
+ } catch (error) {
971
+ return "Object";
972
+ }
973
+ }(argument) + " is not a function");
974
+ }, aCallable$2 = aCallable$3, isNullOrUndefined = isNullOrUndefined$2, call$2 = functionCall, isCallable$3 = isCallable$8, isObject$4 = isObject$5, $TypeError$5 = TypeError, sharedStore = {
975
+ exports: {}
976
+ }, globalThis$7 = globalThis_1, defineProperty = Object.defineProperty, globalThis$6 = globalThis_1, store$1 = sharedStore.exports = globalThis$6["__core-js_shared__"] || function(key, value) {
977
+ try {
978
+ defineProperty(globalThis$7, key, {
979
+ value: value,
980
+ configurable: !0,
981
+ writable: !0
982
+ });
983
+ } catch (error) {
984
+ globalThis$7[key] = value;
1314
985
  }
1315
- return result;
1316
- }
986
+ return value;
987
+ }("__core-js_shared__", {});
1317
988
 
1318
- // ============================================================================
1319
- // Theme Merging
1320
- // ============================================================================
1321
- /**
1322
- * Merge multiple theme options into a single theme options object
1323
- *
1324
- * @param themes - Theme options to merge
1325
- * @returns Merged theme options
1326
- *
1327
- * @example
1328
- * ```typescript
1329
- * const baseTheme = { palette: { primary: { main: '#000' } } };
1330
- * const customTheme = { palette: { secondary: { main: '#fff' } } };
1331
- * const merged = mergeTheme(baseTheme, customTheme);
1332
- * ```
1333
- */ function mergeTheme(...themes) {
1334
- return deepMerge({}, ...themes);
1335
- }
989
+ /* eslint-disable es/no-symbol -- required for testing */ (store$1.versions || (store$1.versions = [])).push({
990
+ version: "3.43.0",
991
+ mode: "pure",
992
+ copyright: "© 2014-2025 Denis Pushkarev (zloirock.ru)",
993
+ license: "https://github.com/zloirock/core-js/blob/v3.43.0/LICENSE",
994
+ source: "https://github.com/zloirock/core-js"
995
+ });
1336
996
 
1337
- /**
1338
- * Extend an existing theme with new options
1339
- *
1340
- * @param baseTheme - Base theme to extend (can be Theme or ThemeOptions)
1341
- * @param extension - Theme options to extend with
1342
- * @returns New theme with extended options
1343
- *
1344
- * @example
1345
- * ```typescript
1346
- * const base = createTheme({ palette: { primary: { main: '#000' } } });
1347
- * const extended = extendTheme(base, {
1348
- * palette: { secondary: { main: '#fff' } }
1349
- * });
1350
- * ```
1351
- */ function extendTheme(baseTheme, extension) {
1352
- /**
1353
- * Extract theme options from a complete Theme object
1354
- */
1355
- var theme;
1356
- // ============================================================================
1357
- // Default Theme Values
1358
- // ============================================================================
1359
- return createThemeObject(mergeTheme(baseTheme.__isJSTheme ? {
1360
- name: (theme = baseTheme).name,
1361
- class: theme.class,
1362
- description: theme.description,
1363
- author: theme.author,
1364
- version: theme.version,
1365
- tags: theme.tags,
1366
- supportsDarkMode: theme.supportsDarkMode,
1367
- status: theme.status,
1368
- a11y: theme.a11y,
1369
- color: theme.color,
1370
- features: theme.features,
1371
- dependencies: theme.dependencies,
1372
- palette: {
1373
- primary: theme.palette.primary,
1374
- secondary: theme.palette.secondary,
1375
- error: theme.palette.error,
1376
- warning: theme.palette.warning,
1377
- info: theme.palette.info,
1378
- success: theme.palette.success,
1379
- background: theme.palette.background,
1380
- text: theme.palette.text
1381
- },
1382
- typography: {
1383
- fontFamily: theme.typography.fontFamily,
1384
- fontSize: theme.typography.fontSize,
1385
- fontWeightLight: theme.typography.fontWeightLight,
1386
- fontWeightRegular: theme.typography.fontWeightRegular,
1387
- fontWeightMedium: theme.typography.fontWeightMedium,
1388
- fontWeightSemiBold: theme.typography.fontWeightSemiBold,
1389
- fontWeightBold: theme.typography.fontWeightBold,
1390
- h1: theme.typography.h1,
1391
- h2: theme.typography.h2,
1392
- h3: theme.typography.h3,
1393
- h4: theme.typography.h4,
1394
- h5: theme.typography.h5,
1395
- h6: theme.typography.h6,
1396
- body1: theme.typography.body1,
1397
- body2: theme.typography.body2
1398
- },
1399
- shadows: theme.shadows,
1400
- transitions: theme.transitions,
1401
- zIndex: theme.zIndex,
1402
- custom: theme.custom
1403
- } : baseTheme, extension));
1404
- }
997
+ var key, value, store = sharedStore.exports, requireObjectCoercible$1 = requireObjectCoercible$3, $Object$1 = Object, toObject$2 = function(argument) {
998
+ return $Object$1(requireObjectCoercible$1(argument));
999
+ }, toObject$1 = toObject$2, hasOwnProperty = functionUncurryThis({}.hasOwnProperty), hasOwnProperty_1 = Object.hasOwn || function(it, key) {
1000
+ return hasOwnProperty(toObject$1(it), key);
1001
+ }, uncurryThis$3 = functionUncurryThis, id = 0, postfix = Math.random(), toString$2 = uncurryThis$3(1.1.toString), hasOwn$2 = hasOwnProperty_1, NATIVE_SYMBOL = symbolConstructorDetection, USE_SYMBOL_AS_UID = useSymbolAsUid, Symbol$1 = globalThis_1.Symbol, WellKnownSymbolsStore = store[key = "wks"] || (store[key] = value || {}), createWellKnownSymbol = USE_SYMBOL_AS_UID ? Symbol$1.for || Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || function(key) {
1002
+ return "Symbol(" + (void 0 === key ? "" : key) + ")_" + toString$2(++id + postfix, 36);
1003
+ }, wellKnownSymbol$5 = function(name) {
1004
+ return hasOwn$2(WellKnownSymbolsStore, name) || (WellKnownSymbolsStore[name] = NATIVE_SYMBOL && hasOwn$2(Symbol$1, name) ? Symbol$1[name] : createWellKnownSymbol("Symbol." + name)),
1005
+ WellKnownSymbolsStore[name];
1006
+ }, call$1 = functionCall, isObject$3 = isObject$5, isSymbol$1 = isSymbol$2, $TypeError$4 = TypeError, TO_PRIMITIVE = wellKnownSymbol$5("toPrimitive"), toPrimitive = function(input, pref) {
1007
+ if (!isObject$3(input) || isSymbol$1(input)) return input;
1008
+ var result, func, exoticToPrim = (func = input[TO_PRIMITIVE], isNullOrUndefined(func) ? void 0 : aCallable$2(func));
1009
+ if (exoticToPrim) {
1010
+ if (void 0 === pref && (pref = "default"), result = call$1(exoticToPrim, input, pref),
1011
+ !isObject$3(result) || isSymbol$1(result)) return result;
1012
+ throw new $TypeError$4("Can't convert object to primitive value");
1013
+ }
1014
+ return void 0 === pref && (pref = "number"), function(input, pref) {
1015
+ var fn, val;
1016
+ if ("string" === pref && isCallable$3(fn = input.toString) && !isObject$4(val = call$2(fn, input))) return val;
1017
+ if (isCallable$3(fn = input.valueOf) && !isObject$4(val = call$2(fn, input))) return val;
1018
+ if ("string" !== pref && isCallable$3(fn = input.toString) && !isObject$4(val = call$2(fn, input))) return val;
1019
+ throw new $TypeError$5("Can't convert object to primitive value");
1020
+ }(input, pref);
1021
+ }, isSymbol = isSymbol$2, toPropertyKey$2 = function(argument) {
1022
+ var key = toPrimitive(argument, "string");
1023
+ return isSymbol(key) ? key : key + "";
1024
+ }, isObject$2 = isObject$5, document$1 = globalThis_1.document, EXISTS = isObject$2(document$1) && isObject$2(document$1.createElement), ie8DomDefine = !descriptors && !fails$9((function() {
1025
+ // eslint-disable-next-line es/no-object-defineproperty -- required for testing
1026
+ return 7 !== Object.defineProperty((it = "div", EXISTS ? document$1.createElement(it) : {}), "a", {
1027
+ get: function() {
1028
+ return 7;
1029
+ }
1030
+ }).a;
1031
+ var it;
1032
+ })), DESCRIPTORS$3 = descriptors, call = functionCall, propertyIsEnumerableModule = objectPropertyIsEnumerable, createPropertyDescriptor$1 = createPropertyDescriptor$2, toIndexedObject$1 = toIndexedObject$2, toPropertyKey$1 = toPropertyKey$2, hasOwn$1 = hasOwnProperty_1, IE8_DOM_DEFINE$1 = ie8DomDefine, $getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor;
1405
1033
 
1406
- const DEFAULT_PALETTE = {
1407
- primary: {
1408
- main: "#7c3aed",
1409
- // Primary-6
1410
- light: "#d0b2f5",
1411
- // Primary-3
1412
- dark: "#3c1583",
1413
- // Primary-9
1414
- contrastText: "#ffffff"
1415
- },
1416
- secondary: {
1417
- main: "#f3f4f6",
1418
- // Gray-2
1419
- light: "#ffffff",
1420
- // Gray-1
1421
- dark: "#e5e7eb",
1422
- // Gray-3
1423
- contrastText: "#1f2937"
1424
- },
1425
- error: {
1426
- main: "#ef4444",
1427
- // Red-6
1428
- light: "#fca5a5",
1429
- // Red-4
1430
- dark: "#991b1b",
1431
- // Red-9
1432
- contrastText: "#ffffff"
1433
- },
1434
- warning: {
1435
- main: "#eab308",
1436
- // Yellow-6
1437
- light: "#fde047",
1438
- // Yellow-4
1439
- dark: "#854d0e",
1440
- // Yellow-9
1441
- contrastText: "#000000"
1442
- },
1443
- info: {
1444
- main: "#3b82f6",
1445
- // Blue-6
1446
- light: "#93c5fd",
1447
- // Blue-4
1448
- dark: "#1e40af",
1449
- // Blue-9
1450
- contrastText: "#ffffff"
1451
- },
1452
- success: {
1453
- main: "#22c55e",
1454
- // Green-6
1455
- light: "#86efac",
1456
- // Green-4
1457
- dark: "#166534",
1458
- // Green-9
1459
- contrastText: "#ffffff"
1460
- },
1461
- background: {
1462
- default: "#ffffff",
1463
- // Primary-bg
1464
- paper: "#f3f4f6",
1465
- // Secondary-bg
1466
- subtle: "#d1d5db"
1467
- },
1468
- text: {
1469
- primary: "#111827",
1470
- // Gray-10
1471
- secondary: "#374151",
1472
- // Gray-8
1473
- disabled: "#9ca3af"
1474
- }
1475
- }, DEFAULT_TYPOGRAPHY = {
1476
- fontFamily: '"Roboto", "Helvetica Neue", "Helvetica", "Arial", sans-serif',
1477
- fontSize: 16,
1478
- // 1rem
1479
- fontWeightLight: 300,
1480
- fontWeightRegular: 400,
1481
- fontWeightMedium: 500,
1482
- fontWeightSemiBold: 600,
1483
- fontWeightBold: 700,
1484
- fontWeightHeavy: 800,
1485
- fontWeightBlack: 900,
1486
- h1: {
1487
- fontSize: "2.5rem",
1488
- // 40px
1489
- fontWeight: 700,
1490
- lineHeight: 1.3,
1491
- letterSpacing: "-1px"
1492
- },
1493
- h2: {
1494
- fontSize: "2rem",
1495
- // 32px
1496
- fontWeight: 700,
1497
- lineHeight: 1.3,
1498
- letterSpacing: "-1px"
1499
- },
1500
- h3: {
1501
- fontSize: "1.5rem",
1502
- // 24px
1503
- fontWeight: 700,
1504
- lineHeight: 1.3,
1505
- letterSpacing: "-1px"
1506
- },
1507
- h4: {
1508
- fontSize: "1.25rem",
1509
- // 20px
1510
- fontWeight: 700,
1511
- lineHeight: 1.3,
1512
- letterSpacing: "-0.5px"
1513
- },
1514
- h5: {
1515
- fontSize: "1.125rem",
1516
- // 18px
1517
- fontWeight: 700,
1518
- lineHeight: 1.3,
1519
- letterSpacing: "-0.5px"
1520
- },
1521
- h6: {
1522
- fontSize: "1rem",
1523
- // 16px
1524
- fontWeight: 700,
1525
- lineHeight: 1.3,
1526
- letterSpacing: "-0.5px"
1527
- },
1528
- body1: {
1529
- fontSize: "1rem",
1530
- // 16px
1531
- fontWeight: 400,
1532
- lineHeight: 1.2
1533
- },
1534
- body2: {
1535
- fontSize: "0.875rem",
1536
- // 14px
1537
- fontWeight: 400,
1538
- lineHeight: 1.2
1539
- }
1540
- }, DEFAULT_SHADOWS = {
1541
- xs: "0px 1px 2px 0px rgba(45, 54, 67, 0.04), 0px 2px 4px 0px rgba(45, 54, 67, 0.08)",
1542
- sm: "0 2px 4px rgba(0, 0, 0, 0.075)",
1543
- md: "0 4px 8px rgba(0, 0, 0, 0.1)",
1544
- lg: "0 16px 48px rgba(0, 0, 0, 0.175)",
1545
- xl: "0px 16px 64px -8px rgba(45, 54, 67, 0.14)",
1546
- inset: "inset 0 1px 2px rgba(0, 0, 0, 0.075)"
1547
- }, DEFAULT_TRANSITIONS = {
1548
- duration: {
1549
- shortest: 150,
1550
- shorter: 200,
1551
- short: 250,
1552
- standard: 300,
1553
- complex: 375,
1554
- enteringScreen: 225,
1555
- leavingScreen: 195
1556
- },
1557
- easing: {
1558
- easeInOut: "cubic-bezier(0.4, 0, 0.2, 1)",
1559
- easeOut: "cubic-bezier(0.0, 0, 0.2, 1)",
1560
- easeIn: "cubic-bezier(0.4, 0, 1, 1)",
1561
- sharp: "cubic-bezier(0.4, 0, 0.6, 1)"
1562
- }
1563
- }, DEFAULT_ZINDEX = {
1564
- mobileStepper: 1e3,
1565
- speedDial: 1050,
1566
- appBar: 1020,
1567
- drawer: 1070,
1568
- modal: 1040,
1569
- snackbar: 1080,
1570
- tooltip: 1060
1571
- }, DEFAULT_BORDER_RADIUS = {
1572
- base: "0.5rem",
1573
- // 8px (spacing-2)
1574
- sm: "0.25rem",
1575
- // 4px (spacing-1)
1576
- md: "0.25rem",
1577
- // 4px (spacing-1)
1578
- lg: "0.625rem",
1579
- // 10px (spacing-2.5)
1580
- xl: "0.75rem",
1581
- // 12px (spacing-3)
1582
- xxl: "1rem",
1583
- // 16px (spacing-4)
1584
- "3xl": "1.5rem",
1585
- // 24px (spacing-6)
1586
- "4xl": "2rem",
1587
- // 32px (spacing-8)
1588
- pill: "50rem"
1034
+ // `Object.getOwnPropertyDescriptor` method
1035
+ // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
1036
+ objectGetOwnPropertyDescriptor.f = DESCRIPTORS$3 ? $getOwnPropertyDescriptor$1 : function(O, P) {
1037
+ if (O = toIndexedObject$1(O), P = toPropertyKey$1(P), IE8_DOM_DEFINE$1) try {
1038
+ return $getOwnPropertyDescriptor$1(O, P);
1039
+ } catch (error) {/* empty */}
1040
+ if (hasOwn$1(O, P)) return createPropertyDescriptor$1(!call(propertyIsEnumerableModule.f, O, P), O[P]);
1589
1041
  };
1590
1042
 
1591
- // ============================================================================
1592
- // Helper Functions
1593
- // ============================================================================
1594
- /**
1595
- * Create a complete palette color from partial configuration
1596
- */
1597
- function createPaletteColor(color) {
1598
- return "string" == typeof color ? {
1599
- main: color,
1600
- light: lighten(color),
1601
- dark: darken(color),
1602
- contrastText: getContrastText(color)
1603
- } : {
1604
- main: color.main || "#000000",
1605
- light: color.light || lighten(color.main || "#000000"),
1606
- dark: color.dark || darken(color.main || "#000000"),
1607
- contrastText: color.contrastText || getContrastText(color.main || "#000000")
1608
- };
1609
- }
1043
+ var fails$3 = fails$9, isCallable$2 = isCallable$8, replacement = /#|\.prototype\./, isForced$1 = function(feature, detection) {
1044
+ var value = data[normalize(feature)];
1045
+ return value === POLYFILL || value !== NATIVE && (isCallable$2(detection) ? fails$3(detection) : !!detection);
1046
+ }, normalize = isForced$1.normalize = function(string) {
1047
+ return String(string).replace(replacement, ".").toLowerCase();
1048
+ }, data = isForced$1.data = {}, NATIVE = isForced$1.NATIVE = "N", POLYFILL = isForced$1.POLYFILL = "P", isForced_1 = isForced$1, aCallable$1 = aCallable$3, NATIVE_BIND = functionBindNative, bind$1 = functionUncurryThisClause(functionUncurryThisClause.bind), objectDefineProperty = {}, v8PrototypeDefineBug = descriptors && fails$9((function() {
1049
+ // eslint-disable-next-line es/no-object-defineproperty -- required for testing
1050
+ return 42 !== Object.defineProperty((function() {/* empty */}), "prototype", {
1051
+ value: 42,
1052
+ writable: !1
1053
+ }).prototype;
1054
+ })), isObject$1 = isObject$5, $String$1 = String, $TypeError$3 = TypeError, DESCRIPTORS$1 = descriptors, IE8_DOM_DEFINE = ie8DomDefine, V8_PROTOTYPE_DEFINE_BUG = v8PrototypeDefineBug, anObject = function(argument) {
1055
+ if (isObject$1(argument)) return argument;
1056
+ throw new $TypeError$3($String$1(argument) + " is not an object");
1057
+ }, toPropertyKey = toPropertyKey$2, $TypeError$2 = TypeError, $defineProperty = Object.defineProperty, $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
1610
1058
 
1611
- /**
1612
- * Create breakpoints object
1613
- */
1614
- // ============================================================================
1615
- // Main createTheme Function
1616
- // ============================================================================
1617
- /**
1618
- * Create a theme object with computed values
1619
- *
1620
- * @param options - Theme configuration options
1621
- * @returns Complete theme object
1622
- */
1623
- function createThemeObject(...options) {
1624
- // Merge all options
1625
- const mergedOptions = _reduceInstanceProperty(options).call(options, ((acc, option) => deepMerge(acc, option)), {}), palette = {
1626
- primary: createPaletteColor(mergedOptions.palette?.primary || DEFAULT_PALETTE.primary),
1627
- secondary: createPaletteColor(mergedOptions.palette?.secondary || DEFAULT_PALETTE.secondary),
1628
- error: createPaletteColor(mergedOptions.palette?.error || DEFAULT_PALETTE.error),
1629
- warning: createPaletteColor(mergedOptions.palette?.warning || DEFAULT_PALETTE.warning),
1630
- info: createPaletteColor(mergedOptions.palette?.info || DEFAULT_PALETTE.info),
1631
- success: createPaletteColor(mergedOptions.palette?.success || DEFAULT_PALETTE.success),
1632
- // Handle light and dark colors if provided
1633
- ...mergedOptions.palette?.light && {
1634
- light: createPaletteColor(mergedOptions.palette.light)
1635
- },
1636
- ...mergedOptions.palette?.dark && {
1637
- dark: createPaletteColor(mergedOptions.palette.dark)
1638
- },
1639
- background: {
1640
- default: mergedOptions.palette?.background?.default || DEFAULT_PALETTE.background.default,
1641
- subtle: mergedOptions.palette?.background?.subtle || DEFAULT_PALETTE.background.subtle
1642
- },
1643
- text: {
1644
- primary: mergedOptions.palette?.text?.primary || DEFAULT_PALETTE.text.primary,
1645
- secondary: mergedOptions.palette?.text?.secondary || DEFAULT_PALETTE.text.secondary,
1646
- disabled: mergedOptions.palette?.text?.disabled || DEFAULT_PALETTE.text.disabled
1647
- }
1648
- }, typography = deepMerge({
1649
- ...DEFAULT_TYPOGRAPHY
1650
- }, mergedOptions.typography || {}), spacing =
1651
- // ============================================================================
1652
- // Spacing Utilities
1653
- // ============================================================================
1654
- /**
1655
- * Create a spacing function from various input types
1656
- *
1657
- * @param spacingInput - Spacing configuration (number, array, or function), default 4
1658
- * @returns Spacing function
1659
- */
1660
- function(spacingInput = 4) {
1661
- // If it's already a function, return it
1662
- return "function" == typeof spacingInput ? spacingInput :
1663
- // If it's a number, create a function that multiplies by that number
1664
- "number" == typeof spacingInput ? (...values) => 0 === values.length ? "0px" : values.map((value => value * spacingInput + "px")).join(" ") :
1665
- // If it's an array, use it as a scale
1666
- Array.isArray(spacingInput) ? (...values) => 0 === values.length ? "0px" : values.map((value => `${spacingInput[value] || value}px`)).join(" ") : (...values) => 0 === values.length ? "0px" : values.map((value => 4 * value + "px")).join(" ");
1667
- }(mergedOptions.spacing), breakpoints = function(breakpointsInput) {
1668
- const values = {
1669
- xs: 0,
1670
- sm: 576,
1671
- md: 768,
1672
- lg: 992,
1673
- xl: 1200,
1674
- xxl: 1440,
1675
- ...breakpointsInput?.values
1676
- }, unit = breakpointsInput?.unit || "px";
1677
- return {
1678
- values: values,
1679
- unit: unit,
1680
- up: key => `@media (min-width:${"number" == typeof key ? key : values[key] ?? 0}${unit})`,
1681
- down: key => `@media (max-width:${("number" == typeof key ? key : values[key] ?? 0) - .05}${unit})`,
1682
- between: (start, end) => {
1683
- const startValue = "number" == typeof start ? start : values[start] ?? 0, endValue = "number" == typeof end ? end : values[end] ?? 0;
1684
- return `@media (min-width:${startValue}${unit}) and (max-width:${endValue - .05}${unit})`;
1685
- }
1686
- };
1687
- }(mergedOptions.breakpoints), shadows = deepMerge({
1688
- ...DEFAULT_SHADOWS
1689
- }, mergedOptions.shadows || {}), transitions = deepMerge({
1690
- ...DEFAULT_TRANSITIONS
1691
- }, mergedOptions.transitions || {}), zIndex = deepMerge({
1692
- ...DEFAULT_ZINDEX
1693
- }, mergedOptions.zIndex || {}), borderRadius = deepMerge({
1694
- ...DEFAULT_BORDER_RADIUS
1695
- }, mergedOptions.borderRadius || {});
1696
- // Create palette
1697
- return {
1698
- // Metadata
1699
- name: mergedOptions.name || "Custom Theme",
1700
- class: mergedOptions.class,
1701
- description: mergedOptions.description,
1702
- author: mergedOptions.author,
1703
- version: mergedOptions.version || "1.0.0",
1704
- tags: mergedOptions.tags,
1705
- supportsDarkMode: mergedOptions.supportsDarkMode,
1706
- status: mergedOptions.status || "experimental",
1707
- a11y: mergedOptions.a11y,
1708
- color: mergedOptions.color || palette.primary.main,
1709
- features: mergedOptions.features,
1710
- dependencies: mergedOptions.dependencies,
1711
- // Theme configuration
1712
- palette: palette,
1713
- typography: typography,
1714
- spacing: spacing,
1715
- breakpoints: breakpoints,
1716
- shadows: shadows,
1717
- transitions: transitions,
1718
- zIndex: zIndex,
1719
- borderRadius: borderRadius,
1720
- custom: mergedOptions.custom || {},
1721
- // Mark as JS theme
1722
- __isJSTheme: !0
1723
- };
1724
- }
1059
+ // `Object.defineProperty` method
1060
+ // https://tc39.es/ecma262/#sec-object.defineproperty
1061
+ objectDefineProperty.f = DESCRIPTORS$1 ? V8_PROTOTYPE_DEFINE_BUG ? function(O, P, Attributes) {
1062
+ if (anObject(O), P = toPropertyKey(P), anObject(Attributes), "function" == typeof O && "prototype" === P && "value" in Attributes && "writable" in Attributes && !Attributes.writable) {
1063
+ var current = $getOwnPropertyDescriptor(O, P);
1064
+ current && current.writable && (O[P] = Attributes.value, Attributes = {
1065
+ configurable: "configurable" in Attributes ? Attributes.configurable : current.configurable,
1066
+ enumerable: "enumerable" in Attributes ? Attributes.enumerable : current.enumerable,
1067
+ writable: !1
1068
+ });
1069
+ }
1070
+ return $defineProperty(O, P, Attributes);
1071
+ } : $defineProperty : function(O, P, Attributes) {
1072
+ if (anObject(O), P = toPropertyKey(P), anObject(Attributes), IE8_DOM_DEFINE) try {
1073
+ return $defineProperty(O, P, Attributes);
1074
+ } catch (error) {/* empty */}
1075
+ if ("get" in Attributes || "set" in Attributes) throw new $TypeError$2("Accessors not supported");
1076
+ return "value" in Attributes && (O[P] = Attributes.value), O;
1077
+ };
1725
1078
 
1726
- /**
1727
- * Theme Configuration Validator
1728
- *
1729
- * Validates theme configuration structure and values
1730
- */
1731
- /**
1732
- * Validate theme configuration
1733
- *
1734
- * @param config - Configuration to validate
1735
- * @returns Validation result with errors and warnings
1736
- */
1737
- /**
1738
- * Validate CSS theme
1739
- */
1740
- function validateCSSTheme(themeId, theme) {
1741
- const errors = [];
1742
- // CSS themes don't require createTheme function
1743
- // But can have optional cssPath
1744
- return {
1745
- valid: 0 === errors.length,
1746
- errors: errors,
1747
- warnings: []
1079
+ var definePropertyModule = objectDefineProperty, createPropertyDescriptor = createPropertyDescriptor$2, createNonEnumerableProperty$1 = descriptors ? function(object, key, value) {
1080
+ return definePropertyModule.f(object, key, createPropertyDescriptor(1, value));
1081
+ } : function(object, key, value) {
1082
+ return object[key] = value, object;
1083
+ }, globalThis$3 = globalThis_1, apply = functionApply, uncurryThis$1 = functionUncurryThisClause, isCallable$1 = isCallable$8, getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f, isForced = isForced_1, path$1 = path$3, bind = function(fn, that) {
1084
+ return aCallable$1(fn), void 0 === that ? fn : NATIVE_BIND ? bind$1(fn, that) : function() {
1085
+ return fn.apply(that, arguments);
1748
1086
  };
1749
- }
1087
+ }, createNonEnumerableProperty = createNonEnumerableProperty$1, hasOwn = hasOwnProperty_1, wrapConstructor = function(NativeConstructor) {
1088
+ var Wrapper = function(a, b, c) {
1089
+ if (this instanceof Wrapper) {
1090
+ switch (arguments.length) {
1091
+ case 0:
1092
+ return new NativeConstructor;
1750
1093
 
1751
- /**
1752
- * Validate JS theme
1753
- */ function validateJSTheme(themeId, theme) {
1754
- const errors = [];
1755
- // JS themes must have createTheme function
1756
- return theme.createTheme && "function" == typeof theme.createTheme || errors.push(`JS theme "${themeId}" must have a "createTheme" function`),
1757
- {
1758
- valid: 0 === errors.length,
1759
- errors: errors,
1760
- warnings: []
1094
+ case 1:
1095
+ return new NativeConstructor(a);
1096
+
1097
+ case 2:
1098
+ return new NativeConstructor(a, b);
1099
+ }
1100
+ return new NativeConstructor(a, b, c);
1101
+ }
1102
+ return apply(NativeConstructor, this, arguments);
1761
1103
  };
1762
- }
1104
+ return Wrapper.prototype = NativeConstructor.prototype, Wrapper;
1105
+ }, _export = function(options, source) {
1106
+ var FORCED, USE_NATIVE, VIRTUAL_PROTOTYPE, key, sourceProperty, targetProperty, nativeProperty, resultProperty, descriptor, TARGET = options.target, GLOBAL = options.global, STATIC = options.stat, PROTO = options.proto, nativeSource = GLOBAL ? globalThis$3 : STATIC ? globalThis$3[TARGET] : globalThis$3[TARGET] && globalThis$3[TARGET].prototype, target = GLOBAL ? path$1 : path$1[TARGET] || createNonEnumerableProperty(path$1, TARGET, {})[TARGET], targetPrototype = target.prototype;
1107
+ for (key in source)
1108
+ // contains in native
1109
+ USE_NATIVE = !(FORCED = isForced(GLOBAL ? key : TARGET + (STATIC ? "." : "#") + key, options.forced)) && nativeSource && hasOwn(nativeSource, key),
1110
+ targetProperty = target[key], USE_NATIVE && (nativeProperty = options.dontCallGetSet ? (descriptor = getOwnPropertyDescriptor(nativeSource, key)) && descriptor.value : nativeSource[key]),
1111
+ // export native or implementation
1112
+ sourceProperty = USE_NATIVE && nativeProperty ? nativeProperty : source[key], (FORCED || PROTO || typeof targetProperty != typeof sourceProperty) && (
1113
+ // bind methods to global for calling from export context
1114
+ resultProperty = options.bind && USE_NATIVE ? bind(sourceProperty, globalThis$3) : options.wrap && USE_NATIVE ? wrapConstructor(sourceProperty) : PROTO && isCallable$1(sourceProperty) ? uncurryThis$1(sourceProperty) : sourceProperty,
1115
+ // add a flag to not completely full polyfills
1116
+ (options.sham || sourceProperty && sourceProperty.sham || targetProperty && targetProperty.sham) && createNonEnumerableProperty(resultProperty, "sham", !0),
1117
+ createNonEnumerableProperty(target, key, resultProperty), PROTO && (hasOwn(path$1, VIRTUAL_PROTOTYPE = TARGET + "Prototype") || createNonEnumerableProperty(path$1, VIRTUAL_PROTOTYPE, {}),
1118
+ // export virtual prototype methods
1119
+ createNonEnumerableProperty(path$1[VIRTUAL_PROTOTYPE], key, sourceProperty),
1120
+ // export real prototype methods
1121
+ options.real && targetPrototype && (FORCED || !targetPrototype[key]) && createNonEnumerableProperty(targetPrototype, key, sourceProperty)));
1122
+ }, ceil = Math.ceil, floor = Math.floor, trunc = Math.trunc || function(x) {
1123
+ var n = +x;
1124
+ return (n > 0 ? floor : ceil)(n);
1125
+ }, toIntegerOrInfinity$2 = function(argument) {
1126
+ var number = +argument;
1127
+ // eslint-disable-next-line no-self-compare -- NaN check
1128
+ return number != number || 0 === number ? 0 : trunc(number);
1129
+ }, toIntegerOrInfinity$1 = toIntegerOrInfinity$2, max = Math.max, min$1 = Math.min, toIntegerOrInfinity = toIntegerOrInfinity$2, min = Math.min, lengthOfArrayLike$2 = function(obj) {
1130
+ return argument = obj.length, (len = toIntegerOrInfinity(argument)) > 0 ? min(len, 9007199254740991) : 0;
1131
+ var argument, len;
1132
+ }, toIndexedObject = toIndexedObject$2, lengthOfArrayLike$1 = lengthOfArrayLike$2, createMethod$1 = function(IS_INCLUDES) {
1133
+ return function($this, el, fromIndex) {
1134
+ var O = toIndexedObject($this), length = lengthOfArrayLike$1(O);
1135
+ if (0 === length) return !IS_INCLUDES && -1;
1136
+ var value, index = function(index, length) {
1137
+ var integer = toIntegerOrInfinity$1(index);
1138
+ return integer < 0 ? max(integer + length, 0) : min$1(integer, length);
1139
+ }(fromIndex, length);
1140
+ // Array#includes uses SameValueZero equality algorithm
1141
+ // eslint-disable-next-line no-self-compare -- NaN check
1142
+ if (IS_INCLUDES && el != el) {
1143
+ for (;length > index; )
1144
+ // eslint-disable-next-line no-self-compare -- NaN check
1145
+ if ((value = O[index++]) != value) return !0;
1146
+ // Array#indexOf ignores holes, Array#includes - not
1147
+ } else for (;length > index; index++) if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
1148
+ return !IS_INCLUDES && -1;
1149
+ };
1150
+ }, $includes = [ createMethod$1(!0), createMethod$1(!1) ][0];
1763
1151
 
1764
- /**
1765
- * Validate build configuration
1766
- */
1767
- /**
1768
- * Theme System Error Handling
1769
- *
1770
- * Centralized error handling for the Atomix theme system.
1771
- * Provides custom error classes and logging utilities.
1772
- */
1773
- /**
1774
- * Theme error codes
1775
- */
1776
- var ThemeErrorCode, LogLevel;
1152
+ // `Array.prototype.includes` method
1153
+ // https://tc39.es/ecma262/#sec-array.prototype.includes
1154
+ _export({
1155
+ target: "Array",
1156
+ proto: !0,
1157
+ forced: fails$9((function() {
1158
+ // eslint-disable-next-line es/no-array-prototype-includes -- detection
1159
+ return !Array(1).includes();
1160
+ }))
1161
+ }, {
1162
+ includes: function(el /* , fromIndex = 0 */) {
1163
+ return $includes(this, el, arguments.length > 1 ? arguments[1] : void 0);
1164
+ }
1165
+ });
1777
1166
 
1778
- !function(ThemeErrorCode) {
1779
- /** Theme not found in registry */
1780
- ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
1781
- /** Theme failed to load */
1782
- ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
1783
- /** Theme validation failed */
1784
- ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
1785
- /** Configuration loading failed */
1786
- ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
1787
- /** Configuration validation failed */
1788
- ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
1789
- /** Circular dependency detected */
1790
- ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
1791
- /** Missing dependency */
1792
- ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
1793
- /** Storage operation failed */
1794
- ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
1795
- /** Invalid theme name */
1796
- ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
1797
- /** CSS injection failed */
1798
- ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
1799
- /** Unknown error */
1800
- ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
1801
- }(ThemeErrorCode || (ThemeErrorCode = {}));
1167
+ var globalThis$2 = globalThis_1, path = path$3, getBuiltInPrototypeMethod$3 = function(CONSTRUCTOR, METHOD) {
1168
+ var Namespace = path[CONSTRUCTOR + "Prototype"], pureMethod = Namespace && Namespace[METHOD];
1169
+ if (pureMethod) return pureMethod;
1170
+ var NativeConstructor = globalThis$2[CONSTRUCTOR], NativePrototype = NativeConstructor && NativeConstructor.prototype;
1171
+ return NativePrototype && NativePrototype[METHOD];
1172
+ }, includes$4 = getBuiltInPrototypeMethod$3("Array", "includes"), isObject = isObject$5, classof$3 = classofRaw$2, MATCH$1 = wellKnownSymbol$5("match"), $TypeError$1 = TypeError, test = {};
1802
1173
 
1803
- /**
1804
- * Custom error class for theme-related errors
1805
- */
1806
- class ThemeError extends Error {
1807
- constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
1808
- super(message), this.name = "ThemeError", this.code = code, this.context = context,
1809
- this.timestamp = Date.now(),
1810
- // Maintains proper stack trace for where our error was thrown (only available on V8)
1811
- Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
1812
- }
1813
- /**
1814
- * Convert error to JSON for logging
1815
- */ toJSON() {
1816
- return {
1817
- name: this.name,
1818
- message: this.message,
1819
- code: this.code,
1820
- context: this.context,
1821
- timestamp: this.timestamp,
1822
- stack: this.stack
1823
- };
1824
- }
1825
- }
1174
+ test[wellKnownSymbol$5("toStringTag")] = "z";
1826
1175
 
1827
- /**
1828
- * Log level
1829
- */ !function(LogLevel) {
1830
- LogLevel[LogLevel.ERROR = 0] = "ERROR", LogLevel[LogLevel.WARN = 1] = "WARN", LogLevel[LogLevel.INFO = 2] = "INFO",
1831
- LogLevel[LogLevel.DEBUG = 3] = "DEBUG";
1832
- }(LogLevel || (LogLevel = {}));
1176
+ var TO_STRING_TAG_SUPPORT = "[object z]" === String(test), isCallable = isCallable$8, classofRaw = classofRaw$2, TO_STRING_TAG = wellKnownSymbol$5("toStringTag"), $Object = Object, CORRECT_ARGUMENTS = "Arguments" === classofRaw(function() {
1177
+ return arguments;
1178
+ }()), classof$1 = TO_STRING_TAG_SUPPORT ? classofRaw : function(it) {
1179
+ var O, tag, result;
1180
+ return void 0 === it ? "Undefined" : null === it ? "Null" : "string" == typeof (tag = function(it, key) {
1181
+ try {
1182
+ return it[key];
1183
+ } catch (error) {/* empty */}
1184
+ }(O = $Object(it), TO_STRING_TAG)) ? tag : CORRECT_ARGUMENTS ? classofRaw(O) : "Object" === (result = classofRaw(O)) && isCallable(O.callee) ? "Arguments" : result;
1185
+ }, $String = String, MATCH = wellKnownSymbol$5("match"), $$1 = _export, notARegExp = function(it) {
1186
+ if (function(it) {
1187
+ var isRegExp;
1188
+ return isObject(it) && (void 0 !== (isRegExp = it[MATCH$1]) ? !!isRegExp : "RegExp" === classof$3(it));
1189
+ }(it)) throw new $TypeError$1("The method doesn't accept regular expressions");
1190
+ return it;
1191
+ }, requireObjectCoercible = requireObjectCoercible$3, toString = function(argument) {
1192
+ if ("Symbol" === classof$1(argument)) throw new TypeError("Cannot convert a Symbol value to a string");
1193
+ return $String(argument);
1194
+ }, stringIndexOf = functionUncurryThis("".indexOf);
1833
1195
 
1834
- /**
1835
- * Theme Logger
1836
- *
1837
- * Centralized logging for the theme system.
1838
- * Replaces console statements with structured logging.
1839
- */
1840
- class ThemeLogger {
1841
- constructor(config = {}) {
1842
- this.config = {
1843
- level: config.level ?? ("production" === process.env.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
1844
- enableConsole: config.enableConsole ?? !0,
1845
- onError: config.onError,
1846
- onWarn: config.onWarn,
1847
- onInfo: config.onInfo,
1848
- onDebug: config.onDebug
1849
- };
1850
- }
1851
- /**
1852
- * Log an error
1853
- */ error(message, error, context) {
1854
- if (this.config.level < LogLevel.ERROR) return;
1855
- const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
1856
- this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
1857
- error: errorObj,
1858
- context: {
1859
- ...context,
1860
- ...themeError.context
1861
- },
1862
- code: themeError.code
1863
- }), this.config.onError?.(themeError, context);
1864
- }
1865
- /**
1866
- * Log a warning
1867
- */ warn(message, context) {
1868
- this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
1869
- this.config.onWarn?.(message, context));
1870
- }
1871
- /**
1872
- * Log an info message
1873
- */ info(message, context) {
1874
- this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
1875
- this.config.onInfo?.(message, context));
1876
- }
1877
- /**
1878
- * Log a debug message
1879
- */ debug(message, context) {
1880
- this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
1196
+ // `String.prototype.includes` method
1197
+ // https://tc39.es/ecma262/#sec-string.prototype.includes
1198
+ $$1({
1199
+ target: "String",
1200
+ proto: !0,
1201
+ forced: !function(METHOD_NAME) {
1202
+ var regexp = /./;
1203
+ try {
1204
+ "/./"[METHOD_NAME](regexp);
1205
+ } catch (error1) {
1206
+ try {
1207
+ return regexp[MATCH] = !1, "/./"[METHOD_NAME](regexp);
1208
+ } catch (error2) {/* empty */}
1209
+ }
1210
+ return !1;
1211
+ }("includes")
1212
+ }, {
1213
+ includes: function(searchString /* , position = 0 */) {
1214
+ return !!~stringIndexOf(toString(requireObjectCoercible(this)), toString(notARegExp(searchString)), arguments.length > 1 ? arguments[1] : void 0);
1881
1215
  }
1882
- }
1216
+ });
1883
1217
 
1884
- /**
1885
- * Default logger instance
1886
- */ let defaultLogger = null;
1218
+ var includes$3 = getBuiltInPrototypeMethod$3("String", "includes"), isPrototypeOf$1 = objectIsPrototypeOf, arrayMethod = includes$4, stringMethod = includes$3, ArrayPrototype$1 = Array.prototype, StringPrototype = String.prototype;
1887
1219
 
1888
- /**
1889
- * Get or create default logger
1890
- */ function getLogger() {
1891
- return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
1892
- }
1220
+ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
1221
+ var own = it.includes;
1222
+ return it === ArrayPrototype$1 || isPrototypeOf$1(ArrayPrototype$1, it) && own === ArrayPrototype$1.includes ? arrayMethod : "string" == typeof it || it === StringPrototype || isPrototypeOf$1(StringPrototype, it) && own === StringPrototype.includes ? stringMethod : own;
1223
+ }));
1893
1224
 
1894
1225
  /**
1895
1226
  * Theme System Constants
@@ -1898,712 +1229,202 @@ class ThemeLogger {
1898
1229
  */
1899
1230
  /**
1900
1231
  * Default storage key for theme persistence
1901
- */ const DEFAULT_ATOMIX_CONFIG_PATH = "atomix.config.ts";
1902
-
1903
- /**
1904
- * Default data attribute name for theme
1905
- */ process.env.NODE_ENV;
1232
+ */ "undefined" != typeof process && process.env;
1906
1233
 
1907
1234
  /**
1908
- * Integration default class names
1235
+ * Check if code is running in a browser environment
1909
1236
  */
1910
- const DEFAULT_INTEGRATION_CLASS_NAMES = {
1911
- theme: "data-theme",
1912
- colorMode: "data-atomix-color-mode"
1913
- }, DEFAULT_INTEGRATION_CSS_VARIABLES = {
1914
- colorMode: "--storybook-color-mode"
1915
- }, DEFAULT_SASS_CONFIG = {
1916
- style: "expanded",
1917
- sourceMap: !0,
1918
- loadPaths: [ "src" ]
1919
- };
1237
+ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof document, isServer = () => !isBrowser(), sanitizePath = path => path.replace(/[<>"']/g, "").replace(/\.\./g, "").replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "") // Trim leading/trailing slashes
1238
+ , buildThemePath = (themeName, basePath = "/themes", useMinified = !1, cdnPath = null) => {
1239
+ // Validate theme name to prevent path injection
1240
+ if (!isValidThemeName(themeName)) throw new ThemeError(`Invalid theme name: "${themeName}". Theme names must be lowercase alphanumeric with hyphens (e.g., "my-theme").`, ThemeErrorCode.INVALID_THEME_NAME, {
1241
+ themeName: themeName,
1242
+ pattern: /^[a-z0-9]+(-[a-z0-9]+)*$/
1243
+ });
1244
+ const fileName = `${themeName}${useMinified ? ".min.css" : ".css"}`;
1245
+ return cdnPath ? `${sanitizePath(cdnPath)}/${fileName}` : `${sanitizePath(basePath)}/${fileName.replace(/^\//, "")}`;
1246
+ // Sanitize basePath to prevent path injection
1247
+ }, applyThemeAttributes = (dataAttribute, themeName) => {
1248
+ isServer() || (
1249
+ // Set data attribute on body (with null check)
1250
+ document.body && document.body.setAttribute(dataAttribute, themeName),
1251
+ // Also set on documentElement for broader compatibility
1252
+ document.documentElement.setAttribute(dataAttribute, themeName));
1253
+ }, isValidThemeName = themeName => !(!themeName || "string" != typeof themeName) && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(themeName), createLocalStorageAdapter = () => ({
1254
+ getItem: key => {
1255
+ if (isServer()) return null;
1256
+ try {
1257
+ return localStorage.getItem(key);
1258
+ } catch {
1259
+ return null;
1260
+ }
1261
+ },
1262
+ setItem: (key, value) => {
1263
+ if (!isServer()) try {
1264
+ localStorage.setItem(key, value);
1265
+ } catch {
1266
+ // Silently fail if localStorage is not available
1267
+ }
1268
+ },
1269
+ removeItem: key => {
1270
+ if (!isServer()) try {
1271
+ localStorage.removeItem(key);
1272
+ } catch {
1273
+ // Silently fail
1274
+ }
1275
+ },
1276
+ isAvailable: () => {
1277
+ if (isServer()) return !1;
1278
+ try {
1279
+ const test = "__atomix_storage_test__";
1280
+ return localStorage.setItem(test, test), localStorage.removeItem(test), !0;
1281
+ } catch {
1282
+ return !1;
1283
+ }
1284
+ }
1285
+ }), domUtils = Object.freeze( Object.defineProperty({
1286
+ __proto__: null,
1287
+ applyThemeAttributes: applyThemeAttributes,
1288
+ buildThemePath: buildThemePath,
1289
+ createLocalStorageAdapter: createLocalStorageAdapter,
1290
+ isBrowser: isBrowser,
1291
+ isServer: isServer,
1292
+ isValidThemeName: isValidThemeName,
1293
+ loadThemeCSS: (fullPath, linkId) => isServer() ? Promise.resolve() : new Promise(((resolve, reject) => {
1294
+ if (document.getElementById(linkId)) return void resolve();
1295
+ // Create link element
1296
+ const link = document.createElement("link");
1297
+ link.id = linkId, link.rel = "stylesheet", link.type = "text/css", link.href = fullPath,
1298
+ // Add data attribute for tracking
1299
+ link.setAttribute("data-atomix-theme", "true"),
1300
+ // Handle load success
1301
+ link.onload = () => {
1302
+ resolve();
1303
+ },
1304
+ // Handle load error
1305
+ link.onerror = () => {
1306
+ // Remove failed link element
1307
+ link.remove(), reject(new ThemeError(`Failed to load theme CSS from: ${fullPath}. Please check that the file exists and is accessible.`, ThemeErrorCode.THEME_LOAD_FAILED, {
1308
+ fullPath: fullPath,
1309
+ linkId: linkId
1310
+ }));
1311
+ },
1312
+ // Append to head
1313
+ document.head.appendChild(link);
1314
+ }))
1315
+ }, Symbol.toStringTag, {
1316
+ value: "Module"
1317
+ }));
1920
1318
 
1921
1319
  /**
1922
- * Integration default CSS variables
1320
+ * Check if code is running on the server (SSR)
1923
1321
  */
1924
1322
  /**
1925
- * Theme Configuration Loader
1323
+ * Theme Utilities
1926
1324
  *
1927
- * Loads and validates the theme configuration from atomix.config.ts
1325
+ * Helper utilities for working with themes, including color manipulation,
1326
+ * spacing helpers, and theme value accessors.
1928
1327
  */
1328
+ // ============================================================================
1329
+ // Color Manipulation Utilities
1330
+ // ============================================================================
1929
1331
  /**
1930
- * Cache for loaded configuration
1332
+ * Convert hex color to RGB object
1931
1333
  */
1932
- let cachedConfig = null;
1933
-
1934
- /**
1935
- * Logger instance
1936
- */ const logger = getLogger();
1334
+ function hexToRgb(hex) {
1335
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
1336
+ return result ? {
1337
+ r: parseInt(result[1], 16),
1338
+ g: parseInt(result[2], 16),
1339
+ b: parseInt(result[3], 16)
1340
+ } : null;
1341
+ }
1937
1342
 
1938
1343
  /**
1939
- * Load theme configuration from atomix.config.ts
1940
- *
1941
- * @param options - Loader options
1942
- * @returns Loaded and validated theme configuration
1943
- *
1944
- * @example
1945
- * ```typescript
1946
- * import { loadThemeConfig } from '@shohojdhara/atomix/theme/config';
1947
- * const config = loadThemeConfig();
1948
- * ```
1949
- */
1950
- /**
1951
- * Theme Registry
1952
- *
1953
- * Manages theme registration, discovery, and dependency resolution
1954
- */
1955
- class ThemeRegistry {
1956
- constructor() {
1957
- this.entries = new Map, this.config = null, this.initialized = !1;
1958
- }
1959
- /**
1960
- * Initialize registry from config
1961
- */ async initialize(config) {
1962
- if (!this.initialized) {
1963
- // Load config if not provided
1964
- if (config) this.config = config; else try {
1965
- this.config = function(options = {}) {
1966
- const {configPath: configPath = DEFAULT_ATOMIX_CONFIG_PATH, validate: validate = !0, env: env = ("undefined" != typeof process && process.env && "production" === process.env.NODE_ENV ? "production" : "development")} = options;
1967
- // Return cached config if available
1968
- if (cachedConfig) return cachedConfig;
1969
- // Try to load config dynamically
1970
- let config;
1971
- try {
1972
- // In browser/Vite environment, we can't load config dynamically
1973
- if ("undefined" != typeof window) throw new Error("Theme config loading not supported in browser environment");
1974
- // In ESM environments, require might be undefined.
1975
- let nodeRequire, configModule;
1976
- try {
1977
- nodeRequire = require;
1978
- } catch {
1979
- // require is not defined
1980
- }
1981
- if (!nodeRequire) throw new Error("Theme config loading not supported in this environment (require is undefined)");
1982
- // Try require (Node.js/CommonJS)
1983
- try {
1984
- // Try relative path first
1985
- try {
1986
- configModule = nodeRequire("../../../../atomix.config");
1987
- } catch {
1988
- // If relative path fails, try to resolve from process.cwd()
1989
- const path = nodeRequire("path"), fs = nodeRequire("fs");
1990
- let configFilePath = path.resolve(process.cwd(), configPath);
1991
- // If atomix.config.ts not found at the root, use the default path
1992
- if (fs.existsSync(configFilePath) || configPath !== DEFAULT_ATOMIX_CONFIG_PATH || (configFilePath = path.resolve(process.cwd(), DEFAULT_ATOMIX_CONFIG_PATH)),
1993
- !fs.existsSync(configFilePath)) throw new Error(`Config file not found: ${configFilePath}`);
1994
- {
1995
- const resolvedPath = nodeRequire.resolve(configFilePath);
1996
- nodeRequire.cache && nodeRequire.cache[resolvedPath] && delete nodeRequire.cache[resolvedPath],
1997
- configModule = nodeRequire(configFilePath);
1998
- }
1999
- }
2000
- } catch (requireError) {
2001
- const errorMessage = requireError instanceof Error ? requireError.message : String(requireError);
2002
- throw new ThemeError(`Cannot load config: ${errorMessage}`, ThemeErrorCode.CONFIG_LOAD_FAILED, {
2003
- configPath: configPath,
2004
- error: errorMessage
2005
- });
2006
- }
2007
- const rawConfig = configModule.default || configModule, finalConfig =
2008
- /**
2009
- * Apply environment-specific overrides to configuration
2010
- *
2011
- * @param config - Base configuration
2012
- * @param env - Environment name
2013
- * @returns Configuration with environment overrides applied
2014
- */
2015
- function(config, env) {
2016
- const overridden = {
2017
- ...config
2018
- };
2019
- // Production overrides
2020
- return "production" === env && overridden.runtime && (overridden.runtime = {
2021
- ...overridden.runtime,
2022
- useMinified: !0,
2023
- lazy: !0
2024
- }),
2025
- // Development overrides
2026
- "development" === env && (overridden.runtime && (overridden.runtime = {
2027
- ...overridden.runtime,
2028
- useMinified: !1,
2029
- lazy: !1
2030
- }), overridden.build && (overridden.build = {
2031
- ...overridden.build,
2032
- sass: {
2033
- ...overridden.build.sass,
2034
- sourceMap: !0
2035
- }
2036
- })),
2037
- // Test overrides
2038
- "test" === env && overridden.runtime && (overridden.runtime = {
2039
- ...overridden.runtime,
2040
- enablePersistence: !1,
2041
- preload: []
2042
- }), overridden;
2043
- }({
2044
- themes: rawConfig.theme?.themes || {},
2045
- build: rawConfig.build || {},
2046
- runtime: rawConfig.runtime || {},
2047
- integration: rawConfig.integration || {},
2048
- dependencies: rawConfig.dependencies || {},
2049
- validated: !1,
2050
- // Will be set after validation
2051
- // Store tokens for generator
2052
- __tokens: rawConfig.theme?.tokens,
2053
- __extend: rawConfig.theme?.extend
2054
- }, env);
2055
- // Process the AtomixConfig structure
2056
- // Validate if requested
2057
- let validationResult = null;
2058
- validate && (validationResult = function(config) {
2059
- const errors = [], warnings = [];
2060
- // Validate top-level structure
2061
- if (!config || "object" != typeof config) return errors.push("Configuration must be an object"),
2062
- {
2063
- valid: !1,
2064
- errors: errors,
2065
- warnings: warnings
2066
- };
2067
- // Validate themes
2068
- if (config.themes && "object" == typeof config.themes) {
2069
- const themeErrors =
2070
- /**
2071
- * Validate themes object
2072
- */
2073
- function(themes) {
2074
- const errors = [], warnings = [];
2075
- 0 === Object.keys(themes).length && warnings.push("No themes defined in configuration");
2076
- for (const [themeId, theme] of Object.entries(themes))
2077
- // Validate theme ID
2078
- if (themeId && "string" == typeof themeId)
2079
- // Validate theme object
2080
- if (theme && "object" == typeof theme)
2081
- // Validate theme type
2082
- if (!theme.type || "css" !== theme.type && "js" !== theme.type) errors.push(`Theme "${themeId}" must have type "css" or "js"`); else {
2083
- // Validate CSS theme
2084
- if (
2085
- // Validate required fields
2086
- theme.name && "string" == typeof theme.name || errors.push(`Theme "${themeId}" must have a "name" string`),
2087
- "css" === theme.type) {
2088
- const cssErrors = validateCSSTheme();
2089
- errors.push(...cssErrors.errors), warnings.push(...cssErrors.warnings);
2090
- }
2091
- // Validate JS theme
2092
- if ("js" === theme.type) {
2093
- const jsErrors = validateJSTheme(themeId, theme);
2094
- errors.push(...jsErrors.errors), warnings.push(...jsErrors.warnings);
2095
- }
2096
- // Validate accessibility (only critical checks)
2097
- theme.a11y?.contrastTarget && ("number" != typeof theme.a11y.contrastTarget || theme.a11y.contrastTarget < 1 || theme.a11y.contrastTarget > 21) && warnings.push(`Theme "${themeId}" has invalid contrast target: ${theme.a11y.contrastTarget}`);
2098
- } else errors.push(`Theme "${themeId}" must be an object`); else errors.push(`Invalid theme ID: ${themeId}`);
2099
- return {
2100
- valid: 0 === errors.length,
2101
- errors: errors,
2102
- warnings: warnings
2103
- };
2104
- }(config.themes);
2105
- errors.push(...themeErrors.errors), warnings.push(...themeErrors.warnings);
2106
- }
2107
- // Validate build config (only if provided)
2108
- else errors.push('Configuration must have a "themes" object');
2109
- if (config.build) {
2110
- const buildErrors = function(build) {
2111
- const errors = [];
2112
- // Only validate structure if provided
2113
- return build.output && "object" != typeof build.output && errors.push("Build output must be an object"),
2114
- build.sass && "object" != typeof build.sass && errors.push("Build sass config must be an object"),
2115
- {
2116
- valid: 0 === errors.length,
2117
- errors: errors,
2118
- warnings: []
2119
- };
2120
- }
2121
- /**
2122
- * Validate runtime configuration
2123
- */ (config.build);
2124
- errors.push(...buildErrors.errors), warnings.push(...buildErrors.warnings);
2125
- }
2126
- // Validate runtime config (only if provided)
2127
- if (config.runtime) {
2128
- const runtimeErrors = function(runtime) {
2129
- const errors = [];
2130
- return runtime.basePath && "string" != typeof runtime.basePath && errors.push("Runtime basePath must be a string"),
2131
- runtime.defaultTheme && "string" != typeof runtime.defaultTheme && errors.push("Runtime defaultTheme must be a string"),
2132
- runtime.preload && !Array.isArray(runtime.preload) && errors.push("Runtime preload must be an array"),
2133
- runtime.storageKey && "string" != typeof runtime.storageKey && errors.push("Runtime storageKey must be a string"),
2134
- {
2135
- valid: 0 === errors.length,
2136
- errors: errors,
2137
- warnings: []
2138
- };
2139
- }
2140
- /**
2141
- * Validate integration configuration
2142
- */ (config.runtime);
2143
- errors.push(...runtimeErrors.errors), warnings.push(...runtimeErrors.warnings);
2144
- }
2145
- // Validate integration config (only if provided)
2146
- if (config.integration) {
2147
- const integrationErrors = function(integration) {
2148
- const errors = [];
2149
- // Only validate structure if provided
2150
- return integration.classNames && "object" != typeof integration.classNames && errors.push("Integration classNames must be an object"),
2151
- {
2152
- valid: 0 === errors.length,
2153
- errors: errors,
2154
- warnings: []
2155
- };
2156
- }
2157
- /**
2158
- * Validate dependencies
2159
- */ (config.integration);
2160
- errors.push(...integrationErrors.errors), warnings.push(...integrationErrors.warnings);
2161
- }
2162
- // Validate dependencies
2163
- if (config.dependencies) {
2164
- const depErrors = function(dependencies, themes) {
2165
- const errors = [], warnings = [];
2166
- for (const [themeId, deps] of Object.entries(dependencies))
2167
- // Check if theme exists
2168
- if (themes[themeId])
2169
- // Validate dependencies array
2170
- if (Array.isArray(deps))
2171
- // Check if all dependencies exist
2172
- for (const dep of deps) themes[dep] || errors.push(`Theme "${themeId}" depends on non-existent theme: ${dep}`); else errors.push(`Dependencies for "${themeId}" must be an array`); else warnings.push(`Dependencies defined for non-existent theme: ${themeId}`);
2173
- return {
2174
- valid: 0 === errors.length,
2175
- errors: errors,
2176
- warnings: warnings
2177
- };
2178
- }(config.dependencies, config.themes || {});
2179
- errors.push(...depErrors.errors), warnings.push(...depErrors.warnings);
2180
- }
2181
- return {
2182
- valid: 0 === errors.length,
2183
- errors: errors,
2184
- warnings: warnings
2185
- };
2186
- }(finalConfig)), config = {
2187
- ...finalConfig,
2188
- validated: validate,
2189
- errors: validationResult?.errors,
2190
- warnings: validationResult?.warnings
2191
- };
2192
- } catch (error) {
2193
- // Fallback: return default config structure
2194
- const errorMessage = error instanceof Error ? error.message : String(error);
2195
- logger.warn(`Failed to load theme config from ${configPath}`, {
2196
- configPath: configPath,
2197
- error: errorMessage
2198
- }), config = {
2199
- themes: {},
2200
- build: {
2201
- output: {
2202
- directory: "themes",
2203
- formats: {
2204
- expanded: ".css",
2205
- compressed: ".min.css"
2206
- }
2207
- },
2208
- sass: {
2209
- ...DEFAULT_SASS_CONFIG,
2210
- loadPaths: [ ...DEFAULT_SASS_CONFIG.loadPaths ]
2211
- }
2212
- },
2213
- runtime: {
2214
- basePath: "/themes",
2215
- cdnPath: null,
2216
- preload: [],
2217
- lazy: !0,
2218
- defaultTheme: "",
2219
- // No default - use built-in styles (empty string instead of undefined)
2220
- storageKey: "atomix-theme",
2221
- dataAttribute: "data-theme",
2222
- enablePersistence: !0,
2223
- useMinified: "production" === env
2224
- },
2225
- integration: {
2226
- cssVariables: DEFAULT_INTEGRATION_CSS_VARIABLES,
2227
- classNames: DEFAULT_INTEGRATION_CLASS_NAMES
2228
- },
2229
- dependencies: {},
2230
- validated: !1,
2231
- errors: [ `Failed to load config: ${error instanceof Error ? error.message : String(error)}` ],
2232
- warnings: [],
2233
- __tokens: {},
2234
- __extend: {}
2235
- };
2236
- }
2237
- // Cache the loaded config
2238
- return cachedConfig = config, config;
2239
- }();
2240
- } catch (error) {
2241
- // In browser environments, config loading will fail
2242
- // Use empty config as fallback
2243
- this.config = {
2244
- themes: {},
2245
- build: {
2246
- output: {
2247
- directory: "themes",
2248
- formats: {
2249
- expanded: ".css",
2250
- compressed: ".min.css"
2251
- }
2252
- },
2253
- sass: {
2254
- style: "expanded",
2255
- sourceMap: !0,
2256
- loadPaths: [ "src" ]
2257
- }
2258
- },
2259
- runtime: {
2260
- basePath: "",
2261
- defaultTheme: void 0
2262
- },
2263
- integration: {
2264
- cssVariables: {
2265
- colorMode: "--color-mode"
2266
- },
2267
- classNames: {
2268
- theme: "data-theme",
2269
- colorMode: "data-color-mode"
2270
- }
2271
- },
2272
- dependencies: {},
2273
- validated: !1,
2274
- errors: [],
2275
- warnings: [],
2276
- __tokens: {},
2277
- __extend: {}
2278
- };
2279
- }
2280
- // Register all themes from config
2281
- for (const [themeId, definition] of Object.entries(this.config.themes)) this.register(themeId, definition);
2282
- // Resolve dependencies
2283
- this.resolveDependencies(), this.initialized = !0;
2284
- }
2285
- }
2286
- /**
2287
- * Register a theme
2288
- */ register(themeId, definition) {
2289
- // Get dependencies from config or definition
2290
- const entry = {
2291
- id: themeId,
2292
- definition: definition,
2293
- loaded: !1,
2294
- dependencies: [ ...this.config?.dependencies?.[themeId] || definition.dependencies || [] ],
2295
- dependents: []
2296
- };
2297
- this.entries.set(themeId, entry);
2298
- }
2299
- /**
2300
- * Get theme entry
2301
- */ get(themeId) {
2302
- return this.entries.get(themeId);
2303
- }
2304
- /**
2305
- * Check if theme exists
2306
- */ has(themeId) {
2307
- return this.entries.has(themeId);
2308
- }
2309
- /**
2310
- * Get all theme IDs
2311
- */ getAllIds() {
2312
- return Array.from(this.entries.keys());
2313
- }
2314
- /**
2315
- * Get all theme metadata
2316
- */ getAllMetadata() {
2317
- return Array.from(this.entries.values()).map((entry => ({
2318
- id: entry.id,
2319
- name: entry.definition.name,
2320
- type: entry.definition.type,
2321
- class: entry.definition.class,
2322
- description: entry.definition.description,
2323
- author: entry.definition.author,
2324
- version: entry.definition.version,
2325
- tags: entry.definition.tags,
2326
- supportsDarkMode: entry.definition.supportsDarkMode,
2327
- status: entry.definition.status,
2328
- a11y: entry.definition.a11y,
2329
- color: entry.definition.color,
2330
- features: entry.definition.features,
2331
- dependencies: entry.dependencies
2332
- })));
2333
- }
2334
- /**
2335
- * Get theme definition
2336
- */ getDefinition(themeId) {
2337
- return this.entries.get(themeId)?.definition;
2338
- }
2339
- /**
2340
- * Check if a theme is loaded
2341
- */ isThemeLoaded(themeId) {
2342
- const entry = this.entries.get(themeId);
2343
- return !!entry && entry.loaded;
2344
- }
2345
- /**
2346
- * Mark a theme as loaded
2347
- */ markLoaded(themeId, theme) {
2348
- const entry = this.entries.get(themeId);
2349
- entry && (entry.loaded = !0, theme && (entry.theme = theme));
2350
- }
2351
- /**
2352
- * Get theme object (for JS themes)
2353
- */ getTheme(themeId) {
2354
- const entry = this.entries.get(themeId);
2355
- return entry?.loaded ? entry.theme : void 0;
2356
- }
2357
- /**
2358
- * Get dependencies for a theme
2359
- */ getDependencies(themeId) {
2360
- return this.entries.get(themeId)?.dependencies || [];
2361
- }
2362
- /**
2363
- * Get dependents for a theme (themes that depend on this one)
2364
- */ getDependents(themeId) {
2365
- return this.entries.get(themeId)?.dependents || [];
2366
- }
2367
- /**
2368
- * Resolve all dependencies in correct order
2369
- */ resolveDependencyOrder(themeId) {
2370
- const resolved = [], visited = new Set, visiting = new Set, visit = id => {
2371
- if (visiting.has(id)) throw new Error(`Circular dependency detected involving theme: ${id}`);
2372
- if (visited.has(id)) return;
2373
- visiting.add(id);
2374
- const entry = this.entries.get(id);
2375
- if (entry) for (const dep of entry.dependencies) {
2376
- if (!this.has(dep)) throw new Error(`Theme "${id}" depends on non-existent theme: ${dep}`);
2377
- visit(dep);
2378
- }
2379
- visiting.delete(id), visited.add(id), resolved.push(id);
2380
- };
2381
- return visit(themeId), resolved;
2382
- }
2383
- /**
2384
- * Resolve dependencies and build dependency graph
2385
- */ resolveDependencies() {
2386
- // Build dependents map
2387
- for (const entry of this.entries.values()) for (const dep of entry.dependencies) {
2388
- const depEntry = this.entries.get(dep);
2389
- var _context;
2390
- depEntry && (_includesInstanceProperty(_context = depEntry.dependents).call(_context, entry.id) || depEntry.dependents.push(entry.id));
2391
- }
2392
- }
2393
- /**
2394
- * Validate all themes
2395
- */ validate() {
2396
- const errors = [];
2397
- // Check for circular dependencies
2398
- for (const themeId of this.entries.keys()) try {
2399
- this.resolveDependencyOrder(themeId);
2400
- } catch (error) {
2401
- errors.push(error instanceof Error ? error.message : String(error));
2402
- }
2403
- // Check for missing dependencies
2404
- for (const [themeId, entry] of this.entries.entries()) for (const dep of entry.dependencies) this.has(dep) || errors.push(`Theme "${themeId}" depends on non-existent theme: ${dep}`);
2405
- return {
2406
- valid: 0 === errors.length,
2407
- errors: errors
2408
- };
2409
- }
2410
- /**
2411
- * Clear registry
2412
- */ clear() {
2413
- this.entries.clear(), this.config = null, this.initialized = !1;
2414
- }
1344
+ * Convert RGB to hex color
1345
+ */ function rgbToHex(r, g, b) {
1346
+ const toHex = val => Math.round(Math.max(0, Math.min(255, val))).toString(16).padStart(2, "0");
1347
+ return `#${toHex(r ?? 0)}${toHex(g ?? 0)}${toHex(b ?? 0)}`;
2415
1348
  }
2416
1349
 
2417
1350
  /**
2418
- * CSS Injection Utilities
2419
- *
2420
- * Inject CSS into HTML head via <style> element.
2421
- */
2422
- /**
2423
- * Check if running in browser environment
2424
- */ function isBrowser$1() {
2425
- return "undefined" != typeof document;
1351
+ * Calculate relative luminance of a color
1352
+ * Used for determining contrast ratios
1353
+ */ function getLuminance(color) {
1354
+ const rgb = hexToRgb(color);
1355
+ if (!rgb) return 0;
1356
+ const {r: r, g: g, b: b} = rgb, [rs, gs, bs] = [ r ?? 0, g ?? 0, b ?? 0 ].map((c => {
1357
+ const val = c / 255;
1358
+ return val <= .03928 ? val / 12.92 : Math.pow((val + .055) / 1.055, 2.4);
1359
+ }));
1360
+ return .2126 * (rs ?? 0) + .7152 * (gs ?? 0) + .0722 * (bs ?? 0);
2426
1361
  }
2427
1362
 
2428
1363
  /**
2429
- * Inject CSS into HTML head via <style> element
2430
- *
2431
- * Creates or updates a style element in the document head.
2432
- * If an element with the same ID exists, it will be updated.
2433
- *
2434
- * @param css - CSS string to inject
2435
- * @param id - Style element ID (default: 'atomix-theme')
2436
- *
2437
- * @example
2438
- * ```typescript
2439
- * const css = ':root { --atomix-color-primary: #7AFFD7; }';
2440
- * injectCSS(css);
2441
- *
2442
- * // With custom ID
2443
- * injectCSS(css, 'my-custom-theme');
2444
- * ```
2445
- */ function injectCSS$1(css, id = "atomix-theme") {
2446
- if (!isBrowser$1()) return void console.warn("injectCSS: Not in browser environment, CSS not injected");
2447
- let styleElement = document.getElementById(id);
2448
- styleElement || (styleElement = document.createElement("style"), styleElement.id = id,
2449
- styleElement.setAttribute("data-atomix-theme", "true"), document.head.appendChild(styleElement)),
2450
- styleElement.textContent = css;
1364
+ * Calculate contrast ratio between two colors
1365
+ */ function getContrastRatio(foreground, background) {
1366
+ const lumA = getLuminance(foreground), lumB = getLuminance(background);
1367
+ return (Math.max(lumA, lumB) + .05) / (Math.min(lumA, lumB) + .05);
2451
1368
  }
2452
1369
 
2453
1370
  /**
2454
- * Remove injected CSS from DOM
2455
- *
2456
- * Removes the style element with the given ID from the document head.
2457
- *
2458
- * @param id - Style element ID to remove (default: 'atomix-theme')
2459
- *
2460
- * @example
2461
- * ```typescript
2462
- * removeCSS(); // Removes default 'atomix-theme'
2463
- * removeCSS('my-custom-theme'); // Removes custom ID
2464
- * ```
2465
- */ function removeCSS(id = "atomix-theme") {
2466
- if (!isBrowser$1()) return;
2467
- const styleElement = document.getElementById(id);
2468
- styleElement && styleElement.remove();
1371
+ * Get appropriate contrast text color (black or white) for a background color
1372
+ */ function getContrastText(background, threshold = 3) {
1373
+ const contrastWithWhite = getContrastRatio("#FFFFFF", background), contrastWithBlack = getContrastRatio("#000000", background);
1374
+ return contrastWithWhite >= threshold ? "#FFFFFF" : contrastWithBlack >= threshold ? "#000000" : contrastWithWhite > contrastWithBlack ? "#FFFFFF" : "#000000";
2469
1375
  }
2470
1376
 
2471
1377
  /**
2472
- * Check if CSS is already injected
1378
+ * Lighten a color by a given amount
2473
1379
  *
2474
- * @param id - Style element ID to check (default: 'atomix-theme')
2475
- * @returns True if style element exists
2476
- */ function isCSSInjected(id = "atomix-theme") {
2477
- return !!isBrowser$1() && null !== document.getElementById(id);
1380
+ * @param color - Hex color string
1381
+ * @param amount - Amount to lighten (0-1), default 0.2
1382
+ * @returns Lightened hex color
1383
+ */ function lighten(color, amount = .2) {
1384
+ const rgb = hexToRgb(color);
1385
+ if (!rgb) return color;
1386
+ const {r: r, g: g, b: b} = rgb, lightenValue = val => Math.min(255, Math.round(val + (255 - val) * amount));
1387
+ return rgbToHex(lightenValue(r), lightenValue(g), lightenValue(b));
2478
1388
  }
2479
1389
 
2480
1390
  /**
2481
- * CSS File Utilities
2482
- *
2483
- * Save CSS to file system (Node.js only).
2484
- */
2485
- /**
2486
- * Save CSS to file
2487
- *
2488
- * Writes CSS string to a file. Only works in Node.js environment.
2489
- *
2490
- * @param css - CSS string to save
2491
- * @param filePath - Output file path
2492
- * @throws Error if called in browser environment
1391
+ * Darken a color by a given amount
2493
1392
  *
2494
- * @example
2495
- * ```typescript
2496
- * const css = ':root { --atomix-color-primary: #7AFFD7; }';
2497
- * await saveCSSFile(css, './themes/custom.css');
2498
- * ```
2499
- */ async function saveCSSFile(css, filePath) {
2500
- // Check if in browser environment
2501
- if ("undefined" != typeof window) throw new Error("saveCSSFile can only be used in Node.js environment. Use injectCSS() for browser environments.");
2502
- // Dynamic import to avoid bundling Node.js modules in browser builds
2503
- const fs = await import("fs/promises"), dir = (await import("path")).dirname(filePath);
2504
- await fs.mkdir(dir, {
2505
- recursive: !0
2506
- }),
2507
- // Write file
2508
- await fs.writeFile(filePath, css, "utf8");
1393
+ * @param color - Hex color string
1394
+ * @param amount - Amount to darken (0-1), default 0.2
1395
+ * @returns Darkened hex color
1396
+ */ function darken(color, amount = .2) {
1397
+ const rgb = hexToRgb(color);
1398
+ if (!rgb) return color;
1399
+ const {r: r, g: g, b: b} = rgb, darkenValue = val => Math.max(0, Math.round(val * (1 - amount)));
1400
+ return rgbToHex(darkenValue(r), darkenValue(g), darkenValue(b));
2509
1401
  }
2510
1402
 
2511
1403
  /**
2512
- * Save CSS to file (synchronous version)
2513
- *
2514
- * Synchronous version of saveCSSFile. Only works in Node.js environment.
1404
+ * Add alpha (opacity) to a color
2515
1405
  *
2516
- * @param css - CSS string to save
2517
- * @param filePath - Output file path
2518
- * @throws Error if called in browser environment
2519
- */ function saveCSSFileSync(css, filePath) {
2520
- // Check if in browser environment
2521
- if ("undefined" != typeof window) throw new Error("saveCSSFileSync can only be used in Node.js environment. Use injectCSS() for browser environments.");
2522
- // Use require for synchronous file operations
2523
- // eslint-disable-next-line @typescript-eslint/no-require-imports
2524
- const fs = require("fs"), dir = require("path").dirname(filePath);
2525
- // eslint-disable-next-line @typescript-eslint/no-require-imports
2526
- fs.existsSync(dir) || fs.mkdirSync(dir, {
2527
- recursive: !0
2528
- }),
2529
- // Write file
2530
- fs.writeFileSync(filePath, css, "utf8");
1406
+ * @param color - Hex color string
1407
+ * @param opacity - Opacity value (0-1)
1408
+ * @returns RGBA color string
1409
+ */ function alpha(color, opacity) {
1410
+ const rgb = hexToRgb(color);
1411
+ if (!rgb) return color;
1412
+ const {r: r, g: g, b: b} = rgb;
1413
+ return `rgba(${r}, ${g}, ${b}, ${Math.max(0, Math.min(1, opacity))})`;
2531
1414
  }
2532
1415
 
2533
1416
  /**
2534
- * Check if code is running in a browser environment
2535
- */ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof document, isServer = () => !isBrowser(), getThemeLinkId = themeName => `atomix-theme-${themeName}`, buildThemePath = (themeName, basePath = "/themes", useMinified = !1, cdnPath = null) => {
2536
- // Validate theme name to prevent path injection
2537
- if (!isValidThemeName(themeName)) throw new Error(`Invalid theme name: "${themeName}". Theme names must be lowercase alphanumeric with hyphens.`);
2538
- const fileName = `${themeName}${useMinified ? ".min.css" : ".css"}`;
2539
- return cdnPath ? `${cdnPath.replace(/[<>"']/g, "")}/${fileName}` : `${basePath.replace(/\/$/, "").replace(/[<>"']/g, "")}/${fileName.replace(/^\//, "")}`;
2540
- // Ensure basePath doesn't end with slash and fileName doesn't start with slash
2541
- // Also sanitize basePath to prevent path injection
2542
- }, loadThemeCSS = (fullPath, linkId) => isServer() ? Promise.resolve() : new Promise(((resolve, reject) => {
2543
- if (document.getElementById(linkId)) return void resolve();
2544
- // Create link element
2545
- const link = document.createElement("link");
2546
- link.id = linkId, link.rel = "stylesheet", link.type = "text/css", link.href = fullPath,
2547
- // Add data attribute for tracking
2548
- link.setAttribute("data-atomix-theme", "true"),
2549
- // Handle load success
2550
- link.onload = () => {
2551
- resolve();
2552
- },
2553
- // Handle load error
2554
- link.onerror = () => {
2555
- // Remove failed link element
2556
- link.remove(), reject(new Error(`Failed to load theme CSS: ${fullPath}`));
2557
- },
2558
- // Append to head
2559
- document.head.appendChild(link);
2560
- })), isThemeLoaded = themeName => {
2561
- if (isServer()) return !1;
2562
- const linkId = getThemeLinkId(themeName);
2563
- return null !== document.getElementById(linkId);
2564
- }, isValidThemeName = themeName => !(!themeName || "string" != typeof themeName) && /^[a-z0-9]+(-[a-z0-9]+)*$/.test(themeName);
2565
-
2566
- /**
2567
- * Check if code is running on the server (SSR)
2568
- */
2569
- /**
2570
- * CSS Variable Generator
2571
- *
2572
- * Generates CSS custom properties from theme objects and injects them into the DOM.
2573
- *
2574
- * **Token Naming Alignment:**
2575
- * This generator produces CSS variables that match the SCSS token naming pattern exactly:
2576
- * - Colors: --atomix-primary, --atomix-primary-1 through --atomix-primary-10
2577
- * - Spacing: --atomix-spacing-1, --atomix-spacing-4, etc.
2578
- * - Typography: --atomix-font-size-base, --atomix-font-weight-normal, etc.
2579
- * - Shadows: --atomix-box-shadow, --atomix-box-shadow-sm, etc.
2580
- *
2581
- * All tokens follow the flat structure pattern used in SCSS (not nested like --atomix-palette-primary-main).
2582
- * This ensures compatibility between SCSS themes and JavaScript themes.
1417
+ * Emphasize a color (lighten if dark, darken if light)
2583
1418
  *
2584
- * @see src/styles/03-generic/_generic.root.scss for SCSS token definitions
2585
- */
2586
- /**
2587
- * Convert a nested object to flat CSS variable declarations
1419
+ * @param color - Hex color string
1420
+ * @param coefficient - Amount to emphasize (0-1), default 0.15
1421
+ * @returns Emphasized hex color
2588
1422
  */
2589
- function flattenObject(obj, prefix = "", result = {}) {
2590
- for (const key in obj) {
2591
- if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
2592
- const value = obj[key], newKey = prefix ? `${prefix}-${key}` : key;
2593
- if (value && "object" == typeof value && !Array.isArray(value)) {
2594
- // Skip special objects like functions
2595
- if ("function" == typeof value) continue;
2596
- // Recursively flatten nested objects
2597
- flattenObject(value, newKey, result);
2598
- } else "string" != typeof value && "number" != typeof value || (result[newKey.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase()] = String(value));
2599
- }
2600
- return result;
2601
- }
2602
-
2603
1423
  /**
2604
1424
  * Generate a color scale from a base color (1-10 steps)
2605
1425
  * Creates lighter to darker variations
2606
- */ function generateColorScale(baseColor, prefix, colorName) {
1426
+ */
1427
+ function generateColorScale(baseColor, prefix, colorName) {
2607
1428
  const vars = {};
2608
1429
  if (!hexToRgb(baseColor)) return vars;
2609
1430
  // Generate 10-step scale
@@ -2667,7 +1488,16 @@ function generateCSSVariables(theme, options = {}) {
2667
1488
  // Text emphasis: emphasized version of the color for text (--atomix-primary-text-emphasis)
2668
1489
  vars[`${prefix}-${key}-text-emphasis`] = function(color, coefficient = .15) {
2669
1490
  return getLuminance(color) > .5 ? darken(color, coefficient) : lighten(color, coefficient);
2670
- }(color.main, .15),
1491
+ }
1492
+ // ============================================================================
1493
+ // Spacing Utilities
1494
+ // ============================================================================
1495
+ /**
1496
+ * Create a spacing function from various input types
1497
+ *
1498
+ * @param spacingInput - Spacing configuration (number, array, or function), default 4
1499
+ * @returns Spacing function
1500
+ */ (color.main, .15),
2671
1501
  // Background subtle: very light version for backgrounds (--atomix-primary-bg-subtle)
2672
1502
  vars[`${prefix}-${key}-bg-subtle`] = alpha(color.main, .1),
2673
1503
  // Border subtle: light version for borders (--atomix-primary-border-subtle)
@@ -3012,7 +1842,52 @@ function generateCSSVariables(theme, options = {}) {
3012
1842
  return vars[`${prefix}-focus-ring-width`] = "3px", vars[`${prefix}-focus-ring-offset`] = "2px",
3013
1843
  vars[`${prefix}-focus-ring-opacity`] = "0.25", vars;
3014
1844
  }(theme.palette, prefix)), theme.custom && Object.keys(theme.custom).length > 0) {
3015
- const customVars = flattenObject(theme.custom, `${prefix}-custom`);
1845
+ const customVars =
1846
+ /**
1847
+ * CSS Variable Generator
1848
+ *
1849
+ * Generates CSS custom properties from theme objects and injects them into the DOM.
1850
+ *
1851
+ * **Token Naming Alignment:**
1852
+ * This generator produces CSS variables that match the SCSS token naming pattern exactly:
1853
+ * - Colors: --atomix-primary, --atomix-primary-1 through --atomix-primary-10
1854
+ * - Spacing: --atomix-spacing-1, --atomix-spacing-4, etc.
1855
+ * - Typography: --atomix-font-size-base, --atomix-font-weight-normal, etc.
1856
+ * - Shadows: --atomix-box-shadow, --atomix-box-shadow-sm, etc.
1857
+ *
1858
+ * All tokens follow the flat structure pattern used in SCSS (not nested like --atomix-palette-primary-main).
1859
+ * This ensures compatibility between SCSS themes and JavaScript themes.
1860
+ *
1861
+ * @see src/styles/03-generic/_generic.root.scss for SCSS token definitions
1862
+ */
1863
+ /**
1864
+ * Convert a nested object to flat CSS variable declarations
1865
+ * Uses iterative approach for better performance with large objects
1866
+ */
1867
+ function(obj, prefix = "", result = {}) {
1868
+ // Use iterative approach with stack to avoid deep recursion
1869
+ const stack = [ {
1870
+ obj: obj,
1871
+ prefix: prefix
1872
+ } ];
1873
+ for (;stack.length > 0; ) {
1874
+ const {obj: currentObj, prefix: currentPrefix} = stack.pop();
1875
+ for (const key in currentObj) {
1876
+ if (!Object.prototype.hasOwnProperty.call(currentObj, key)) continue;
1877
+ const value = currentObj[key], newKey = currentPrefix ? `${currentPrefix}-${key}` : key;
1878
+ if (value && "object" == typeof value && !Array.isArray(value)) {
1879
+ // Skip special objects like functions
1880
+ if ("function" == typeof value) continue;
1881
+ // Add to stack for iterative processing
1882
+ stack.push({
1883
+ obj: value,
1884
+ prefix: newKey
1885
+ });
1886
+ } else "string" != typeof value && "number" != typeof value || (result[newKey.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase()] = String(value));
1887
+ }
1888
+ }
1889
+ return result;
1890
+ }(theme.custom, `${prefix}-custom`);
3016
1891
  Object.assign(variables, customVars);
3017
1892
  }
3018
1893
  // Convert to CSS string
@@ -3033,243 +1908,211 @@ function generateCSSVariables(theme, options = {}) {
3033
1908
  styleElement.textContent = css;
3034
1909
  }
3035
1910
  /**
3036
- * Theme Context
1911
+ * Naming Utilities
3037
1912
  *
3038
- * React context for theme management
1913
+ * Provides consistent naming conventions across the theme system
3039
1914
  */
3040
1915
  /**
3041
- * Theme context with default values
1916
+ * Generate consistent CSS class names following BEM methodology
3042
1917
  */ (css, styleId), css;
3043
1918
  }
3044
1919
 
3045
- const ThemeContext = createContext(null);
1920
+ function generateClassName(block, element, modifiers) {
1921
+ let className = block;
1922
+ return element && (className += `__${element}`), modifiers && Object.entries(modifiers).forEach((([key, value]) => {
1923
+ value && (className += `--${key}`, "string" == typeof value && value !== key && (className += `-${value}`));
1924
+ })), className;
1925
+ }
3046
1926
 
3047
- ThemeContext.displayName = "ThemeContext";
1927
+ /**
1928
+ * Generate consistent CSS variable names
1929
+ */ function generateCSSVariableName(property, options = {}) {
1930
+ const {prefix: prefix = "atomix", component: component, variant: variant, state: state} = options, parts = [ prefix ];
1931
+ return component && parts.push(component), variant && parts.push(variant), state && parts.push(state),
1932
+ parts.push(property), `--${parts.join("-")}`;
1933
+ }
3048
1934
 
3049
1935
  /**
3050
- * Theme Applicator
3051
- *
3052
- * Applies theme configurations to the DOM, including CSS variables,
3053
- * component overrides, typography, spacing, and color palettes.
3054
- *
3055
- * Uses the unified theme system for CSS generation and injection.
3056
- */
1936
+ * Normalize theme tokens to consistent naming convention
1937
+ */ function normalizeThemeTokens(tokens) {
1938
+ const normalized = {};
1939
+ for (const [key, value] of Object.entries(tokens))
1940
+ // Recursively normalize nested objects
1941
+ normalized[key] = "object" == typeof value && null !== value ? normalizeThemeTokens(value) : value;
1942
+ return normalized;
1943
+ }
1944
+
3057
1945
  /**
3058
- * Theme applicator class for runtime theme application
1946
+ * Convert camelCase to kebab-case for CSS custom properties
1947
+ */ function camelToKebab(str) {
1948
+ return str.replace(/[A-Z]/g, (match => `-${match.toLowerCase()}`));
1949
+ }
1950
+
1951
+ /**
1952
+ * Convert theme property to CSS variable name
1953
+ */ function themePropertyToCSSVar(propertyPath, prefix = "atomix") {
1954
+ return `--${prefix}-${propertyPath.split(".").map((part => camelToKebab(part))).join("-")}`;
1955
+ }
1956
+
1957
+ /**
1958
+ * Component Theming Utilities
3059
1959
  *
3060
- * Uses the unified theme system for efficient CSS variable generation and injection.
1960
+ * Provides consistent patterns for applying theme values to components
1961
+ * using DesignTokens and CSS variables
3061
1962
  */
3062
- class ThemeApplicator {
3063
- constructor(root = document.documentElement) {
3064
- this.styleId = "atomix-theme-applicator", this.root = root;
3065
- }
3066
- /**
3067
- * Apply a complete theme configuration
3068
- *
3069
- * Uses the unified theme system to convert Theme to DesignTokens and inject CSS.
3070
- * Automatically respects atomix.config.ts when using DesignTokens.
3071
- */ applyTheme(theme) {
3072
- // Clear previously applied variables
3073
- this.clearAppliedVars(),
3074
- // Check if it's DesignTokens
3075
- this.isDesignTokens(theme) ?
3076
- // Direct DesignTokens - use unified theme system (with config support)
3077
- this.applyDesignTokens(theme) : injectCSS$1(createTheme(theme, {
3078
- selector: ":root",
3079
- prefix: "atomix"
3080
- }), this.styleId),
3081
- // Apply component overrides (only for Theme objects)
3082
- !this.isDesignTokens(theme) && theme.components && this.applyComponentOverrides(theme.components);
3083
- }
3084
- /**
3085
- * Apply DesignTokens using unified theme system
3086
- *
3087
- * Uses createTheme() which automatically loads from atomix.config.ts
3088
- * if no tokens are provided, ensuring config is always respected.
3089
- */ applyDesignTokens(tokens) {
3090
- // Inject CSS into DOM
3091
- injectCSS$1(createTheme(tokens, {
3092
- selector: ":root",
3093
- prefix: "atomix"
3094
- }), this.styleId);
3095
- }
3096
- /**
3097
- * Check if object is DesignTokens
3098
- */ isDesignTokens(obj) {
3099
- // DesignTokens is a flat object with string keys, no nested structures
3100
- return null !== obj && "object" == typeof obj && !("palette" in obj) && !("typography" in obj) && !("__isJSTheme" in obj);
3101
- }
3102
- /**
3103
- * Apply global CSS variables (for component overrides)
3104
- */ applyGlobalCSSVars(vars) {
3105
- Object.entries(vars).forEach((([key, value]) => {
3106
- this.root.style.setProperty(key, String(value));
3107
- }));
3108
- }
3109
- /**
3110
- * Apply component-level overrides
3111
- */ applyComponentOverrides(overrides) {
3112
- Object.entries(overrides).forEach((([componentName, override]) => {
3113
- override && this.applyComponentOverride(componentName, override);
3114
- }));
3115
- }
3116
- /**
3117
- * Apply override for a specific component
3118
- */ applyComponentOverride(componentName, override) {
3119
- const vars = {}, componentKey = componentName.toLowerCase();
3120
- // Apply component-level CSS variables
3121
- override.cssVars && Object.entries(override.cssVars).forEach((([key, value]) => {
3122
- // If key doesn't start with --, add component prefix
3123
- const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${key}`;
3124
- vars[varKey] = value;
3125
- })),
3126
- // Apply part-specific CSS variables
3127
- override.parts && Object.entries(override.parts).forEach((([partName, partOverride]) => {
3128
- partOverride.cssVars && Object.entries(partOverride.cssVars).forEach((([key, value]) => {
3129
- const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${partName}-${key}`;
3130
- vars[varKey] = value;
3131
- }));
3132
- })),
3133
- // Apply variant-specific CSS variables
3134
- override.variants && Object.entries(override.variants).forEach((([variantName, variantOverride]) => {
3135
- variantOverride.cssVars && Object.entries(variantOverride.cssVars).forEach((([key, value]) => {
3136
- const varKey = key.startsWith("--") ? key : `--atomix-${componentKey}-${variantName}-${key}`;
3137
- vars[varKey] = value;
3138
- }));
3139
- })), this.applyGlobalCSSVars(vars);
3140
- }
3141
- /**
3142
- * Clear all applied CSS variables
3143
- */ clearAppliedVars() {
3144
- removeCSS(this.styleId);
3145
- }
3146
- /**
3147
- * Remove theme application
3148
- */ removeTheme() {
3149
- this.clearAppliedVars(), removeCSS(this.styleId);
3150
- }
3151
- /**
3152
- * Update specific CSS variables without clearing all
3153
- */ updateCSSVars(vars) {
3154
- this.applyGlobalCSSVars(vars);
3155
- }
1963
+ /**
1964
+ * Get a theme value for a specific component using CSS variables
1965
+ * This ensures all components access theme values consistently
1966
+ */ function getComponentThemeValue(component, property, variant, size) {
1967
+ // Build CSS variable name following consistent pattern
1968
+ const parts = [ "atomix", component ];
1969
+ // Return CSS variable reference with fallback
1970
+ return variant && parts.push(variant), size && parts.push(size), parts.push(property),
1971
+ `var(--${parts.join("-")}, var(--atomix-${property}, initial))`;
3156
1972
  }
3157
1973
 
3158
1974
  /**
3159
- * Global theme applicator instance
3160
- */ let globalApplicator = null;
1975
+ * Generate component-specific CSS variables from DesignTokens
1976
+ */ function generateComponentCSSVars(component, tokens, variant, size) {
1977
+ const vars = {};
1978
+ if (!tokens) return vars;
1979
+ const prefixParts = [ "atomix", component ];
1980
+ variant && prefixParts.push(variant), size && prefixParts.push(size);
1981
+ const prefix = prefixParts.join("-");
1982
+ // Map common DesignTokens to component-specific CSS variables
1983
+ return tokens.primary && (vars[`--${prefix}-color`] = tokens.primary), tokens["primary-9"] && (vars[`--${prefix}-color-hover`] = tokens["primary-9"]),
1984
+ tokens["body-color"] && (vars[`--${prefix}-color-disabled`] = tokens["body-color"]),
1985
+ tokens["body-font-family"] && (vars[`--${prefix}-font-family`] = tokens["body-font-family"]),
1986
+ tokens["body-font-size"] && (vars[`--${prefix}-font-size`] = tokens["body-font-size"]),
1987
+ tokens["spacing-1"] && (vars[`--${prefix}-spacing-sm`] = tokens["spacing-1"]), tokens["spacing-2"] && (vars[`--${prefix}-spacing-md`] = tokens["spacing-2"]),
1988
+ tokens["spacing-4"] && (vars[`--${prefix}-spacing-lg`] = tokens["spacing-4"]), vars;
1989
+ }
3161
1990
 
3162
1991
  /**
3163
- * Get or create global theme applicator
3164
- */ function getThemeApplicator() {
3165
- return globalApplicator || (globalApplicator = new ThemeApplicator), globalApplicator;
1992
+ * Apply consistent theme to component style object using DesignTokens
1993
+ */ function applyComponentTheme(component, style = {}, variant, size, tokens) {
1994
+ // If no tokens provided, return original style
1995
+ return tokens ? {
1996
+ ...generateComponentCSSVars(component, tokens, variant, size),
1997
+ ...style
1998
+ } : style;
1999
+ // Generate component-specific CSS variables
3166
2000
  }
3167
2001
 
3168
2002
  /**
3169
- * Apply theme using global applicator
3170
- */ function applyTheme(theme) {
3171
- getThemeApplicator().applyTheme(theme);
2003
+ * Create a hook for consistent component theming
2004
+ */ function useComponentTheme(component, variant, size, tokens) {
2005
+ return property => getComponentThemeValue(component, property, variant, size);
3172
2006
  }
3173
2007
 
3174
2008
  /**
3175
- * ThemeProvider component
3176
- *
3177
- * Provides theme context to child components and manages theme state.
2009
+ * Theme Configuration Loader
3178
2010
  *
3179
- * **Config-First Approach**: If `defaultTheme` is not provided, loads from `atomix.config.ts`.
3180
- * Config file is required when `defaultTheme` is not provided.
2011
+ * Provides functions to load theme configurations from atomix.config.ts
2012
+ * Includes both sync and async versions, with automatic fallbacks
2013
+ */
2014
+ /**
2015
+ * Load theme from config file (synchronous, Node.js only)
2016
+ * @param configPath - Path to config file (default: atomix.config.ts)
2017
+ * @returns DesignTokens from theme configuration
2018
+ * @throws Error if config loading is not available in browser environment
2019
+ */ function loadThemeFromConfigSync(options) {
2020
+ // Check if we're in a browser environment
2021
+ if ("undefined" != typeof window) throw new Error("loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.");
2022
+ // Use static import - the function handles browser environment checks internally
2023
+ let config;
2024
+ try {
2025
+ config = loadAtomixConfig({
2026
+ configPath: options?.configPath || "atomix.config.ts",
2027
+ required: !1 !== options?.required
2028
+ });
2029
+ } catch (error) {
2030
+ if (!1 !== options?.required) throw new Error("Config loader module not available");
2031
+ // Return empty tokens if config is not required
2032
+ return createTokens({});
2033
+ }
2034
+ if (!config?.theme) return createTokens({});
2035
+ // Extract tokens from config.theme structure
2036
+ // config.theme can have: { extend?: ThemeTokens, tokens?: ThemeTokens, themes?: ... }
2037
+ // We need to extract the actual DesignTokens (flat structure)
2038
+ const themeConfig = config.theme;
2039
+ // Check if theme is directly a flat object (DesignTokens format)
2040
+ // This handles the case where config.theme might be passed as DesignTokens directly
2041
+ return createTokens(!themeConfig || "object" != typeof themeConfig || "extend" in themeConfig || "tokens" in themeConfig || "themes" in themeConfig ? {} : themeConfig);
2042
+ // If theme has nested structure (extend/tokens/themes), we can't directly use it
2043
+ // Return empty tokens - the theme system will use defaults
2044
+ // TODO: Add proper conversion from ThemeTokens to DesignTokens if needed
2045
+ }
2046
+
2047
+ /**
2048
+ * Load theme from config file (asynchronous)
2049
+ * @param configPath - Path to config file (default: atomix.config.ts)
2050
+ * @returns Promise resolving to DesignTokens from theme configuration
2051
+ */ async function loadThemeFromConfig(options) {
2052
+ // Check if we're in a browser environment
2053
+ if ("undefined" != typeof window) throw new Error("loadThemeFromConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.");
2054
+ // Use static import with runtime check
2055
+ // The function will handle browser environment checks internally
2056
+ let config;
2057
+ try {
2058
+ // loadAtomixConfig is synchronous, not async
2059
+ config = loadAtomixConfig({
2060
+ configPath: options?.configPath || "atomix.config.ts",
2061
+ required: !1 !== options?.required
2062
+ });
2063
+ } catch (error) {
2064
+ if (!1 !== options?.required) throw new Error("Config loader module not available");
2065
+ // Return empty tokens if config is not required
2066
+ return createTokens({});
2067
+ }
2068
+ if (!config?.theme) return createTokens({});
2069
+ // Extract tokens from config.theme structure
2070
+ // config.theme can have: { extend?: ThemeTokens, tokens?: ThemeTokens, themes?: ... }
2071
+ // We need to extract the actual DesignTokens (flat structure)
2072
+ const themeConfig = config.theme;
2073
+ // Check if theme is directly a flat object (DesignTokens format)
2074
+ // This handles the case where config.theme might be passed as DesignTokens directly
2075
+ return createTokens(!themeConfig || "object" != typeof themeConfig || "extend" in themeConfig || "tokens" in themeConfig || "themes" in themeConfig ? {} : themeConfig);
2076
+ // If theme has nested structure (extend/tokens/themes), we can't directly use it
2077
+ // Return empty tokens - the theme system will use defaults
2078
+ // TODO: Add proper conversion from ThemeTokens to DesignTokens if needed
2079
+ }
2080
+
2081
+ /**
2082
+ * Theme Context
3181
2083
  *
3182
- * @example
3183
- * ```tsx
3184
- * import { ThemeProvider } from '@shohojdhara/atomix/theme';
2084
+ * React context for theme management
2085
+ */
2086
+ /**
2087
+ * Theme context with default values
2088
+ */ const ThemeContext = createContext(null);
2089
+
2090
+ ThemeContext.displayName = "ThemeContext";
2091
+
2092
+ /**
2093
+ * Theme Provider
3185
2094
  *
3186
- * // Loads from atomix.config.ts (config file required)
3187
- * function App() {
3188
- * return (
3189
- * <ThemeProvider>
3190
- * <YourApp />
3191
- * </ThemeProvider>
3192
- * );
3193
- * }
2095
+ * React context provider for theme management with separated concerns.
2096
+ * Simplified version focusing on core functionality:
2097
+ * - String-based themes (CSS files)
2098
+ * - DesignTokens (dynamic themes)
2099
+ * - Persistence via localStorage
3194
2100
  *
3195
- * // Provide explicit theme (bypasses config)
3196
- * function App() {
3197
- * return (
3198
- * <ThemeProvider defaultTheme="dark">
3199
- * <YourApp />
3200
- * </ThemeProvider>
3201
- * );
3202
- * }
3203
- * ```
3204
- */ const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes: themes = {}, basePath: basePath = "/themes", cdnPath: cdnPath = null, preload: preload = [], lazy: lazy = !0, storageKey: storageKey = "atomix-theme", dataAttribute: dataAttribute = "data-theme", enablePersistence: enablePersistence = !0, useMinified: useMinified = !1, onThemeChange: onThemeChange, onError: onError}) => {
2101
+ * Falls back to 'default' theme if no configuration is found.
2102
+ */
2103
+ const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes: themes = {}, basePath: basePath = "/themes", cdnPath: cdnPath = null, useMinified: useMinified = !1, storageKey: storageKey = "atomix-theme", dataAttribute: dataAttribute = "data-theme", enablePersistence: enablePersistence = !0, onThemeChange: onThemeChange, onError: onError}) => {
3205
2104
  // Store callbacks in refs to avoid recreating when they change
3206
2105
  const onThemeChangeRef = useRef(onThemeChange), onErrorRef = useRef(onError);
3207
- // Update refs when callbacks change
2106
+ // Update ref when callback changes
3208
2107
  useEffect((() => {
3209
2108
  onThemeChangeRef.current = onThemeChange, onErrorRef.current = onError;
3210
2109
  }), [ onThemeChange, onError ]);
3211
- // Create stable wrapper functions that read from refs
2110
+ // Create stable wrapper functions that read from ref
3212
2111
  const handleThemeChange = useCallback((theme => {
3213
2112
  onThemeChangeRef.current?.(theme);
3214
2113
  }), []), handleError = useCallback(((error, themeName) => {
3215
2114
  onErrorRef.current?.(error, themeName);
3216
- }), []), themesRef = useRef(themes), themesStable = useMemo((() => {
3217
- // Only update if themes object actually changed (shallow comparison)
3218
- const currentKeys = Object.keys(themes), prevKeys = Object.keys(themesRef.current);
3219
- return currentKeys.length !== prevKeys.length || currentKeys.some((key => themes[key] !== themesRef.current[key])) ? (themesRef.current = themes,
3220
- themes) : themesRef.current;
3221
- }), [ themes ]), logger = useMemo((() => getLogger()), []), registry = useMemo((() => {
3222
- const reg = new ThemeRegistry;
3223
- // Register themes from props
3224
- if (themesStable && Object.keys(themesStable).length > 0) for (const [themeId, metadata] of Object.entries(themesStable)) reg.has(themeId) || reg.register(themeId, {
3225
- type: "css",
3226
- name: metadata.name,
3227
- class: metadata.class || themeId,
3228
- description: metadata.description,
3229
- author: metadata.author,
3230
- version: metadata.version,
3231
- tags: metadata.tags,
3232
- supportsDarkMode: metadata.supportsDarkMode,
3233
- status: metadata.status,
3234
- a11y: metadata.a11y,
3235
- color: metadata.color,
3236
- features: metadata.features,
3237
- dependencies: metadata.dependencies
3238
- });
3239
- return reg;
3240
- }), [ themesStable ]), storageAdapter = useMemo((() => ({
3241
- getItem: key => {
3242
- if (isServer()) return null;
3243
- try {
3244
- return localStorage.getItem(key);
3245
- } catch {
3246
- return null;
3247
- }
3248
- },
3249
- setItem: (key, value) => {
3250
- if (!isServer()) try {
3251
- localStorage.setItem(key, value);
3252
- } catch {
3253
- // Silently fail if localStorage is not available
3254
- }
3255
- },
3256
- removeItem: key => {
3257
- if (!isServer()) try {
3258
- localStorage.removeItem(key);
3259
- } catch {
3260
- // Silently fail
3261
- }
3262
- },
3263
- isAvailable: () => {
3264
- if (isServer()) return !1;
3265
- try {
3266
- const test = "__atomix_storage_test__";
3267
- return localStorage.setItem(test, test), localStorage.removeItem(test), !0;
3268
- } catch {
3269
- return !1;
3270
- }
3271
- }
3272
- })), []), themeApplicator = useMemo((() => isServer() ? null : new ThemeApplicator), []), initialDefaultTheme = useMemo((() => {
2115
+ }), []), storageAdapter = useMemo((() => createLocalStorageAdapter()), []), initialDefaultTheme = useMemo((() => {
3273
2116
  // Check storage first
3274
2117
  if (enablePersistence && storageAdapter.isAvailable()) {
3275
2118
  const stored = storageAdapter.getItem(storageKey);
@@ -3277,193 +2120,169 @@ class ThemeApplicator {
3277
2120
  }
3278
2121
  // If defaultTheme is provided, use it
3279
2122
  if (null != defaultTheme) return defaultTheme;
3280
- // Load from atomix.config.ts (required)
3281
- const configTokens = loadThemeFromConfigSync();
3282
- return configTokens && Object.keys(configTokens).length > 0 ? configTokens : null;
3283
- // Config is required - this will be caught in useEffect
3284
- }), [ enablePersistence, storageAdapter, storageKey, defaultTheme ]), [currentTheme, setCurrentTheme] = useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : isJSTheme(initialDefaultTheme) ? initialDefaultTheme.name || "js-theme" : initialDefaultTheme && "object" == typeof initialDefaultTheme && !isJSTheme(initialDefaultTheme) ? "config-theme" : "" // No default theme - use built-in styles
3285
- )), [activeTheme, setActiveTheme] = useState((() => isJSTheme(initialDefaultTheme) ? initialDefaultTheme : null)), [availableThemes, setAvailableThemes] = useState((() => registry.getAllMetadata().map((meta => ({
3286
- name: meta.name || "",
3287
- class: meta.class,
3288
- description: meta.description,
3289
- author: meta.author,
3290
- version: meta.version,
3291
- tags: meta.tags,
3292
- supportsDarkMode: meta.supportsDarkMode,
3293
- status: meta.status,
3294
- a11y: meta.a11y,
3295
- color: meta.color,
3296
- features: meta.features,
3297
- dependencies: meta.dependencies
3298
- }))))), [isLoading, setIsLoading] = useState(!1), [error, setError] = useState(null), loadedThemesRef = useRef(new Set), previousThemeRef = useRef(null);
3299
- // Get default theme (with automatic config loading)
3300
- useCallback((() => {
3301
- // Check storage first
3302
- if (enablePersistence && storageAdapter.isAvailable()) {
3303
- const stored = storageAdapter.getItem(storageKey);
3304
- if (stored) return stored;
2123
+ // Try to load from atomix.config.ts as fallback, but only in Node.js/SSR environments
2124
+ if ("undefined" == typeof window) try {
2125
+ // Dynamically import the config loader to avoid bundling issues in browser
2126
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
2127
+ const {loadThemeFromConfigSync: loadThemeFromConfigSync} = require("../config/configLoader"), configTokens = loadThemeFromConfigSync();
2128
+ if (configTokens && Object.keys(configTokens).length > 0)
2129
+ // For simplicity, we'll treat config tokens as a special theme name
2130
+ return "config-theme";
2131
+ } catch (error) {
2132
+ // Failed to load theme from config, using default
3305
2133
  }
3306
- // If defaultTheme is provided, use it
3307
- if (null != defaultTheme) return defaultTheme;
3308
- // Load from atomix.config.ts (required)
3309
- // Config file must exist - throws error if not found
3310
- const configTokens = loadThemeFromConfigSync();
3311
- if (configTokens && Object.keys(configTokens).length > 0)
3312
- // Return config tokens as Partial<DesignTokens>
3313
- return configTokens;
3314
- throw new Error("ThemeProvider: atomix.config.ts is required when defaultTheme is not provided.");
3315
- }), [ enablePersistence, storageAdapter, storageKey, defaultTheme ]);
3316
- // Apply JS theme (supports both Theme and DesignTokens)
3317
- const applyJSTheme = useCallback((async (theme, removePrevious = !0) => {
3318
- !isServer() && themeApplicator && (removePrevious && (
3319
- // Remove previous theme
3320
- removeCSS("atomix-theme"),
3321
- // Also remove any existing CSS variables
3322
- activeTheme && activeTheme.cssVars && Object.keys(activeTheme.cssVars).forEach((key => {
3323
- document.documentElement.style.removeProperty(key);
3324
- }))), null === theme || "object" != typeof theme || "palette" in theme || "typography" in theme || "__isJSTheme" in theme ?
3325
- // Use ThemeApplicator for Theme objects
3326
- themeApplicator?.applyTheme(theme) : injectCSS$1(createTheme(theme), "atomix-theme"));
3327
- }), [ activeTheme, themeApplicator ]), setTheme = useCallback((async (theme, options) => {
3328
- const {removePrevious: removePrevious = !0, fallbackOnError: fallbackOnError = !0, customPath: customPath} = options || {};
3329
- setIsLoading(!0), setError(null);
2134
+ // Default fallback
2135
+ return "default";
2136
+ }), [ defaultTheme, enablePersistence, storageKey ]), [currentTheme, setCurrentTheme] = useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : "tokens-theme")), [activeTokens, setActiveTokens] = useState((() => {
2137
+ // If defaultTheme is DesignTokens, store them
2138
+ if (defaultTheme && "string" != typeof defaultTheme) {
2139
+ const {createTokens: createTokens} = require("../tokens/tokens");
2140
+ return createTokens(defaultTheme);
2141
+ }
2142
+ return null;
2143
+ })), [isLoading, setIsLoading] = useState(!1), [error, setError] = useState(null), loadedThemesRef = useRef(new Set), themePromisesRef = useRef({}), abortControllerRef = useRef(null);
2144
+ // Handle initial DesignTokens defaultTheme
2145
+ useEffect((() => {
2146
+ defaultTheme && "string" != typeof defaultTheme && activeTokens && !isServer() && injectCSS$1(createTheme(defaultTheme), "theme-tokens-theme");
2147
+ }), [ defaultTheme, activeTokens ]), // Run when defaultTheme or activeTokens change
2148
+ // Apply initial theme attributes to document element
2149
+ useEffect((() => {
2150
+ isServer() || applyThemeAttributes(String(currentTheme), dataAttribute);
2151
+ }), [ currentTheme, dataAttribute ]),
2152
+ // Handle theme persistence
2153
+ useEffect((() => {
2154
+ enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, String(currentTheme));
2155
+ }), [ currentTheme, storageKey, enablePersistence, storageAdapter ]),
2156
+ // Cleanup: Remove completed promises and abort controllers on unmount
2157
+ useEffect((() => () => {
2158
+ // Cancel any in-flight theme loads
2159
+ abortControllerRef.current && (abortControllerRef.current.abort(), abortControllerRef.current = null),
2160
+ Object.entries(themePromisesRef.current).forEach((([key, promise]) => {})),
2161
+ // Clear all on unmount
2162
+ themePromisesRef.current = {};
2163
+ }), []);
2164
+ // Function to set theme with proper type handling
2165
+ const setTheme = useCallback((async (theme, options) => {
2166
+ // Cancel previous theme load if in progress
2167
+ abortControllerRef.current && abortControllerRef.current.abort();
2168
+ // Create new AbortController for this theme load
2169
+ const abortController = new AbortController;
2170
+ abortControllerRef.current = abortController, setIsLoading(!0), setError(null);
3330
2171
  try {
3331
- // Handle Theme or DesignTokens object directly
2172
+ let themeName;
3332
2173
  if ("string" != typeof theme) {
3333
- if (null !== theme && "object" == typeof theme && !("palette" in theme) && !("typography" in theme) && !("__isJSTheme" in theme)) {
3334
- // Handle DesignTokens using unified theme system
3335
- await applyJSTheme(theme, removePrevious);
3336
- const themeName = "design-tokens-theme";
3337
- return previousThemeRef.current = currentTheme, setCurrentTheme(themeName), setActiveTheme(null),
3338
- previousThemeRef.current, Date.now(), handleThemeChange(themeName),
3339
- // Persist to storage
3340
- enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, themeName),
3341
- void setIsLoading(!1);
3342
- }
3343
- if (isJSTheme(theme)) {
3344
- // Handle Theme object
3345
- await applyJSTheme(theme, removePrevious);
3346
- const themeName = theme.name || "js-theme";
3347
- return previousThemeRef.current = currentTheme, setCurrentTheme(themeName), setActiveTheme(theme),
3348
- previousThemeRef.current, Date.now(), handleThemeChange(theme),
3349
- // Persist to storage
3350
- enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, themeName),
2174
+ // Check if aborted before processing
2175
+ if (abortController.signal.aborted) return;
2176
+ // For DesignTokens, create CSS and inject it
2177
+ const {createTheme: createTheme} = await Promise.resolve().then((() => index)), css = createTheme(theme), themeId = "tokens-theme";
2178
+ // Check if aborted after async operation
2179
+ if (abortController.signal.aborted) return;
2180
+ // Remove any previously loaded theme CSS
2181
+ removeCSS(`theme-${currentTheme}`),
2182
+ // Inject new theme CSS
2183
+ injectCSS$1(css, `theme-${themeId}`);
2184
+ // Store tokens for reference
2185
+ const {createTokens: createTokens} = await Promise.resolve().then((() => tokens)), fullTokens = createTokens(theme);
2186
+ // Check if aborted before state update
2187
+ if (abortController.signal.aborted) return;
2188
+ return setActiveTokens(fullTokens), setCurrentTheme(themeId), handleThemeChange(fullTokens),
2189
+ void setIsLoading(!1);
2190
+ }
2191
+ // If it's a string theme name, load the associated CSS
2192
+ if (themeName = theme, "string" == typeof theme && themes[theme]) {
2193
+ // Check if theme is already loading
2194
+ if (themePromisesRef.current[theme]) try {
2195
+ // Check if aborted
2196
+ if (await themePromisesRef.current[theme], abortController.signal.aborted) return;
2197
+ return setCurrentTheme(theme), setActiveTokens(null), handleThemeChange(theme),
3351
2198
  void setIsLoading(!1);
2199
+ } catch {
2200
+ // If previous load failed, continue with new load
3352
2201
  }
3353
- {
3354
- const error = new Error("Invalid theme object provided");
3355
- throw handleError(error, "js-theme"), setError(error), setIsLoading(!1), error;
2202
+ // Load CSS theme
2203
+ const themeLoadPromise = new Promise((async (resolve, reject) => {
2204
+ try {
2205
+ // Check if aborted
2206
+ if (abortController.signal.aborted) return void resolve();
2207
+ if (!themes[theme]) throw new Error(`Theme metadata not found for theme: ${theme}`);
2208
+ {
2209
+ // Build CSS path using utility function
2210
+ const cssPath = buildThemePath(theme, basePath, useMinified, cdnPath);
2211
+ // Check if aborted
2212
+ if (abortController.signal.aborted) return void resolve();
2213
+ // Load CSS file (using loadThemeCSS from domUtils)
2214
+ const {loadThemeCSS: loadThemeCSS} = await Promise.resolve().then((() => domUtils));
2215
+ // Check if aborted after async operation
2216
+ if (await loadThemeCSS(cssPath, `theme-${theme}`), abortController.signal.aborted) return void resolve();
2217
+ // Remove any previously loaded theme CSS
2218
+ removeCSS(`theme-${String(currentTheme)}`), loadedThemesRef.current.add(theme),
2219
+ setCurrentTheme(theme), setActiveTokens(null), handleThemeChange(theme), resolve();
2220
+ }
2221
+ } catch (err) {
2222
+ // Don't reject if aborted
2223
+ if (abortController.signal.aborted) return void resolve();
2224
+ const error = err instanceof Error ? err : new Error(String(err));
2225
+ setError(error), handleError(error, String(theme)), reject(error);
2226
+ }
2227
+ }));
2228
+ themePromisesRef.current[theme] = themeLoadPromise;
2229
+ try {
2230
+ await themeLoadPromise;
2231
+ } catch {
2232
+ // Error already handled in promise
3356
2233
  }
2234
+ // Clean up completed promise after a delay to prevent memory leak
2235
+ setTimeout((() => {
2236
+ themePromisesRef.current[theme] === themeLoadPromise && delete themePromisesRef.current[theme];
2237
+ }), 1e3);
2238
+ } else {
2239
+ // Check if aborted
2240
+ if (abortController.signal.aborted) return;
2241
+ // For string theme that isn't in our themes record, just set the name
2242
+ setCurrentTheme(themeName), setActiveTokens(null), handleThemeChange(themeName);
3357
2243
  }
3358
- // Check if theme exists
3359
- if (!registry.has(theme)) {
3360
- const error = new Error(`Theme "${theme}" not found in registry`);
3361
- if (handleError(error, theme), setError(error), fallbackOnError && currentTheme) return void setIsLoading(!1);
3362
- throw setIsLoading(!1), error;
3363
- }
3364
- // Load theme CSS if needed
3365
- const themePath = customPath || buildThemePath(theme, basePath, useMinified, cdnPath || void 0), linkId = getThemeLinkId(theme);
3366
- // Remove previous theme if requested
3367
- removePrevious && previousThemeRef.current && previousThemeRef.current !== theme && (themeNameOrLinkId => {
3368
- if (isServer()) return;
3369
- // Try as link ID first, then as theme name
3370
- let link = document.getElementById(themeNameOrLinkId);
3371
- if (!link) {
3372
- const linkId = getThemeLinkId(themeNameOrLinkId);
3373
- link = document.getElementById(linkId);
3374
- }
3375
- link && link.remove();
3376
- })(previousThemeRef.current),
3377
- // Load CSS if not already loaded
3378
- isThemeLoaded(theme) || (await loadThemeCSS(themePath, linkId), loadedThemesRef.current.add(theme)),
3379
- // Apply theme attributes
3380
- ((dataAttribute, themeName) => {
3381
- isServer() || (
3382
- // Set data attribute on body
3383
- document.body.setAttribute(dataAttribute, themeName),
3384
- // Also set on documentElement for broader compatibility
3385
- document.documentElement.setAttribute(dataAttribute, themeName));
3386
- })(dataAttribute, theme),
3387
- // Update state
3388
- previousThemeRef.current = currentTheme, setCurrentTheme(theme), setActiveTheme(null),
3389
- previousThemeRef.current, Date.now(), handleThemeChange(theme),
3390
- // Persist to storage
3391
- enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, theme),
3392
- setIsLoading(!1);
3393
2244
  } catch (err) {
2245
+ // Don't set error if aborted
2246
+ if (abortController.signal.aborted) return;
3394
2247
  const error = err instanceof Error ? err : new Error(String(err));
3395
- throw handleError(error, "string" == typeof theme ? theme : "js-theme"), setError(error),
3396
- setIsLoading(!1), err;
3397
- }
3398
- }), [ registry, basePath, cdnPath, useMinified, dataAttribute, enablePersistence, storageAdapter, storageKey, currentTheme, activeTheme, applyJSTheme, handleThemeChange, handleError ]), preloadTheme = useCallback((async themeName => {
3399
- if (!isServer() && !isThemeLoaded(themeName)) {
3400
- setIsLoading(!0);
3401
- try {
3402
- if (!registry.has(themeName)) throw new Error(`Theme "${themeName}" not found in registry`);
3403
- const themePath = buildThemePath(themeName, basePath, useMinified, cdnPath || void 0), linkId = getThemeLinkId(themeName);
3404
- await loadThemeCSS(themePath, linkId), loadedThemesRef.current.add(themeName);
3405
- } catch (err) {
3406
- const error = err instanceof Error ? err : new Error(String(err));
3407
- handleError(error, themeName), setError(error);
3408
- } finally {
3409
- setIsLoading(!1);
3410
- }
2248
+ setError(error), handleError(error, String(theme));
2249
+ } finally {
2250
+ // Only update loading state if not aborted
2251
+ abortController.signal.aborted || setIsLoading(!1);
3411
2252
  }
3412
- }), [ registry, basePath, cdnPath, useMinified, handleError ]), isThemeLoaded$1 = useCallback((themeName => isThemeLoaded(themeName)), []);
3413
- // Set theme function (supports string, Theme, or DesignTokens)
3414
- // Initialize default theme on mount
3415
- useEffect((() => {
3416
- isServer() || (async () => {
3417
- // Use the initial default theme we computed
3418
- const defaultThemeValue = initialDefaultTheme;
3419
- if (defaultThemeValue) try {
3420
- null === defaultThemeValue || "object" != typeof defaultThemeValue || "palette" in defaultThemeValue || "typography" in defaultThemeValue || "__isJSTheme" in defaultThemeValue || "string" == typeof defaultThemeValue ?
3421
- // Handle string or Theme object
3422
- await setTheme(defaultThemeValue, {
3423
- removePrevious: !1,
3424
- fallbackOnError: !0
3425
- }) : (
3426
- // Apply config tokens directly
3427
- await applyJSTheme(defaultThemeValue, !1),
3428
- // Update state and emit events
3429
- setCurrentTheme("config-theme"), setActiveTheme(null), Date.now(), handleThemeChange("config-theme"),
3430
- // Persist to storage
3431
- enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, "config-theme"));
3432
- } catch (err) {
3433
- const error = err instanceof Error ? err : new Error(String(err));
3434
- throw logger.error("Failed to load theme from config", error, {
3435
- theme: defaultThemeValue
3436
- }), handleError(error, "config-theme"), setError(error), error;
3437
- }
3438
- })();
3439
- }
3440
- // eslint-disable-next-line react-hooks/exhaustive-deps
3441
- ), []), // Only run once on mount - initialDefaultTheme is stable
3442
- // Preload themes
3443
- useEffect((() => {
3444
- !isServer() && preload && 0 !== preload.length && (async () => {
3445
- for (const themeName of preload) if (!isThemeLoaded(themeName)) try {
3446
- await preloadTheme(themeName);
2253
+ }), [ themes, currentTheme, handleThemeChange, handleError, basePath, useMinified, cdnPath ]), isThemeLoaded = useCallback((themeName => loadedThemesRef.current.has(themeName)), []), preloadTheme = useCallback((async themeName => {
2254
+ if (themes[themeName] && !isThemeLoaded(themeName)) {
2255
+ setIsLoading(!0);
2256
+ try {
2257
+ // Build CSS path using utility function
2258
+ const cssPath = buildThemePath(themeName, basePath, useMinified, cdnPath);
2259
+ // Preload CSS by fetching it
2260
+ await fetch(cssPath), loadedThemesRef.current.add(themeName);
3447
2261
  } catch (err) {
3448
- // Silently fail for preload
3449
- logger.warn(`Failed to preload theme "${themeName}"`, {
3450
- error: err instanceof Error ? err.message : String(err)
3451
- });
2262
+ const error = err instanceof Error ? err : new Error(String(err));
2263
+ setError(error), handleError(error, themeName);
2264
+ } finally {
2265
+ setIsLoading(!1);
3452
2266
  }
3453
- })();
3454
- }), [ preload, preloadTheme, logger ]);
3455
- // Context value
3456
- const contextValue = useMemo((() => ({
2267
+ }
2268
+ }), [ themes, isThemeLoaded, handleError, basePath, useMinified, cdnPath ]), themeManager = useMemo((() => ({})), []), availableThemes = useMemo((() => Object.entries(themes).map((([name, metadata]) => ({
2269
+ ...metadata,
2270
+ name: name
2271
+ })))), [ themes ]), contextValue = useMemo((() => ({
3457
2272
  theme: currentTheme,
3458
- activeTheme: activeTheme,
2273
+ activeTokens: activeTokens,
3459
2274
  setTheme: setTheme,
3460
2275
  availableThemes: availableThemes,
3461
2276
  isLoading: isLoading,
3462
2277
  error: error,
3463
- isThemeLoaded: isThemeLoaded$1,
3464
- preloadTheme: preloadTheme
3465
- })), [ currentTheme, activeTheme, setTheme, availableThemes, isLoading, error, isThemeLoaded$1, preloadTheme ]);
3466
- return jsx(ThemeContext.Provider, {
2278
+ isThemeLoaded: isThemeLoaded,
2279
+ preloadTheme: preloadTheme,
2280
+ themeManager: themeManager
2281
+ })), [ currentTheme, activeTokens, setTheme, availableThemes,
2282
+ // Use memoized value
2283
+ isLoading, error, isThemeLoaded, preloadTheme, themeManager ]);
2284
+ // Check if theme is loaded
2285
+ return jsx(ThemeContext.Provider, {
3467
2286
  value: contextValue,
3468
2287
  children: children
3469
2288
  });
@@ -3499,7 +2318,7 @@ class ThemeApplicator {
3499
2318
  if (!context) throw new Error("useTheme must be used within a ThemeProvider");
3500
2319
  return {
3501
2320
  theme: context.theme,
3502
- activeTheme: context.activeTheme,
2321
+ activeTokens: context.activeTokens,
3503
2322
  setTheme: context.setTheme,
3504
2323
  availableThemes: context.availableThemes,
3505
2324
  isLoading: context.isLoading,
@@ -3509,6 +2328,89 @@ class ThemeApplicator {
3509
2328
  };
3510
2329
  }
3511
2330
 
2331
+ function useThemeTokens() {
2332
+ const {theme: theme, activeTokens: activeTokens} = useTheme(), getToken = useCallback(((tokenName, fallback) => {
2333
+ if ("undefined" == typeof window) return fallback || "";
2334
+ const cssVarName = `--atomix-${tokenName}`;
2335
+ return getComputedStyle(document.documentElement).getPropertyValue(cssVarName).trim() || fallback || "";
2336
+ }), []);
2337
+ // Helper function to get CSS variable value
2338
+ // Return unified API for accessing theme values
2339
+ // Note: For SSR or direct token access, use activeTokens directly
2340
+ return {
2341
+ theme: theme,
2342
+ activeTokens: activeTokens,
2343
+ getToken: getToken,
2344
+ // Commonly used tokens with fallbacks
2345
+ colors: {
2346
+ primary: getToken("primary", "#3b82f6"),
2347
+ secondary: getToken("secondary", "#10b981"),
2348
+ error: getToken("error", "#ef4444"),
2349
+ success: getToken("success", "#22c55e"),
2350
+ warning: getToken("warning", "#eab308"),
2351
+ info: getToken("info", "#3b82f6"),
2352
+ light: getToken("light", "#f9fafb"),
2353
+ dark: getToken("dark", "#111827")
2354
+ },
2355
+ spacing: {
2356
+ 1: getToken("spacing-1", "0.25rem"),
2357
+ 2: getToken("spacing-2", "0.5rem"),
2358
+ 3: getToken("spacing-3", "0.75rem"),
2359
+ 4: getToken("spacing-4", "1rem"),
2360
+ 5: getToken("spacing-5", "1.25rem"),
2361
+ 6: getToken("spacing-6", "1.5rem"),
2362
+ 8: getToken("spacing-8", "2rem"),
2363
+ 10: getToken("spacing-10", "2.5rem"),
2364
+ 12: getToken("spacing-12", "3rem"),
2365
+ 16: getToken("spacing-16", "4rem"),
2366
+ 20: getToken("spacing-20", "5rem")
2367
+ },
2368
+ borderRadius: {
2369
+ sm: getToken("border-radius-sm", "0.25rem"),
2370
+ md: getToken("border-radius-md", "0.5rem"),
2371
+ lg: getToken("border-radius-lg", "0.75rem"),
2372
+ xl: getToken("border-radius-xl", "1rem"),
2373
+ full: getToken("border-radius-full", "9999px")
2374
+ },
2375
+ typography: {
2376
+ fontFamily: {
2377
+ sans: getToken("font-sans-serif", "Inter, system-ui, sans-serif"),
2378
+ serif: getToken("font-serif", "Georgia, serif"),
2379
+ mono: getToken("font-monospace", "Fira Code, monospace")
2380
+ },
2381
+ fontSize: {
2382
+ xs: getToken("font-size-xs", "0.75rem"),
2383
+ sm: getToken("font-size-sm", "0.875rem"),
2384
+ md: getToken("font-size-md", "1rem"),
2385
+ lg: getToken("font-size-lg", "1.125rem"),
2386
+ xl: getToken("font-size-xl", "1.25rem"),
2387
+ "2xl": getToken("font-size-2xl", "1.5rem"),
2388
+ "3xl": getToken("font-size-3xl", "1.875rem"),
2389
+ "4xl": getToken("font-size-4xl", "2.25rem")
2390
+ },
2391
+ fontWeight: {
2392
+ light: getToken("font-weight-light", "300"),
2393
+ normal: getToken("font-weight-normal", "400"),
2394
+ medium: getToken("font-weight-medium", "500"),
2395
+ semibold: getToken("font-weight-semibold", "600"),
2396
+ bold: getToken("font-weight-bold", "700")
2397
+ }
2398
+ },
2399
+ shadows: {
2400
+ sm: getToken("box-shadow-sm", "0 1px 2px 0 rgba(0, 0, 0, 0.05)"),
2401
+ md: getToken("box-shadow-md", "0 4px 6px -1px rgba(0, 0, 0, 0.1)"),
2402
+ lg: getToken("box-shadow-lg", "0 10px 15px -3px rgba(0, 0, 0, 0.1)"),
2403
+ xl: getToken("box-shadow-xl", "0 20px 25px -5px rgba(0, 0, 0, 0.1)"),
2404
+ inset: getToken("box-shadow-inset", "inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)")
2405
+ },
2406
+ transitions: {
2407
+ fast: getToken("transition-fast", "150ms"),
2408
+ base: getToken("transition-base", "200ms"),
2409
+ slow: getToken("transition-slow", "300ms")
2410
+ }
2411
+ };
2412
+ }
2413
+
3512
2414
  /**
3513
2415
  * Default fallback UI
3514
2416
  */ const DefaultFallback = ({error: error, errorInfo: errorInfo}) => {
@@ -3557,7 +2459,7 @@ class ThemeApplicator {
3557
2459
  },
3558
2460
  children: JSON.stringify(context, null, 2)
3559
2461
  }) ]
3560
- }), "development" === process.env.NODE_ENV && errorInfo && jsxs("details", {
2462
+ }), ("undefined" == typeof process || "development" === process.env?.NODE_ENV) && errorInfo && jsxs("details", {
3561
2463
  style: {
3562
2464
  marginTop: "1rem"
3563
2465
  },
@@ -3653,6 +2555,76 @@ class ThemeApplicator {
3653
2555
  }
3654
2556
  }
3655
2557
 
2558
+ /**
2559
+ * Theme Applicator
2560
+ *
2561
+ * Applies theme configurations to the DOM, including CSS variables,
2562
+ * component overrides, typography, spacing, and color palettes.
2563
+ *
2564
+ * Uses the unified theme system for CSS generation and injection.
2565
+ */
2566
+ /**
2567
+ * Theme applicator class for runtime theme application
2568
+ *
2569
+ * Uses the unified theme system for efficient CSS variable generation and injection.
2570
+ */ class ThemeApplicator {
2571
+ constructor(root = document.documentElement) {
2572
+ this.styleId = "atomix-theme-applicator", this.root = root;
2573
+ }
2574
+ /**
2575
+ * Apply a complete theme configuration using DesignTokens
2576
+ *
2577
+ * Uses the unified theme system to generate and inject CSS.
2578
+ * Automatically respects atomix.config.ts when using DesignTokens.
2579
+ */ applyTheme(tokens) {
2580
+ // Clear previously applied variables
2581
+ this.clearAppliedVars(),
2582
+ // Inject CSS into DOM
2583
+ injectCSS$1(createTheme(tokens, {
2584
+ selector: ":root",
2585
+ prefix: "atomix"
2586
+ }), this.styleId);
2587
+ }
2588
+ /**
2589
+ * Apply global CSS variables
2590
+ */ applyGlobalCSSVars(vars) {
2591
+ Object.entries(vars).forEach((([key, value]) => {
2592
+ this.root.style.setProperty(key, String(value));
2593
+ }));
2594
+ }
2595
+ /**
2596
+ * Clear all applied CSS variables
2597
+ */ clearAppliedVars() {
2598
+ removeCSS(this.styleId);
2599
+ }
2600
+ /**
2601
+ * Remove theme application
2602
+ */ removeTheme() {
2603
+ this.clearAppliedVars(), removeCSS(this.styleId);
2604
+ }
2605
+ /**
2606
+ * Update specific CSS variables without clearing all
2607
+ */ updateCSSVars(vars) {
2608
+ this.applyGlobalCSSVars(vars);
2609
+ }
2610
+ }
2611
+
2612
+ /**
2613
+ * Global theme applicator instance
2614
+ */ let globalApplicator = null;
2615
+
2616
+ /**
2617
+ * Get or create global theme applicator
2618
+ */ function getThemeApplicator() {
2619
+ return globalApplicator || (globalApplicator = new ThemeApplicator), globalApplicator;
2620
+ }
2621
+
2622
+ /**
2623
+ * Apply theme using global applicator
2624
+ */ function applyTheme(tokens) {
2625
+ getThemeApplicator().applyTheme(tokens);
2626
+ }
2627
+
3656
2628
  const VIEWPORT_PRESETS = {
3657
2629
  mobile: {
3658
2630
  width: 375,
@@ -5138,10 +4110,374 @@ class ThemeValidator {
5138
4110
  };
5139
4111
 
5140
4112
  /**
5141
- * Theme Comparator Component
4113
+ * Theme Comparator Component
4114
+ *
4115
+ * Compares two themes and highlights differences
4116
+ */ var aCallable = aCallable$3, toObject = toObject$2, IndexedObject = indexedObject, lengthOfArrayLike = lengthOfArrayLike$2, $TypeError = TypeError, REDUCE_EMPTY = "Reduce of empty array with no initial value", createMethod = function(IS_RIGHT) {
4117
+ return function(that, callbackfn, argumentsLength, memo) {
4118
+ var O = toObject(that), self = IndexedObject(O), length = lengthOfArrayLike(O);
4119
+ if (aCallable(callbackfn), 0 === length && argumentsLength < 2) throw new $TypeError(REDUCE_EMPTY);
4120
+ var index = IS_RIGHT ? length - 1 : 0, i = IS_RIGHT ? -1 : 1;
4121
+ if (argumentsLength < 2) for (;;) {
4122
+ if (index in self) {
4123
+ memo = self[index], index += i;
4124
+ break;
4125
+ }
4126
+ if (index += i, IS_RIGHT ? index < 0 : length <= index) throw new $TypeError(REDUCE_EMPTY);
4127
+ }
4128
+ for (;IS_RIGHT ? index >= 0 : length > index; index += i) index in self && (memo = callbackfn(memo, self[index], index, O));
4129
+ return memo;
4130
+ };
4131
+ }, arrayReduce = {
4132
+ // `Array.prototype.reduce` method
4133
+ // https://tc39.es/ecma262/#sec-array.prototype.reduce
4134
+ left: createMethod(!1),
4135
+ // `Array.prototype.reduceRight` method
4136
+ // https://tc39.es/ecma262/#sec-array.prototype.reduceright
4137
+ right: createMethod(!0)
4138
+ }, fails = fails$9, globalThis$1 = globalThis_1, userAgent = environmentUserAgent, classof = classofRaw$2, userAgentStartsWith = function(string) {
4139
+ return userAgent.slice(0, string.length) === string;
4140
+ }, environment = userAgentStartsWith("Bun/") ? "BUN" : userAgentStartsWith("Cloudflare-Workers") ? "CLOUDFLARE" : userAgentStartsWith("Deno/") ? "DENO" : userAgentStartsWith("Node.js/") ? "NODE" : globalThis$1.Bun && "string" == typeof Bun.version ? "BUN" : globalThis$1.Deno && "object" == typeof Deno.version ? "DENO" : "process" === classof(globalThis$1.process) ? "NODE" : globalThis$1.window && globalThis$1.document ? "BROWSER" : "REST", $reduce = arrayReduce.left;
4141
+
4142
+ // `Array.prototype.reduce` method
4143
+ // https://tc39.es/ecma262/#sec-array.prototype.reduce
4144
+ _export({
4145
+ target: "Array",
4146
+ proto: !0,
4147
+ forced: !("NODE" === environment) && environmentV8Version > 79 && environmentV8Version < 83 || !function(METHOD_NAME, argument) {
4148
+ var method = [][METHOD_NAME];
4149
+ return !!method && fails((function() {
4150
+ // eslint-disable-next-line no-useless-call -- required for testing
4151
+ method.call(null, argument || function() {
4152
+ return 1;
4153
+ }, 1);
4154
+ }));
4155
+ }("reduce")
4156
+ }, {
4157
+ reduce: function(callbackfn /* , initialValue */) {
4158
+ var length = arguments.length;
4159
+ return $reduce(this, callbackfn, length, length > 1 ? arguments[1] : void 0);
4160
+ }
4161
+ });
4162
+
4163
+ var reduce$3 = getBuiltInPrototypeMethod$3("Array", "reduce"), isPrototypeOf = objectIsPrototypeOf, method = reduce$3, ArrayPrototype = Array.prototype;
4164
+
4165
+ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
4166
+ var own = it.reduce;
4167
+ return it === ArrayPrototype || isPrototypeOf(ArrayPrototype, it) && own === ArrayPrototype.reduce ? method : own;
4168
+ })), DEFAULT_PALETTE = {
4169
+ primary: {
4170
+ main: "#7c3aed",
4171
+ // Primary-6
4172
+ light: "#d0b2f5",
4173
+ // Primary-3
4174
+ dark: "#3c1583",
4175
+ // Primary-9
4176
+ contrastText: "#ffffff"
4177
+ },
4178
+ secondary: {
4179
+ main: "#f3f4f6",
4180
+ // Gray-2
4181
+ light: "#ffffff",
4182
+ // Gray-1
4183
+ dark: "#e5e7eb",
4184
+ // Gray-3
4185
+ contrastText: "#1f2937"
4186
+ },
4187
+ error: {
4188
+ main: "#ef4444",
4189
+ // Red-6
4190
+ light: "#fca5a5",
4191
+ // Red-4
4192
+ dark: "#991b1b",
4193
+ // Red-9
4194
+ contrastText: "#ffffff"
4195
+ },
4196
+ warning: {
4197
+ main: "#eab308",
4198
+ // Yellow-6
4199
+ light: "#fde047",
4200
+ // Yellow-4
4201
+ dark: "#854d0e",
4202
+ // Yellow-9
4203
+ contrastText: "#000000"
4204
+ },
4205
+ info: {
4206
+ main: "#3b82f6",
4207
+ // Blue-6
4208
+ light: "#93c5fd",
4209
+ // Blue-4
4210
+ dark: "#1e40af",
4211
+ // Blue-9
4212
+ contrastText: "#ffffff"
4213
+ },
4214
+ success: {
4215
+ main: "#22c55e",
4216
+ // Green-6
4217
+ light: "#86efac",
4218
+ // Green-4
4219
+ dark: "#166534",
4220
+ // Green-9
4221
+ contrastText: "#ffffff"
4222
+ },
4223
+ background: {
4224
+ default: "#ffffff",
4225
+ // Primary-bg
4226
+ paper: "#f3f4f6",
4227
+ // Secondary-bg
4228
+ subtle: "#d1d5db"
4229
+ },
4230
+ text: {
4231
+ primary: "#111827",
4232
+ // Gray-10
4233
+ secondary: "#374151",
4234
+ // Gray-8
4235
+ disabled: "#9ca3af"
4236
+ }
4237
+ }, DEFAULT_TYPOGRAPHY = {
4238
+ fontFamily: '"Roboto", "Helvetica Neue", "Helvetica", "Arial", sans-serif',
4239
+ fontSize: 16,
4240
+ // 1rem
4241
+ fontWeightLight: 300,
4242
+ fontWeightRegular: 400,
4243
+ fontWeightMedium: 500,
4244
+ fontWeightSemiBold: 600,
4245
+ fontWeightBold: 700,
4246
+ fontWeightHeavy: 800,
4247
+ fontWeightBlack: 900,
4248
+ h1: {
4249
+ fontSize: "2.5rem",
4250
+ // 40px
4251
+ fontWeight: 700,
4252
+ lineHeight: 1.3,
4253
+ letterSpacing: "-1px"
4254
+ },
4255
+ h2: {
4256
+ fontSize: "2rem",
4257
+ // 32px
4258
+ fontWeight: 700,
4259
+ lineHeight: 1.3,
4260
+ letterSpacing: "-1px"
4261
+ },
4262
+ h3: {
4263
+ fontSize: "1.5rem",
4264
+ // 24px
4265
+ fontWeight: 700,
4266
+ lineHeight: 1.3,
4267
+ letterSpacing: "-1px"
4268
+ },
4269
+ h4: {
4270
+ fontSize: "1.25rem",
4271
+ // 20px
4272
+ fontWeight: 700,
4273
+ lineHeight: 1.3,
4274
+ letterSpacing: "-0.5px"
4275
+ },
4276
+ h5: {
4277
+ fontSize: "1.125rem",
4278
+ // 18px
4279
+ fontWeight: 700,
4280
+ lineHeight: 1.3,
4281
+ letterSpacing: "-0.5px"
4282
+ },
4283
+ h6: {
4284
+ fontSize: "1rem",
4285
+ // 16px
4286
+ fontWeight: 700,
4287
+ lineHeight: 1.3,
4288
+ letterSpacing: "-0.5px"
4289
+ },
4290
+ body1: {
4291
+ fontSize: "1rem",
4292
+ // 16px
4293
+ fontWeight: 400,
4294
+ lineHeight: 1.2
4295
+ },
4296
+ body2: {
4297
+ fontSize: "0.875rem",
4298
+ // 14px
4299
+ fontWeight: 400,
4300
+ lineHeight: 1.2
4301
+ }
4302
+ }, DEFAULT_SHADOWS = {
4303
+ xs: "0px 1px 2px 0px rgba(45, 54, 67, 0.04), 0px 2px 4px 0px rgba(45, 54, 67, 0.08)",
4304
+ sm: "0 2px 4px rgba(0, 0, 0, 0.075)",
4305
+ md: "0 4px 8px rgba(0, 0, 0, 0.1)",
4306
+ lg: "0 16px 48px rgba(0, 0, 0, 0.175)",
4307
+ xl: "0px 16px 64px -8px rgba(45, 54, 67, 0.14)",
4308
+ inset: "inset 0 1px 2px rgba(0, 0, 0, 0.075)"
4309
+ }, DEFAULT_TRANSITIONS = {
4310
+ duration: {
4311
+ shortest: 150,
4312
+ shorter: 200,
4313
+ short: 250,
4314
+ standard: 300,
4315
+ complex: 375,
4316
+ enteringScreen: 225,
4317
+ leavingScreen: 195
4318
+ },
4319
+ easing: {
4320
+ easeInOut: "cubic-bezier(0.4, 0, 0.2, 1)",
4321
+ easeOut: "cubic-bezier(0.0, 0, 0.2, 1)",
4322
+ easeIn: "cubic-bezier(0.4, 0, 1, 1)",
4323
+ sharp: "cubic-bezier(0.4, 0, 0.6, 1)"
4324
+ }
4325
+ }, DEFAULT_ZINDEX = {
4326
+ mobileStepper: 1e3,
4327
+ speedDial: 1050,
4328
+ appBar: 1020,
4329
+ drawer: 1070,
4330
+ modal: 1040,
4331
+ snackbar: 1080,
4332
+ tooltip: 1060
4333
+ }, DEFAULT_BORDER_RADIUS = {
4334
+ base: "0.5rem",
4335
+ // 8px (spacing-2)
4336
+ sm: "0.25rem",
4337
+ // 4px (spacing-1)
4338
+ md: "0.25rem",
4339
+ // 4px (spacing-1)
4340
+ lg: "0.625rem",
4341
+ // 10px (spacing-2.5)
4342
+ xl: "0.75rem",
4343
+ // 12px (spacing-3)
4344
+ xxl: "1rem",
4345
+ // 16px (spacing-4)
4346
+ "3xl": "1.5rem",
4347
+ // 24px (spacing-6)
4348
+ "4xl": "2rem",
4349
+ // 32px (spacing-8)
4350
+ pill: "50rem"
4351
+ };
4352
+
4353
+ // ============================================================================
4354
+ // Default Theme Values
4355
+ // ============================================================================
4356
+ // ============================================================================
4357
+ // Helper Functions
4358
+ // ============================================================================
4359
+ /**
4360
+ * Create a complete palette color from partial configuration
4361
+ */
4362
+ function createPaletteColor(color) {
4363
+ return "string" == typeof color ? {
4364
+ main: color,
4365
+ light: lighten(color),
4366
+ dark: darken(color),
4367
+ contrastText: getContrastText(color)
4368
+ } : {
4369
+ main: color.main || "#000000",
4370
+ light: color.light || lighten(color.main || "#000000"),
4371
+ dark: color.dark || darken(color.main || "#000000"),
4372
+ contrastText: color.contrastText || getContrastText(color.main || "#000000")
4373
+ };
4374
+ }
4375
+
4376
+ /**
4377
+ * Create breakpoints object
4378
+ */
4379
+ // ============================================================================
4380
+ // Main createTheme Function
4381
+ // ============================================================================
4382
+ /**
4383
+ * Create a theme object with computed values
5142
4384
  *
5143
- * Compares two themes and highlights differences
4385
+ * @param options - Theme configuration options
4386
+ * @returns Complete theme object
5144
4387
  */
4388
+ function createThemeObject(...options) {
4389
+ // Merge all options
4390
+ const mergedOptions = _reduceInstanceProperty(options).call(options, ((acc, option) => deepMerge(acc, option)), {}), palette = {
4391
+ primary: createPaletteColor(mergedOptions.palette?.primary || DEFAULT_PALETTE.primary),
4392
+ secondary: createPaletteColor(mergedOptions.palette?.secondary || DEFAULT_PALETTE.secondary),
4393
+ error: createPaletteColor(mergedOptions.palette?.error || DEFAULT_PALETTE.error),
4394
+ warning: createPaletteColor(mergedOptions.palette?.warning || DEFAULT_PALETTE.warning),
4395
+ info: createPaletteColor(mergedOptions.palette?.info || DEFAULT_PALETTE.info),
4396
+ success: createPaletteColor(mergedOptions.palette?.success || DEFAULT_PALETTE.success),
4397
+ // Handle light and dark colors if provided
4398
+ ...mergedOptions.palette?.light && {
4399
+ light: createPaletteColor(mergedOptions.palette.light)
4400
+ },
4401
+ ...mergedOptions.palette?.dark && {
4402
+ dark: createPaletteColor(mergedOptions.palette.dark)
4403
+ },
4404
+ background: {
4405
+ default: mergedOptions.palette?.background?.default || DEFAULT_PALETTE.background.default,
4406
+ subtle: mergedOptions.palette?.background?.subtle || DEFAULT_PALETTE.background.subtle
4407
+ },
4408
+ text: {
4409
+ primary: mergedOptions.palette?.text?.primary || DEFAULT_PALETTE.text.primary,
4410
+ secondary: mergedOptions.palette?.text?.secondary || DEFAULT_PALETTE.text.secondary,
4411
+ disabled: mergedOptions.palette?.text?.disabled || DEFAULT_PALETTE.text.disabled
4412
+ }
4413
+ }, typography = deepMerge({
4414
+ ...DEFAULT_TYPOGRAPHY
4415
+ }, mergedOptions.typography || {}), spacing = function(spacingInput = 4) {
4416
+ // If it's already a function, return it
4417
+ return "function" == typeof spacingInput ? spacingInput :
4418
+ // If it's a number, create a function that multiplies by that number
4419
+ "number" == typeof spacingInput ? (...values) => 0 === values.length ? "0px" : values.map((value => value * spacingInput + "px")).join(" ") :
4420
+ // If it's an array, use it as a scale
4421
+ Array.isArray(spacingInput) ? (...values) => 0 === values.length ? "0px" : values.map((value => `${spacingInput[value] || value}px`)).join(" ") : (...values) => 0 === values.length ? "0px" : values.map((value => 4 * value + "px")).join(" ");
4422
+ }(mergedOptions.spacing), breakpoints = function(breakpointsInput) {
4423
+ const values = {
4424
+ xs: 0,
4425
+ sm: 576,
4426
+ md: 768,
4427
+ lg: 992,
4428
+ xl: 1200,
4429
+ xxl: 1440,
4430
+ ...breakpointsInput?.values
4431
+ }, unit = breakpointsInput?.unit || "px";
4432
+ return {
4433
+ values: values,
4434
+ unit: unit,
4435
+ up: key => `@media (min-width:${"number" == typeof key ? key : values[key] ?? 0}${unit})`,
4436
+ down: key => `@media (max-width:${("number" == typeof key ? key : values[key] ?? 0) - .05}${unit})`,
4437
+ between: (start, end) => {
4438
+ const startValue = "number" == typeof start ? start : values[start] ?? 0, endValue = "number" == typeof end ? end : values[end] ?? 0;
4439
+ return `@media (min-width:${startValue}${unit}) and (max-width:${endValue - .05}${unit})`;
4440
+ }
4441
+ };
4442
+ }(mergedOptions.breakpoints), shadows = deepMerge({
4443
+ ...DEFAULT_SHADOWS
4444
+ }, mergedOptions.shadows || {}), transitions = deepMerge({
4445
+ ...DEFAULT_TRANSITIONS
4446
+ }, mergedOptions.transitions || {}), zIndex = deepMerge({
4447
+ ...DEFAULT_ZINDEX
4448
+ }, mergedOptions.zIndex || {}), borderRadius = deepMerge({
4449
+ ...DEFAULT_BORDER_RADIUS
4450
+ }, mergedOptions.borderRadius || {});
4451
+ // Create palette
4452
+ return {
4453
+ // Metadata
4454
+ name: mergedOptions.name || "Custom Theme",
4455
+ class: mergedOptions.class,
4456
+ description: mergedOptions.description,
4457
+ author: mergedOptions.author,
4458
+ version: mergedOptions.version || "1.0.0",
4459
+ tags: mergedOptions.tags,
4460
+ supportsDarkMode: mergedOptions.supportsDarkMode,
4461
+ status: mergedOptions.status || "experimental",
4462
+ a11y: mergedOptions.a11y,
4463
+ color: mergedOptions.color || palette.primary.main,
4464
+ features: mergedOptions.features,
4465
+ dependencies: mergedOptions.dependencies,
4466
+ // Theme configuration
4467
+ palette: palette,
4468
+ typography: typography,
4469
+ spacing: spacing,
4470
+ breakpoints: breakpoints,
4471
+ shadows: shadows,
4472
+ transitions: transitions,
4473
+ zIndex: zIndex,
4474
+ borderRadius: borderRadius,
4475
+ custom: mergedOptions.custom || {},
4476
+ // Mark as JS theme
4477
+ __isJSTheme: !0
4478
+ };
4479
+ }
4480
+
5145
4481
  /**
5146
4482
  * useHistory Hook
5147
4483
  *
@@ -5159,8 +4495,7 @@ class ThemeValidator {
5159
4495
  * maxHistorySize: 50
5160
4496
  * });
5161
4497
  * ```
5162
- */
5163
- function useHistory(options = {}) {
4498
+ */ function useHistory(options = {}) {
5164
4499
  const {maxHistorySize: maxHistorySize = 50, initialState: initialState} = options, [state, setStateInternal] = useState(initialState), historyRef = useRef([ initialState ]), currentIndexRef = useRef(0), [canUndo, setCanUndo] = useState(!1), [canRedo, setCanRedo] = useState(!1), updateHistoryState = useCallback((() => {
5165
4500
  setCanUndo(currentIndexRef.current > 0), setCanRedo(currentIndexRef.current < historyRef.current.length - 1);
5166
4501
  }), []), setState = useCallback((newState => {
@@ -5602,59 +4937,20 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
5602
4937
  };
5603
4938
 
5604
4939
  /**
5605
- * CSS Variable Mapper
4940
+ * Theme Adapter
5606
4941
  *
5607
- * Utilities for generating and managing CSS custom properties from SCSS tokens
5608
- * and component configurations.
4942
+ * Converts between Theme objects and DesignTokens.
5609
4943
  */
5610
4944
  /**
5611
- * Generate CSS variable name from parts
5612
- *
5613
- * @example
5614
- * generateCSSVariableName('button', 'bg', { prefix: 'atomix' })
5615
- * // Returns: '--atomix-button-bg'
5616
- */ function generateCSSVariableName(component, property, options = {}) {
5617
- const {prefix: prefix = "atomix", separator: separator = "-", includeComponent: includeComponent = !0} = options, parts = [ prefix ];
5618
- return includeComponent && parts.push(component), parts.push(property), `--${parts.join(separator)}`;
5619
- }
5620
-
5621
- /**
5622
- * Generate CSS variables object from configuration
4945
+ * Convert DesignTokens to Theme-compatible CSS variables
5623
4946
  *
5624
- * @example
5625
- * const vars = generateComponentCSSVars({
5626
- * component: 'button',
5627
- * properties: { bg: '#000', color: '#fff' }
5628
- * })
5629
- * // Returns: { '--atomix-button-bg': '#000', '--atomix-button-color': '#fff' }
5630
- */ function generateComponentCSSVars(config, options = {}) {
5631
- const vars = {}, {component: component, properties: properties, parts: parts, states: states, variants: variants} = config;
5632
- // Base properties
5633
- return Object.entries(properties).forEach((([key, value]) => {
5634
- const varName = generateCSSVariableName(component, key, options);
5635
- vars[varName] = String(value);
5636
- })),
5637
- // Part properties
5638
- parts && Object.entries(parts).forEach((([partName, partProps]) => {
5639
- Object.entries(partProps).forEach((([key, value]) => {
5640
- const varName = generateCSSVariableName(component, `${partName}-${key}`, options);
5641
- vars[varName] = String(value);
5642
- }));
5643
- })),
5644
- // State properties
5645
- states && Object.entries(states).forEach((([stateName, stateProps]) => {
5646
- Object.entries(stateProps).forEach((([key, value]) => {
5647
- const varName = generateCSSVariableName(component, `${stateName}-${key}`, options);
5648
- vars[varName] = String(value);
5649
- }));
5650
- })),
5651
- // Variant properties
5652
- variants && Object.entries(variants).forEach((([variantName, variantProps]) => {
5653
- Object.entries(variantProps).forEach((([key, value]) => {
5654
- const varName = generateCSSVariableName(component, `${variantName}-${key}`, options);
5655
- vars[varName] = String(value);
5656
- }));
5657
- })), vars;
4947
+ * @param tokens - DesignTokens object
4948
+ * @returns CSS variables object compatible with Theme.cssVars
4949
+ */ function designTokensToCSSVars(tokens) {
4950
+ const cssVars = {};
4951
+ return Object.entries(tokens).forEach((([key, value]) => {
4952
+ void 0 !== value && (cssVars[`--atomix-${key}`] = String(value));
4953
+ })), cssVars;
5658
4954
  }
5659
4955
 
5660
4956
  /**
@@ -5677,11 +4973,14 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
5677
4973
  /**
5678
4974
  * Apply CSS variables to an element
5679
4975
  *
5680
- * @param element - Target element (defaults to document.documentElement)
5681
4976
  * @param vars - CSS variables to apply
5682
- */ function applyCSSVariables(vars, element = document.documentElement) {
4977
+ * @param element - Target element (defaults to document.documentElement)
4978
+ */ function applyCSSVariables(vars, element) {
4979
+ if ("undefined" == typeof window) return;
4980
+ // SSR safety
4981
+ const target = element || document.documentElement;
5683
4982
  Object.entries(vars).forEach((([key, value]) => {
5684
- element.style.setProperty(key, String(value));
4983
+ target.style.setProperty(key, String(value));
5685
4984
  }));
5686
4985
  }
5687
4986
 
@@ -5690,9 +4989,12 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
5690
4989
  *
5691
4990
  * @param varNames - Variable names to remove
5692
4991
  * @param element - Target element (defaults to document.documentElement)
5693
- */ function removeCSSVariables(varNames, element = document.documentElement) {
4992
+ */ function removeCSSVariables(varNames, element) {
4993
+ if ("undefined" == typeof window) return;
4994
+ // SSR safety
4995
+ const target = element || document.documentElement;
5694
4996
  varNames.forEach((varName => {
5695
- element.style.removeProperty(varName);
4997
+ target.style.removeProperty(varName);
5696
4998
  }));
5697
4999
  }
5698
5000
 
@@ -5702,8 +5004,11 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
5702
5004
  * @param varName - Variable name to get
5703
5005
  * @param element - Target element (defaults to document.documentElement)
5704
5006
  * @returns Variable value or null if not found
5705
- */ function getCSSVariable(varName, element = document.documentElement) {
5706
- return getComputedStyle(element).getPropertyValue(varName).trim() || null;
5007
+ */ function getCSSVariable(varName, element) {
5008
+ if ("undefined" == typeof window) return null;
5009
+ // SSR safety
5010
+ const target = element || document.documentElement;
5011
+ return getComputedStyle(target).getPropertyValue(varName).trim() || null;
5707
5012
  }
5708
5013
 
5709
5014
  /**
@@ -5747,28 +5052,8 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
5747
5052
  /**
5748
5053
  * Theme Helper Functions
5749
5054
  *
5750
- * Utility functions for working with themes and DesignTokens
5055
+ * Utility functions for working with DesignTokens
5751
5056
  */
5752
- /**
5753
- * Get DesignTokens from current theme
5754
- *
5755
- * Converts a Theme object to DesignTokens. Useful when you need to
5756
- * work with DesignTokens but have a Theme object.
5757
- *
5758
- * @param theme - Theme object to convert
5759
- * @returns DesignTokens object
5760
- *
5761
- * @example
5762
- * ```typescript
5763
- * // If you have a Theme object, convert it to DesignTokens
5764
- * const tokens = getDesignTokensFromTheme(theme);
5765
- * // Now you can use tokens with unified theme system
5766
- * const css = createTheme(tokens);
5767
- * ```
5768
- */ function getDesignTokensFromTheme(theme) {
5769
- return theme ? createDesignTokensFromTheme(theme) : null;
5770
- }
5771
-
5772
5057
  /**
5773
5058
  * Check if a value is DesignTokens
5774
5059
  *
@@ -5788,17 +5073,6 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
5788
5073
  // Check if keys look like DesignTokens (kebab-case, no nesting)
5789
5074
  }
5790
5075
 
5791
- /**
5792
- * Check if a value is a Theme object
5793
- *
5794
- * Type guard to check if an object is a Theme.
5795
- *
5796
- * @param value - Value to check
5797
- * @returns True if value is Theme
5798
- */ function isThemeObject(value) {
5799
- return !(!value || "object" != typeof value) && ("__isJSTheme" in value || "palette" in value && "typography" in value);
5800
- }
5801
-
5802
5076
  /**
5803
5077
  * RTL (Right-to-Left) Support Utilities
5804
5078
  *
@@ -5987,13 +5261,13 @@ class RTLManager {
5987
5261
  /**
5988
5262
  * Theme System Exports
5989
5263
  *
5990
- * Unified theme system - handles both DesignTokens and Theme objects.
5264
+ * Simplified theme system using DesignTokens only.
5991
5265
  *
5992
5266
  * @example
5993
5267
  * ```typescript
5994
5268
  * import { createTheme, injectTheme } from '@shohojdhara/atomix/theme';
5995
5269
  *
5996
- * // Using DesignTokens (recommended - flat structure)
5270
+ * // Using DesignTokens
5997
5271
  * const css = createTheme({ 'primary': '#7AFFD7', 'spacing-4': '1rem' });
5998
5272
  * injectTheme(css);
5999
5273
  *
@@ -6006,7 +5280,7 @@ class RTLManager {
6006
5280
  // ============================================================================
6007
5281
  // Core Theme Functions
6008
5282
  // ============================================================================
6009
- // Unified createTheme (handles both DesignTokens and Theme objects)
5283
+ // Create theme CSS from DesignTokens
6010
5284
  /**
6011
5285
  * Inject theme CSS into DOM
6012
5286
  */ function injectTheme(css, id = "atomix-theme") {
@@ -6022,63 +5296,18 @@ class RTLManager {
6022
5296
  /**
6023
5297
  * Save theme to CSS file
6024
5298
  */ async function saveTheme(css, filePath) {
6025
- await saveCSSFile(css, filePath);
5299
+ await async function(css, filePath) {
5300
+ // Check if in browser environment
5301
+ if ("undefined" != typeof window) throw new Error("saveCSSFile can only be used in Node.js environment. Use injectCSS() for browser environments.");
5302
+ // Dynamic import to avoid bundling Node.js modules in browser builds
5303
+ const fs = await import("fs/promises"), dir = (await import("path")).dirname(filePath);
5304
+ await fs.mkdir(dir, {
5305
+ recursive: !0
5306
+ }),
5307
+ // Write file
5308
+ await fs.writeFile(filePath, css, "utf8");
5309
+ }(css, filePath);
6026
5310
  }
6027
5311
 
6028
- /**
6029
- * Atomix Config Loader
6030
- *
6031
- * Helper functions to load atomix.config.ts from external projects.
6032
- * Similar to how Tailwind loads tailwind.config.js
6033
- */
6034
- /**
6035
- * Load Atomix configuration from project root
6036
- *
6037
- * Attempts to load atomix.config.ts from the current working directory.
6038
- * Falls back to default config if file doesn't exist.
6039
- *
6040
- * @param options - Loader options
6041
- * @returns Loaded configuration or default
6042
- *
6043
- * @example
6044
- * ```typescript
6045
- * import { loadAtomixConfig } from '@shohojdhara/atomix/config';
6046
- * import { createTheme } from '@shohojdhara/atomix/theme';
6047
- *
6048
- * const config = loadAtomixConfig();
6049
- * const theme = createTheme(config.theme?.tokens || {});
6050
- * ```
6051
- */ const loader = Object.freeze( Object.defineProperty({
6052
- __proto__: null,
6053
- loadAtomixConfig: function(options = {}) {
6054
- const {configPath: configPath = "atomix.config.ts", required: required = !1} = options, defaultConfig = {
6055
- prefix: "atomix",
6056
- theme: {
6057
- extend: {}
6058
- }
6059
- };
6060
- // Default config
6061
- // In browser environments, config loading is not supported
6062
- if ("undefined" != typeof window) {
6063
- if (required) throw new Error("Config loading not supported in browser environment");
6064
- return defaultConfig;
6065
- }
6066
- // Try to load config file
6067
- try {
6068
- // Use dynamic import for ESM compatibility
6069
- const configModule = require(configPath), config = configModule.default || configModule;
6070
- // Validate it's an AtomixConfig
6071
- if (config && "object" == typeof config) return config;
6072
- throw new Error("Invalid config format");
6073
- } catch (error) {
6074
- if (required) throw new Error(`Failed to load config from ${configPath}: ${error.message}`);
6075
- // Return default config if not required
6076
- return defaultConfig;
6077
- }
6078
- }
6079
- }, Symbol.toStringTag, {
6080
- value: "Module"
6081
- }));
6082
-
6083
- export { RTLManager, ThemeApplicator, ThemeComparator, ThemeContext, ThemeErrorBoundary, ThemeInspector, ThemeLiveEditor, ThemePreview, ThemeProvider, ThemeRegistry, ThemeValidator, applyCSSVariables, applyTheme, createDesignTokensFromTheme, createTheme, createThemeObject, createTokens, cssVarsToStyle, deepMerge, defaultTokens, designTokensToCSSVars, designTokensToTheme, extendTheme, extractComponentName, generateCSSVariableName, generateCSSVariables$1 as generateCSSVariables, generateCSSVariablesForSelector, generateComponentCSSVars, getCSSVariable, getDesignTokensFromTheme, getThemeApplicator, injectCSS$1 as injectCSS, injectTheme, isCSSInjected, isDesignTokens, isThemeObject, isValidCSSVariableName, loadThemeFromConfig, loadThemeFromConfigSync, mapSCSSTokensToCSSVars, mergeCSSVars, mergeTheme, removeCSS, removeCSSVariables, removeTheme, saveCSSFile, saveCSSFileSync, saveTheme, themeToDesignTokens, useHistory, useTheme };
5312
+ export { RTLManager, ThemeApplicator, ThemeComparator, ThemeContext, ThemeErrorBoundary, ThemeInspector, ThemeLiveEditor, ThemePreview, ThemeProvider, ThemeValidator, applyCSSVariables, applyComponentTheme, applyTheme, camelToKebab, clearThemes, createTheme, createThemeRegistry, createTokens, cssVarsToStyle, deepMerge, defaultTokens, designTokensToCSSVars, extendTheme, extractComponentName, generateCSSVariableName, generateCSSVariables$1 as generateCSSVariables, generateCSSVariablesForSelector, generateClassName, generateComponentCSSVars, getAllThemes, getCSSVariable, getComponentThemeValue, getTheme, getThemeApplicator, getThemeCount, getThemeIds, hasTheme, injectCSS$1 as injectCSS, injectTheme, isCSSInjected, isDesignTokens, isValidCSSVariableName, loadThemeFromConfig, loadThemeFromConfigSync, mapSCSSTokensToCSSVars, mergeCSSVars, mergeTheme, normalizeThemeTokens, registerTheme, removeCSS, removeCSSVariables, removeTheme, saveTheme, themePropertyToCSSVar, unregisterTheme, useComponentTheme, useHistory, useTheme, useThemeTokens };
6084
5313
  //# sourceMappingURL=theme.js.map