@shohojdhara/atomix 0.3.12 → 0.3.14

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 (155) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +2 -0
  3. package/dist/atomix.css +101 -88
  4. package/dist/atomix.css.map +1 -1
  5. package/dist/atomix.min.css +5 -15258
  6. package/dist/atomix.min.css.map +1 -1
  7. package/dist/charts.d.ts +1 -1
  8. package/dist/charts.js +17 -19
  9. package/dist/charts.js.map +1 -1
  10. package/dist/core.d.ts +41 -11
  11. package/dist/core.js +55 -41
  12. package/dist/core.js.map +1 -1
  13. package/dist/forms.d.ts +28 -11
  14. package/dist/forms.js +25 -24
  15. package/dist/forms.js.map +1 -1
  16. package/dist/heavy.d.ts +1 -1
  17. package/dist/heavy.js +32 -25
  18. package/dist/heavy.js.map +1 -1
  19. package/dist/index.d.ts +122 -46
  20. package/dist/index.esm.js +865 -200
  21. package/dist/index.esm.js.map +1 -1
  22. package/dist/index.js +870 -204
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.min.js +1 -1
  25. package/dist/index.min.js.map +1 -1
  26. package/dist/theme.d.ts +27 -2
  27. package/dist/theme.js +721 -108
  28. package/dist/theme.js.map +1 -1
  29. package/package.json +1 -1
  30. package/scripts/atomix-cli.js +610 -1111
  31. package/scripts/cli/component-generator.js +610 -0
  32. package/scripts/cli/documentation-sync.js +542 -0
  33. package/scripts/cli/interactive-init.js +84 -288
  34. package/scripts/cli/mappings.js +211 -0
  35. package/scripts/cli/migration-tools.js +95 -288
  36. package/scripts/cli/template-manager.js +107 -0
  37. package/scripts/cli/templates/README.md +123 -0
  38. package/scripts/cli/templates/composable-templates.js +149 -0
  39. package/scripts/cli/templates/config-templates.js +126 -0
  40. package/scripts/cli/templates/index.js +95 -0
  41. package/scripts/cli/templates/project-templates.js +214 -0
  42. package/scripts/cli/templates/react-templates.js +261 -0
  43. package/scripts/cli/templates/scss-templates.js +156 -0
  44. package/scripts/cli/templates/storybook-templates.js +236 -0
  45. package/scripts/cli/templates/testing-templates.js +45 -0
  46. package/scripts/cli/templates/token-templates.js +447 -0
  47. package/scripts/cli/templates/types-templates.js +133 -0
  48. package/scripts/cli/templates-original-backup.js +1655 -0
  49. package/scripts/cli/templates.js +35 -0
  50. package/scripts/cli/templates_backup.js +684 -0
  51. package/scripts/cli/theme-bridge.js +20 -14
  52. package/scripts/cli/token-manager.js +150 -77
  53. package/scripts/cli/utils.js +37 -25
  54. package/src/components/Accordion/Accordion.stories.tsx +5 -5
  55. package/src/components/Accordion/Accordion.test.tsx +57 -0
  56. package/src/components/Accordion/Accordion.tsx +4 -0
  57. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +41 -44
  58. package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +1 -1
  59. package/src/components/AtomixGlass/stories/Examples.stories.tsx +37 -37
  60. package/src/components/AtomixGlass/stories/Modes.stories.tsx +1 -2
  61. package/src/components/AtomixGlass/stories/Playground.stories.tsx +50 -51
  62. package/src/components/Avatar/Avatar.stories.tsx +26 -26
  63. package/src/components/Badge/Badge.stories.tsx +31 -31
  64. package/src/components/Badge/Badge.test.tsx +51 -0
  65. package/src/components/Badge/Badge.tsx +20 -1
  66. package/src/components/Block/Block.stories.tsx +5 -5
  67. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +1 -1
  68. package/src/components/Breadcrumb/Breadcrumb.tsx +2 -2
  69. package/src/components/Button/Button.stories.tsx +13 -13
  70. package/src/components/Button/Button.tsx +4 -4
  71. package/src/components/Button/ButtonGroup.stories.tsx +2 -2
  72. package/src/components/Button/README.md +5 -0
  73. package/src/components/Callout/Callout.stories.tsx +11 -11
  74. package/src/components/Callout/Callout.test.tsx +10 -10
  75. package/src/components/Callout/Callout.tsx +7 -7
  76. package/src/components/Callout/README.md +9 -8
  77. package/src/components/Card/Card.tsx +2 -2
  78. package/src/components/Chart/Chart.stories.tsx +6 -6
  79. package/src/components/Chart/Chart.tsx +1 -1
  80. package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +1 -1
  81. package/src/components/DataTable/DataTable.tsx +14 -12
  82. package/src/components/DatePicker/DatePicker.stories.tsx +6 -6
  83. package/src/components/Dropdown/Dropdown.stories.tsx +4 -4
  84. package/src/components/Form/Checkbox.stories.tsx +3 -3
  85. package/src/components/Form/Checkbox.tsx +4 -2
  86. package/src/components/Form/Form.stories.tsx +3 -3
  87. package/src/components/Form/FormGroup.stories.tsx +1 -1
  88. package/src/components/Form/Input.stories.tsx +28 -16
  89. package/src/components/Form/Input.test.tsx +59 -0
  90. package/src/components/Form/Input.tsx +97 -95
  91. package/src/components/Form/Radio.stories.tsx +94 -94
  92. package/src/components/Form/Radio.tsx +2 -2
  93. package/src/components/Form/Select.stories.tsx +4 -4
  94. package/src/components/Form/Select.tsx +2 -2
  95. package/src/components/Form/Textarea.stories.tsx +22 -7
  96. package/src/components/Form/Textarea.test.tsx +45 -0
  97. package/src/components/Form/Textarea.tsx +88 -86
  98. package/src/components/List/List.stories.tsx +2 -2
  99. package/src/components/Modal/Modal.stories.tsx +4 -4
  100. package/src/components/Navigation/Navbar/Navbar.stories.tsx +5 -5
  101. package/src/components/Navigation/Navbar/Navbar.tsx +1 -1
  102. package/src/components/Navigation/README.md +1 -1
  103. package/src/components/Pagination/Pagination.stories.tsx +5 -2
  104. package/src/components/Pagination/Pagination.tsx +1 -1
  105. package/src/components/PhotoViewer/PhotoViewer.stories.tsx +10 -10
  106. package/src/components/Popover/Popover.stories.tsx +1 -1
  107. package/src/components/ProductReview/ProductReview.tsx +1 -1
  108. package/src/components/Progress/Progress.tsx +46 -46
  109. package/src/components/Rating/Rating.stories.tsx +4 -4
  110. package/src/components/Rating/Rating.tsx +8 -8
  111. package/src/components/Slider/Slider.stories.tsx +63 -63
  112. package/src/components/Spinner/Spinner.stories.tsx +2 -2
  113. package/src/components/Spinner/Spinner.test.tsx +35 -0
  114. package/src/components/Spinner/Spinner.tsx +9 -2
  115. package/src/components/Testimonial/Testimonial.stories.tsx +1 -1
  116. package/src/components/Toggle/Toggle.stories.tsx +32 -9
  117. package/src/components/Toggle/Toggle.test.tsx +91 -0
  118. package/src/components/Toggle/Toggle.tsx +44 -27
  119. package/src/components/Tooltip/Tooltip.tsx +1 -1
  120. package/src/layouts/Grid/Grid.stories.tsx +49 -49
  121. package/src/layouts/MasonryGrid/MasonryGrid.stories.tsx +2 -2
  122. package/src/lib/composables/useAccordion.ts +12 -3
  123. package/src/lib/composables/useBreadcrumb.ts +2 -2
  124. package/src/lib/composables/useCallout.ts +7 -7
  125. package/src/lib/composables/useNavbar.ts +1 -1
  126. package/src/lib/constants/components.ts +1 -1
  127. package/src/lib/storybook/InteractiveDemo.tsx +113 -0
  128. package/src/lib/storybook/PreviewContainer.tsx +36 -0
  129. package/src/lib/storybook/VariantsGrid.tsx +21 -0
  130. package/src/lib/storybook/index.ts +3 -0
  131. package/src/lib/theme/core/createThemeObject.ts +9 -5
  132. package/src/lib/theme/devtools/CLI.ts +155 -0
  133. package/src/lib/theme/devtools/DesignTokensCustomizer.stories.tsx +213 -0
  134. package/src/lib/theme/devtools/DesignTokensCustomizer.tsx +566 -0
  135. package/src/lib/theme/devtools/LiveEditor.tsx +2 -1
  136. package/src/lib/theme/devtools/index.ts +3 -0
  137. package/src/lib/theme/errors/errors.ts +8 -0
  138. package/src/lib/theme/runtime/ThemeProvider.tsx +117 -57
  139. package/src/lib/theme/runtime/__tests__/ThemeProvider.integration.test.tsx +305 -0
  140. package/src/lib/theme/runtime/__tests__/ThemeProvider.test.tsx +588 -0
  141. package/src/lib/theme/utils/__tests__/themeValidation.test.ts +264 -0
  142. package/src/lib/theme/utils/index.ts +1 -0
  143. package/src/lib/theme/utils/themeValidation.ts +501 -0
  144. package/src/lib/theme-tools.ts +32 -3
  145. package/src/lib/types/components.ts +81 -26
  146. package/src/lib/utils/themeNaming.ts +1 -1
  147. package/src/styles/06-components/_components.atomix-glass.scss +14 -15
  148. package/src/styles/06-components/_components.callout.scss +29 -33
  149. package/src/styles/06-components/_index.scss +1 -1
  150. package/src/styles/99-utilities/_utilities.display.scss +14 -3
  151. package/src/styles/99-utilities/_utilities.flex.scss +10 -10
  152. package/src/styles/99-utilities/_utilities.text.scss +28 -8
  153. package/scripts/cli/__tests__/cli-commands.test.js +0 -204
  154. package/scripts/cli/__tests__/utils.test.js +0 -201
  155. package/scripts/cli/__tests__/vitest.config.js +0 -26
package/dist/index.js CHANGED
@@ -73,7 +73,7 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
73
73
  CLOSE_BTN_CLASS: "c-callout__close-btn",
74
74
  VARIANT_PREFIX: "c-callout--",
75
75
  CLASSES: {
76
- ONELINE: "c-callout--oneline",
76
+ COMPACT: "c-callout--compact",
77
77
  TOAST: "c-callout--toast",
78
78
  HIDE: "is-hide"
79
79
  }
@@ -1604,7 +1604,12 @@ function useAccordion(initialProps) {
1604
1604
  panelHeight: panelHeight
1605
1605
  },
1606
1606
  toggle: () => {
1607
- defaultProps.disabled || (isControlled ? defaultProps.onOpenChange && defaultProps.onOpenChange(!isOpen) : setInternalOpen((prev => !prev)));
1607
+ if (!defaultProps.disabled) {
1608
+ const nextOpen = !isOpen;
1609
+ isControlled || setInternalOpen(nextOpen), defaultProps.onOpenChange?.(nextOpen),
1610
+ // Call legacy handlers
1611
+ nextOpen ? defaultProps.onOpen?.() : defaultProps.onClose?.();
1612
+ }
1608
1613
  },
1609
1614
  updatePanelHeight: updatePanelHeight,
1610
1615
  panelRef: panelRef,
@@ -1848,7 +1853,13 @@ const {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS, calculateDistance = (pos1, pos2)
1848
1853
  */ GlassFilterComponent.displayName = "GlassFilter";
1849
1854
 
1850
1855
  // Memoize component to prevent unnecessary re-renders
1851
- const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) => prevProps.id === nextProps.id && prevProps.displacementScale === nextProps.displacementScale && prevProps.aberrationIntensity === nextProps.aberrationIntensity && prevProps.mode === nextProps.mode && prevProps.shaderMapUrl === nextProps.shaderMapUrl && prevProps.blurAmount === nextProps.blurAmount)), sharedShaderCache = new Map, AtomixGlassContainer = React.forwardRef((({children: children, className: className = "", style: style, displacementScale: displacementScale = 25, blurAmount: blurAmount = .0625, saturation: saturation = 180, aberrationIntensity: aberrationIntensity = 2, mouseOffset: mouseOffset = {
1856
+ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) => prevProps.id === nextProps.id && prevProps.displacementScale === nextProps.displacementScale && prevProps.aberrationIntensity === nextProps.aberrationIntensity && prevProps.mode === nextProps.mode && prevProps.shaderMapUrl === nextProps.shaderMapUrl && prevProps.blurAmount === nextProps.blurAmount));
1857
+
1858
+ // Module-level counter for deterministic ID generation
1859
+ let idCounter = 0;
1860
+
1861
+ // Module-level shared shader cache with LRU eviction
1862
+ const sharedShaderCache = new Map, AtomixGlassContainer = React.forwardRef((({children: children, className: className = "", style: style, displacementScale: displacementScale = 25, blurAmount: blurAmount = .0625, saturation: saturation = 180, aberrationIntensity: aberrationIntensity = 2, mouseOffset: mouseOffset = {
1852
1863
  x: 0,
1853
1864
  y: 0
1854
1865
  }, globalMousePosition: globalMousePosition = {
@@ -1859,10 +1870,8 @@ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) =>
1859
1870
  height: 0
1860
1871
  }, onClick: onClick, mode: mode = "standard", effectiveDisableEffects: effectiveDisableEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", enableLiquidBlur: enableLiquidBlur = !1, elasticity: elasticity = 0, contentRef: contentRef}, ref) => {
1861
1872
  // Generate a stable, deterministic ID for SSR compatibility
1862
- // Use a counter-based approach to avoid hydration mismatches
1863
- const [filterId] = React.useState((() =>
1864
- // Use a simple counter for deterministic IDs
1865
- "undefined" == typeof window ? `atomix-glass-filter-ssr-${Math.random().toString(36).substring(2, 11)}` : `atomix-glass-filter-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`)), [shaderMapUrl, setShaderMapUrl] = React.useState(""), shaderGeneratorRef = React.useRef(null), shaderUtilsRef = React.useRef(null), shaderDebounceTimeoutRef = React.useRef(null);
1873
+ // Use a module-level counter that's consistent across server and client
1874
+ const filterId = React.useMemo((() => "atomix-glass-filter-" + ++idCounter), []), [shaderMapUrl, setShaderMapUrl] = React.useState(""), shaderGeneratorRef = React.useRef(null), shaderUtilsRef = React.useRef(null), shaderDebounceTimeoutRef = React.useRef(null);
1866
1875
  // Lazy load shader utilities only when shader mode is needed
1867
1876
  React.useEffect((() => {
1868
1877
  "shader" === mode ?
@@ -1905,9 +1914,9 @@ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) =>
1905
1914
  width: glassSize.width,
1906
1915
  height: glassSize.height,
1907
1916
  fragment: selectedShader
1908
- });
1909
- // Use requestIdleCallback if available for non-blocking generation
1910
- const generate = () => {
1917
+ }),
1918
+ // Defer shader generation with longer delay to avoid blocking
1919
+ setTimeout((() => {
1911
1920
  const url = shaderGeneratorRef.current?.updateShader() || "";
1912
1921
  ((key, url) => {
1913
1922
  // Evict oldest entries if at capacity
@@ -1926,20 +1935,15 @@ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) =>
1926
1935
  // Development mode: log cache size
1927
1936
  "undefined" != typeof process && "production" === process.env?.NODE_ENV || sharedShaderCache.size;
1928
1937
  })(cacheKey, url), setShaderMapUrl(url);
1929
- };
1930
- "undefined" != typeof requestIdleCallback ? requestIdleCallback(generate, {
1931
- timeout: 1e3
1932
- }) :
1933
- // Fallback to setTimeout for browsers without requestIdleCallback
1934
- setTimeout(generate, 0);
1938
+ }), 100);
1935
1939
  } catch (error) {
1936
1940
  console.warn("AtomixGlassContainer: Error generating shader map", error), setShaderMapUrl("");
1937
1941
  } else
1938
1942
  // Shader utils not loaded yet, retry after a short delay
1939
1943
  shaderDebounceTimeoutRef.current = setTimeout(generateShader, 100);
1940
1944
  };
1941
- // Debounce with 300ms delay
1942
- shaderDebounceTimeoutRef.current = setTimeout(generateShader, 300);
1945
+ // Debounce with 500ms delay to reduce frequency
1946
+ shaderDebounceTimeoutRef.current = setTimeout(generateShader, 500);
1943
1947
  } else
1944
1948
  // Not in shader mode, clear URL
1945
1949
  setShaderMapUrl("");
@@ -2006,7 +2010,7 @@ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) =>
2006
2010
  backdropFilter: `blur(${blurAmount}px) saturate(${saturation}%) contrast(1.05) brightness(1.05)`
2007
2011
  };
2008
2012
  }
2009
- }), [ filterId, liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion, effectiveDisableEffects, enableLiquidBlur ]), containerVars = React.useMemo((() => {
2013
+ }), [ liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion, effectiveDisableEffects, enableLiquidBlur ]), containerVars = React.useMemo((() => {
2010
2014
  try {
2011
2015
  // Safe extraction of mouse offset values
2012
2016
  const mx = mouseOffset && "number" == typeof mouseOffset.x && !isNaN(mouseOffset.x) ? mouseOffset.x : 0, my = mouseOffset && "number" == typeof mouseOffset.y && !isNaN(mouseOffset.y) ? mouseOffset.y : 0;
@@ -2095,7 +2099,6 @@ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) =>
2095
2099
  });
2096
2100
  }));
2097
2101
 
2098
- // Module-level shared shader cache with LRU eviction
2099
2102
  AtomixGlassContainer.displayName = "AtomixGlassContainer";
2100
2103
 
2101
2104
  // Singleton instance
@@ -2843,14 +2846,16 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
2843
2846
  });
2844
2847
  }
2845
2848
 
2846
- const Accordion = React.memo((({title: title, children: children, defaultOpen: defaultOpen = !1, isOpen: controlledOpen, onOpenChange: onOpenChange, disabled: disabled = !1, iconPosition: iconPosition = "right", icon: icon, className: className = "", style: style, glass: glass}) => {
2849
+ const Accordion = React.memo((({title: title, children: children, defaultOpen: defaultOpen = !1, isOpen: controlledOpen, onOpenChange: onOpenChange, onOpen: onOpen, onClose: onClose, disabled: disabled = !1, iconPosition: iconPosition = "right", icon: icon, className: className = "", style: style, glass: glass}) => {
2847
2850
  // Generate unique IDs for accessibility
2848
2851
  const instanceId = React.useId(), buttonId = `accordion-header-${instanceId}`, panelId = `accordion-panel-${instanceId}`, {state: state, toggle: toggle, updatePanelHeight: updatePanelHeight, panelRef: panelRef, contentRef: contentRef, generateClassNames: generateClassNames, generateHeaderClassNames: generateHeaderClassNames} = useAccordion({
2849
2852
  defaultOpen: defaultOpen,
2850
2853
  disabled: disabled,
2851
2854
  iconPosition: iconPosition,
2852
2855
  isOpen: controlledOpen,
2853
- onOpenChange: onOpenChange
2856
+ onOpenChange: onOpenChange,
2857
+ onOpen: onOpen,
2858
+ onClose: onClose
2854
2859
  }), defaultIcon = jsxRuntime.jsx("i", {
2855
2860
  className: "c-accordion__icon",
2856
2861
  "aria-hidden": "true",
@@ -3337,7 +3342,7 @@ function useBadge(initialProps) {
3337
3342
 
3338
3343
  AvatarGroup.displayName = "AvatarGroup";
3339
3344
 
3340
- const Badge = React.memo((({label: label, variant: variant = "primary", size: size = "md", disabled: disabled = !1, icon: icon, className: className = "", glass: glass, style: style}) => {
3345
+ const Badge = React.memo((({label: label, variant: variant = "primary", size: size = "md", disabled: disabled = !1, icon: icon, onRemove: onRemove, "aria-label": ariaLabel, className: className = "", glass: glass, style: style}) => {
3341
3346
  const {generateBadgeClass: generateBadgeClass} = useBadge({
3342
3347
  variant: variant,
3343
3348
  size: size,
@@ -3350,6 +3355,7 @@ const Badge = React.memo((({label: label, variant: variant = "primary", size: s
3350
3355
  }), badgeElement = jsxRuntime.jsxs("span", {
3351
3356
  className: badgeClass,
3352
3357
  "aria-disabled": disabled,
3358
+ "aria-label": ariaLabel,
3353
3359
  ref: ref,
3354
3360
  style: style,
3355
3361
  children: [ icon && jsxRuntime.jsx("span", {
@@ -3357,6 +3363,13 @@ const Badge = React.memo((({label: label, variant: variant = "primary", size: s
3357
3363
  children: icon
3358
3364
  }), jsxRuntime.jsx("span", {
3359
3365
  children: label
3366
+ }), onRemove && jsxRuntime.jsx("button", {
3367
+ type: "button",
3368
+ className: "c-badge__close",
3369
+ onClick: onRemove,
3370
+ "aria-label": "Remove badge",
3371
+ disabled: disabled,
3372
+ children: "×"
3360
3373
  }) ]
3361
3374
  });
3362
3375
  if (glass) {
@@ -3484,7 +3497,7 @@ const useBlock = () => ({
3484
3497
  * ```
3485
3498
  */ Block.displayName = "Block";
3486
3499
 
3487
- const Breadcrumb = React.memo((({items: items, divider: divider, className: className = "", ariaLabel: ariaLabel = "Breadcrumb", LinkComponent: LinkComponent, style: style}) => {
3500
+ const Breadcrumb = React.memo((({items: items, divider: divider, className: className = "", "aria-label": ariaLabel = "Breadcrumb", LinkComponent: LinkComponent, style: style}) => {
3488
3501
  const breadcrumbClasses = [ BREADCRUMB.CLASSES.BASE, className ].filter(Boolean).join(" ");
3489
3502
  return jsxRuntime.jsx("nav", {
3490
3503
  "aria-label": ariaLabel,
@@ -3587,7 +3600,7 @@ function useButton(initialProps) {
3587
3600
 
3588
3601
  Breadcrumb.displayName = "Breadcrumb";
3589
3602
 
3590
- const Spinner = React.memo((({size: size = "md", variant: variant = "primary", fullscreen: fullscreen = !1, className: className = "", style: style, glass: glass}) => {
3603
+ const Spinner = React.memo((({size: size = "md", variant: variant = "primary", fullscreen: fullscreen = !1, className: className = "", style: style, glass: glass, "aria-label": ariaLabel, role: role = "status"}) => {
3591
3604
  const {generateSpinnerClass: generateSpinnerClass} = useSpinner({
3592
3605
  size: size,
3593
3606
  variant: variant,
@@ -3600,10 +3613,11 @@ const Spinner = React.memo((({size: size = "md", variant: variant = "primary",
3600
3613
  }), spinnerContent = jsxRuntime.jsx("div", {
3601
3614
  className: spinnerClass,
3602
3615
  style: style,
3603
- role: "status",
3616
+ role: role,
3617
+ "aria-label": ariaLabel || "Loading",
3604
3618
  children: jsxRuntime.jsx("span", {
3605
3619
  className: SPINNER.VISUALLY_HIDDEN,
3606
- children: "Loading..."
3620
+ children: ariaLabel || "Loading..."
3607
3621
  })
3608
3622
  });
3609
3623
  if (glass) {
@@ -3655,7 +3669,7 @@ class ThemeNaming {
3655
3669
  * Convert kebab-case to camelCase for JavaScript properties
3656
3670
  * @param str - String to convert
3657
3671
  */ static kebabToCamel(str) {
3658
- return str.replace(/-([a-z])/g, (g => g[1].toUpperCase()));
3672
+ return str.replace(/-([a-z])/g, (g => g[1]?.toUpperCase() ?? ""));
3659
3673
  }
3660
3674
  /**
3661
3675
  * Create a CSS variable name
@@ -3716,7 +3730,7 @@ class ThemeNaming {
3716
3730
 
3717
3731
  ThemeNaming.prefix = "atomix";
3718
3732
 
3719
- const Button = React__default.default.memo( React.forwardRef((({label: label, children: children, onClick: onClick, variant: variant = "primary", size: size = "md", disabled: disabled = !1, loading: loading = !1, loadingText: loadingText, icon: icon, iconName: iconName, iconSize: iconSize = "sm", iconPosition: iconPosition = "start", iconOnly: iconOnly = !1, rounded: rounded = !1, fullWidth: fullWidth = !1, block: block = !1, active: active = !1, selected: selected = !1, type: type = "button", className: className = "", as: Component = "button", href: href, target: target, glass: glass, onHover: onHover, onFocus: onFocus, onBlur: onBlur, ariaLabel: ariaLabel, ariaDescribedBy: ariaDescribedBy, ariaExpanded: ariaExpanded, ariaControls: ariaControls, tabIndex: tabIndex, style: style, LinkComponent: LinkComponent, ...props}, ref) => {
3733
+ const Button = React__default.default.memo( React.forwardRef((({label: label, children: children, onClick: onClick, variant: variant = "primary", size: size = "md", disabled: disabled = !1, loading: loading = !1, loadingText: loadingText, icon: icon, iconName: iconName, iconSize: iconSize = "sm", iconPosition: iconPosition = "start", iconOnly: iconOnly = !1, rounded: rounded = !1, fullWidth: fullWidth = !1, block: block = !1, active: active = !1, selected: selected = !1, type: type = "button", className: className = "", as: Component = "button", href: href, target: target, glass: glass, onHover: onHover, onFocus: onFocus, onBlur: onBlur, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, "aria-expanded": ariaExpanded, "aria-controls": ariaControls, tabIndex: tabIndex, style: style, LinkComponent: LinkComponent, ...props}, ref) => {
3720
3734
  const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement = iconName ? jsxRuntime.jsx(Icon, {
3721
3735
  name: iconName,
3722
3736
  size: iconSize
@@ -4245,7 +4259,7 @@ var includes$3 = getBuiltInPrototypeMethod$3("String", "includes"), isPrototypeO
4245
4259
  /**
4246
4260
  * Callout component for displaying important messages, notifications, or alerts
4247
4261
  */
4248
- const Callout = ({title: title, children: children, icon: icon, variant: variant = "primary", onClose: onClose, actions: actions, oneLine: oneLine = !1, toast: toast = !1, glass: glass, className: className, style: style, ...props}) => {
4262
+ const Callout = ({title: title, children: children, icon: icon, variant: variant = "primary", onClose: onClose, actions: actions, compact: compact = !1, isToast: isToast = !1, glass: glass, className: className, style: style, ...props}) => {
4249
4263
  const {generateCalloutClass: generateCalloutClass, handleClose: handleClose} =
4250
4264
  /**
4251
4265
  * Callout state and functionality
@@ -4256,8 +4270,8 @@ const Callout = ({title: title, children: children, icon: icon, variant: variant
4256
4270
  // Default callout properties
4257
4271
  const defaultProps = {
4258
4272
  variant: "primary",
4259
- oneLine: !1,
4260
- toast: !1,
4273
+ compact: !1,
4274
+ isToast: !1,
4261
4275
  glass: !1,
4262
4276
  ...initialProps
4263
4277
  };
@@ -4268,8 +4282,8 @@ const Callout = ({title: title, children: children, icon: icon, variant: variant
4268
4282
  */ return {
4269
4283
  defaultProps: defaultProps,
4270
4284
  generateCalloutClass: props => {
4271
- const {variant: variant = defaultProps.variant, oneLine: oneLine = defaultProps.oneLine, toast: toast = defaultProps.toast, glass: glass = defaultProps.glass, className: className = ""} = props;
4272
- return `c-callout ${variant ? `c-callout--${variant}` : ""} ${oneLine ? "c-callout--oneline" : ""} ${toast ? "c-callout--toast" : ""} ${glass ? "c-callout--glass" : ""} ${className}`.trim();
4285
+ const {variant: variant = defaultProps.variant, compact: compact = defaultProps.compact, isToast: isToast = defaultProps.isToast, glass: glass = defaultProps.glass, className: className = ""} = props;
4286
+ return `c-callout ${variant ? `c-callout--${variant}` : ""} ${compact ? "c-callout--compact" : ""} ${isToast ? "c-callout--toast" : ""} ${glass ? "c-callout--glass" : ""} ${className}`.trim();
4273
4287
  },
4274
4288
  handleClose: handler => () => {
4275
4289
  handler && handler();
@@ -4277,8 +4291,8 @@ const Callout = ({title: title, children: children, icon: icon, variant: variant
4277
4291
  };
4278
4292
  }({
4279
4293
  variant: variant,
4280
- oneLine: oneLine,
4281
- toast: toast,
4294
+ compact: compact,
4295
+ isToast: isToast,
4282
4296
  glass: glass,
4283
4297
  className: className,
4284
4298
  style: style
@@ -4288,7 +4302,7 @@ const Callout = ({title: title, children: children, icon: icon, variant: variant
4288
4302
  role: "region"
4289
4303
  };
4290
4304
  // For toast notifications or alerts, use appropriate role and live region
4291
- return toast ? (baseAttributes.role = "alert", baseAttributes["aria-live"] = "polite") : _includesInstanceProperty(_context = [ "warning", "error" ]).call(_context, variant) ? (baseAttributes.role = "alert",
4305
+ return isToast ? (baseAttributes.role = "alert", baseAttributes["aria-live"] = "polite") : _includesInstanceProperty(_context = [ "warning", "error" ]).call(_context, variant) ? (baseAttributes.role = "alert",
4292
4306
  baseAttributes["aria-live"] = "assertive") : _includesInstanceProperty(_context2 = [ "info", "success" ]).call(_context2, variant) && (baseAttributes.role = "status",
4293
4307
  baseAttributes["aria-live"] = "polite"), baseAttributes;
4294
4308
  }, calloutContent = jsxRuntime.jsxs(jsxRuntime.Fragment, {
@@ -4334,8 +4348,8 @@ const Callout = ({title: title, children: children, icon: icon, variant: variant
4334
4348
  return jsxRuntime.jsx("div", {
4335
4349
  className: generateCalloutClass({
4336
4350
  variant: variant,
4337
- oneLine: oneLine,
4338
- toast: toast,
4351
+ compact: compact,
4352
+ isToast: isToast,
4339
4353
  glass: glass,
4340
4354
  className: className
4341
4355
  }),
@@ -4357,8 +4371,8 @@ const Callout = ({title: title, children: children, icon: icon, variant: variant
4357
4371
  return jsxRuntime.jsx("div", {
4358
4372
  className: generateCalloutClass({
4359
4373
  variant: variant,
4360
- oneLine: oneLine,
4361
- toast: toast,
4374
+ compact: compact,
4375
+ isToast: isToast,
4362
4376
  glass: glass,
4363
4377
  className: className
4364
4378
  }),
@@ -4385,7 +4399,7 @@ onClick: onClick, onHover: onHover, onFocus: onFocus, href: href, target: target
4385
4399
  // Glass
4386
4400
  glass: glass,
4387
4401
  // Accessibility
4388
- role: role, ariaLabel: ariaLabel, ariaDescribedBy: ariaDescribedBy, tabIndex: tabIndex,
4402
+ role: role, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, tabIndex: tabIndex,
4389
4403
  // Styling
4390
4404
  className: className = "", style: style, ...rest}, ref) => {
4391
4405
  // Determine if card is clickable/interactive
@@ -5933,7 +5947,7 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
5933
5947
  tabIndex: 0,
5934
5948
  ...props,
5935
5949
  children: [ (title || subtitle || showToolbar) && jsxRuntime.jsxs("div", {
5936
- className: `${CHART.HEADER_CLASS} u-d-flex u-justify-between u-align-items-start u-gap-4`,
5950
+ className: `${CHART.HEADER_CLASS} u-flex u-justify-between u-items-start u-gap-4`,
5937
5951
  children: [ jsxRuntime.jsxs("div", {
5938
5952
  className: `${CHART.HEADER_CONTENT_CLASS} u-flex-1`,
5939
5953
  children: [ title && jsxRuntime.jsx("h3", {
@@ -9247,7 +9261,7 @@ const range = (start, end) => {
9247
9261
  "aria-hidden": "true"
9248
9262
  })
9249
9263
  })
9250
- }))), Pagination = React.memo((({currentPage: currentPage = PAGINATION_DEFAULTS.currentPage, totalPages: totalPages = PAGINATION_DEFAULTS.totalPages, onPageChange: onPageChange, siblingCount: siblingCount = PAGINATION_DEFAULTS.siblingCount, showFirstLastButtons: showFirstLastButtons = PAGINATION_DEFAULTS.showFirstLastButtons, showPrevNextButtons: showPrevNextButtons = PAGINATION_DEFAULTS.showPrevNextButtons, showSearch: showSearch = !1, searchPlaceholder: searchPlaceholder = "Go to page", size: size = PAGINATION_DEFAULTS.size, className: className = "", style: style, ariaLabel: ariaLabel = "Pagination", glass: glass}) => {
9264
+ }))), Pagination = React.memo((({currentPage: currentPage = PAGINATION_DEFAULTS.currentPage, totalPages: totalPages = PAGINATION_DEFAULTS.totalPages, onPageChange: onPageChange, siblingCount: siblingCount = PAGINATION_DEFAULTS.siblingCount, showFirstLastButtons: showFirstLastButtons = PAGINATION_DEFAULTS.showFirstLastButtons, showPrevNextButtons: showPrevNextButtons = PAGINATION_DEFAULTS.showPrevNextButtons, showSearch: showSearch = !1, searchPlaceholder: searchPlaceholder = "Go to page", size: size = PAGINATION_DEFAULTS.size, className: className = "", style: style, "aria-label": ariaLabel = "Pagination", glass: glass}) => {
9251
9265
  const {paginationRange: paginationRange, goToPage: goToPage, nextPage: nextPage, prevPage: prevPage, firstPage: firstPage, lastPage: lastPage} = usePagination({
9252
9266
  currentPage: currentPage,
9253
9267
  totalPages: totalPages,
@@ -9414,7 +9428,7 @@ function useCheckbox(initialProps) {
9414
9428
 
9415
9429
  /**
9416
9430
  * Checkbox - A component for checkbox inputs
9417
- */ const Checkbox = React.memo((({label: label, checked: checked = !1, onChange: onChange, className: className = "", style: style, disabled: disabled = !1, required: required = !1, id: id, name: name, value: value, invalid: invalid = !1, valid: valid = !1, indeterminate: indeterminate = !1, ariaLabel: ariaLabel, ariaDescribedBy: ariaDescribedBy, glass: glass}) => {
9431
+ */ const Checkbox = React.memo((({label: label, checked: checked = !1, onChange: onChange, className: className = "", style: style, disabled: disabled = !1, required: required = !1, id: id, name: name, value: value, invalid: invalid = !1, valid: valid = !1, indeterminate: indeterminate = !1, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, onClick: onClick, glass: glass}) => {
9418
9432
  const {generateCheckboxClass: generateCheckboxClass, checkboxRef: checkboxRef} = useCheckbox({
9419
9433
  indeterminate: indeterminate,
9420
9434
  disabled: disabled,
@@ -9435,6 +9449,7 @@ function useCheckbox(initialProps) {
9435
9449
  className: "c-checkbox__input",
9436
9450
  checked: checked,
9437
9451
  onChange: onChange,
9452
+ onClick: onClick,
9438
9453
  disabled: disabled,
9439
9454
  required: required,
9440
9455
  id: id,
@@ -9732,7 +9747,7 @@ const DataTable = React.memo((({data: data, columns: columns, className: classN
9732
9747
  }), []), handleDrop = React.useCallback(((e, dropIndex) => {
9733
9748
  if (e.preventDefault(), null !== dragStartIndex && dragStartIndex !== dropIndex && onColumnReorder) {
9734
9749
  const newOrder = [ ...visibleColumns.map((col => col.key)) ], [removed] = newOrder.splice(dragStartIndex, 1);
9735
- newOrder.splice(dropIndex, 0, removed), onColumnReorder(newOrder);
9750
+ removed && (newOrder.splice(dropIndex, 0, removed), onColumnReorder(newOrder));
9736
9751
  }
9737
9752
  setDragStartIndex(null), setDragOverIndex(null);
9738
9753
  }), [ dragStartIndex, visibleColumns, onColumnReorder ]), handleExport = React.useCallback((format => {
@@ -10042,7 +10057,7 @@ const DataTable = React.memo((({data: data, columns: columns, className: classN
10042
10057
  showFirstLastButtons: !0,
10043
10058
  showPrevNextButtons: !0,
10044
10059
  size: "sm",
10045
- ariaLabel: "Data table pagination",
10060
+ "aria-label": "Data table pagination",
10046
10061
  className: "c-data-table__pagination"
10047
10062
  })
10048
10063
  }) ]
@@ -11026,7 +11041,7 @@ function useInput(initialProps) {
11026
11041
  * Input - A component for text input fields
11027
11042
  */ FormGroup.displayName = "FormGroup";
11028
11043
 
11029
- const Input = React.memo( React.forwardRef((({type: type = "text", value: value, onChange: onChange, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder, className: className = "", style: style, disabled: disabled = !1, required: required = !1, readOnly: readOnly = !1, id: id, name: name, autoComplete: autoComplete, autoFocus: autoFocus = !1, size: size = "md", variant: variant, invalid: invalid = !1, valid: valid = !1, maxLength: maxLength, minLength: minLength, pattern: pattern, min: min, max: max, step: step, ariaLabel: ariaLabel, ariaDescribedBy: ariaDescribedBy, glass: glass}, ref) => {
11044
+ const Input = React.memo( React.forwardRef((({type: type = "text", value: value, defaultValue: defaultValue, onChange: onChange, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder, className: className = "", style: style, disabled: disabled = !1, required: required = !1, readOnly: readOnly = !1, id: id, name: name, autoComplete: autoComplete, autoFocus: autoFocus = !1, size: size = "md", variant: variant, invalid: invalid = !1, valid: valid = !1, maxLength: maxLength, minLength: minLength, pattern: pattern, min: min, max: max, step: step, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, glass: glass}, ref) => {
11030
11045
  const {generateInputClass: generateInputClass} = useInput({
11031
11046
  size: size,
11032
11047
  variant: variant,
@@ -11046,6 +11061,7 @@ const Input = React.memo( React.forwardRef((({type: type = "text", value: value
11046
11061
  type: type,
11047
11062
  className: inputClass,
11048
11063
  value: value,
11064
+ defaultValue: defaultValue,
11049
11065
  onChange: onChange,
11050
11066
  onBlur: onBlur,
11051
11067
  onFocus: onFocus,
@@ -11300,7 +11316,7 @@ function useHero(initialProps) {
11300
11316
  backdrop: !1,
11301
11317
  closeOnOutsideClick: !0,
11302
11318
  closeOnEscape: !0,
11303
- ariaLabel: "Main navigation",
11319
+ "aria-label": "Main navigation",
11304
11320
  ...initialProps
11305
11321
  }, [isExpanded, setIsExpanded] = React.useState(defaultProps.expanded || !1);
11306
11322
  // Local expanded state for when not controlled externally
@@ -12100,7 +12116,7 @@ const DEFAULT_ATOMIX_FONTS = [ {
12100
12116
  items: [],
12101
12117
  divider: BREADCRUMB.DEFAULTS.DIVIDER,
12102
12118
  className: "",
12103
- ariaLabel: "Breadcrumb",
12119
+ "aria-label": "Breadcrumb",
12104
12120
  ...initialOptions
12105
12121
  },
12106
12122
  generateBreadcrumbClass: options => {
@@ -12433,21 +12449,21 @@ function useSlider(options) {
12433
12449
  const [interaction, setInteraction] = React.useState({
12434
12450
  hoveredIndex: null,
12435
12451
  selectedIndex: null
12436
- }), handlePointHover = React.useCallback((index => {
12437
- setInteraction((prev => ({
12438
- ...prev,
12439
- hoveredIndex: index
12440
- })));
12441
- }), []), handlePointClick = React.useCallback((index => {
12442
- setInteraction((prev => ({
12443
- ...prev,
12444
- selectedIndex: prev.selectedIndex === index ? null : index
12445
- })));
12446
- }), []);
12452
+ });
12447
12453
  return {
12448
12454
  interaction: interaction,
12449
- handlePointHover: handlePointHover,
12450
- handlePointClick: handlePointClick,
12455
+ handlePointHover: React.useCallback((index => {
12456
+ setInteraction((prev => ({
12457
+ ...prev,
12458
+ hoveredIndex: index
12459
+ })));
12460
+ }), []),
12461
+ handlePointClick: React.useCallback((index => {
12462
+ setInteraction((prev => ({
12463
+ ...prev,
12464
+ selectedIndex: prev.selectedIndex === index ? null : index
12465
+ })));
12466
+ }), []),
12451
12467
  clearInteraction: React.useCallback((() => {
12452
12468
  setInteraction({
12453
12469
  hoveredIndex: null,
@@ -12501,7 +12517,7 @@ var composablesImport = Object.freeze({
12501
12517
 
12502
12518
  /**
12503
12519
  * Select - A component for dropdown selection
12504
- */ const Select = React.memo((({options: options = [], value: value, onChange: onChange, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder = "Select an option", className: className = "", style: style, disabled: disabled = !1, required: required = !1, id: id, name: name, size: size = "md", invalid: invalid = !1, valid: valid = !1, multiple: multiple = !1, ariaLabel: ariaLabel, ariaDescribedBy: ariaDescribedBy, glass: glass}) => {
12520
+ */ const Select = React.memo((({options: options = [], value: value, onChange: onChange, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder = "Select an option", className: className = "", style: style, disabled: disabled = !1, required: required = !1, id: id, name: name, size: size = "md", invalid: invalid = !1, valid: valid = !1, multiple: multiple = !1, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, glass: glass}) => {
12505
12521
  const {generateSelectClass: generateSelectClass} = useSelect({
12506
12522
  size: size,
12507
12523
  disabled: disabled,
@@ -12647,7 +12663,7 @@ Select.displayName = "Select";
12647
12663
  /**
12648
12664
  * Radio - A component for radio button inputs
12649
12665
  */
12650
- const Radio = React.memo((({label: label, checked: checked = !1, onChange: onChange, className: className = "", style: style, disabled: disabled = !1, required: required = !1, id: id, name: name, value: value, invalid: invalid = !1, valid: valid = !1, ariaLabel: ariaLabel, ariaDescribedBy: ariaDescribedBy, glass: glass}) => {
12666
+ const Radio = React.memo((({label: label, checked: checked = !1, onChange: onChange, className: className = "", style: style, disabled: disabled = !1, required: required = !1, id: id, name: name, value: value, invalid: invalid = !1, valid: valid = !1, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, glass: glass}) => {
12651
12667
  const {generateRadioClass: generateRadioClass} = useRadio({
12652
12668
  disabled: disabled,
12653
12669
  invalid: invalid,
@@ -12705,7 +12721,7 @@ Radio.displayName = "Radio";
12705
12721
  /**
12706
12722
  * Textarea - A component for multiline text input
12707
12723
  */
12708
- const Textarea = React.memo( React.forwardRef((({value: value, onChange: onChange, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder, className: className = "", style: style, disabled: disabled = !1, required: required = !1, readOnly: readOnly = !1, id: id, name: name, rows: rows = 4, cols: cols, maxLength: maxLength, minLength: minLength, size: size = "md", variant: variant, invalid: invalid = !1, valid: valid = !1, autoFocus: autoFocus = !1, ariaLabel: ariaLabel, ariaDescribedBy: ariaDescribedBy, glass: glass}, ref) => {
12724
+ const Textarea = React.memo( React.forwardRef((({value: value, defaultValue: defaultValue, onChange: onChange, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder, className: className = "", style: style, disabled: disabled = !1, required: required = !1, readOnly: readOnly = !1, id: id, name: name, rows: rows = 4, cols: cols, maxLength: maxLength, minLength: minLength, size: size = "md", variant: variant, invalid: invalid = !1, valid: valid = !1, autoFocus: autoFocus = !1, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, glass: glass}, ref) => {
12709
12725
  const {generateTextareaClass: generateTextareaClass} = useTextarea({
12710
12726
  size: size,
12711
12727
  variant: variant,
@@ -12723,6 +12739,7 @@ const Textarea = React.memo( React.forwardRef((({value: value, onChange: onChan
12723
12739
  ref: ref,
12724
12740
  className: textareaClass,
12725
12741
  value: value,
12742
+ defaultValue: defaultValue,
12726
12743
  onChange: onChange,
12727
12744
  onBlur: onBlur,
12728
12745
  onFocus: onFocus,
@@ -14271,7 +14288,7 @@ NavItem.displayName = "NavItem";
14271
14288
  * </Navbar>
14272
14289
  * ```
14273
14290
  */
14274
- const Navbar = React.forwardRef((({brand: brand, children: children, variant: variant, position: position = "static", containerWidth: containerWidth, collapsible: collapsible = !0, expanded: expanded, onToggle: onToggle, className: className = "", style: style, disabled: disabled = !1, backdrop: backdrop = !1, closeOnOutsideClick: closeOnOutsideClick = !0, closeOnEscape: closeOnEscape = !0, ariaLabel: ariaLabel = "Main navigation", id: id, glass: glass}, ref) => {
14291
+ const Navbar = React.forwardRef((({brand: brand, children: children, variant: variant, position: position = "static", containerWidth: containerWidth, collapsible: collapsible = !0, expanded: expanded, onToggle: onToggle, className: className = "", style: style, disabled: disabled = !1, backdrop: backdrop = !1, closeOnOutsideClick: closeOnOutsideClick = !0, closeOnEscape: closeOnEscape = !0, "aria-label": ariaLabel = "Main navigation", id: id, glass: glass}, ref) => {
14275
14292
  const {generateNavbarClass: generateNavbarClass, generateContainerStyle: generateContainerStyle, generateCollapseClass: generateCollapseClass} = useNavbar({
14276
14293
  position: position,
14277
14294
  collapsible: collapsible,
@@ -16355,7 +16372,7 @@ const PopoverContext = React.createContext({
16355
16372
  /**
16356
16373
  * Hook for managing rating component state and interactions
16357
16374
  */
16358
- const Rating = React.forwardRef((({value: valueProp = 0, defaultValue: defaultValue, maxValue: maxValue = 5, allowHalf: allowHalf = !1, readOnly: readOnly = !1, size: size = "md", color: color, onChange: onChange, className: className = "", style: style, label: label, id: id, useVanillaJS: useVanillaJS = !1, glass: glass, ...restProps}, ref) => {
16375
+ const Rating = React.forwardRef((({value: valueProp = 0, defaultValue: defaultValue, maxValue: maxValue = 5, allowHalf: allowHalf = !1, readOnly: readOnly = !1, size: size = "md", variant: variant, onChange: onChange, className: className = "", style: style, label: label, id: id, useVanillaJS: useVanillaJS = !1, glass: glass, ...restProps}, ref) => {
16359
16376
  const internalRef = React.useRef(null), ratingInstance = React.useRef(null), {currentValue: currentValue, hoverValue: hoverValue, focusedIndex: focusedIndex, setHoverValue: setHoverValue, setFocused: setFocused, handleKeyDown: handleKeyDown} = (({value: value = 0, maxValue: maxValue = 5, allowHalf: allowHalf = !1, readOnly: readOnly = !1, onChange: onChange}) => {
16360
16377
  // Determine if component is in controlled mode
16361
16378
  const isControlled = void 0 !== onChange, [internalValue, setInternalValue] = React.useState(value), [hoverValue, setHoverValue] = React.useState(null), [focusedIndex, setFocusedIndex] = React.useState(null), currentValue = isControlled ? value : internalValue, handleMouseEnter = React.useCallback((starValue => {
@@ -16450,7 +16467,7 @@ const Rating = React.forwardRef((({value: valueProp = 0, defaultValue: defaultV
16450
16467
  return () => {
16451
16468
  ratingInstance.current && ratingInstance.current.destroy();
16452
16469
  };
16453
- }), [ useVanillaJS, valueProp, defaultValue, maxValue, allowHalf, readOnly, size, color, onChange ]),
16470
+ }), [ useVanillaJS, valueProp, defaultValue, maxValue, allowHalf, readOnly, size, variant, onChange ]),
16454
16471
  // Update vanilla JS implementation when props change
16455
16472
  React.useEffect((() => {
16456
16473
  useVanillaJS && ratingInstance.current && ratingInstance.current.updateOptions({
@@ -16459,11 +16476,11 @@ const Rating = React.forwardRef((({value: valueProp = 0, defaultValue: defaultV
16459
16476
  allowHalf: allowHalf,
16460
16477
  readOnly: readOnly,
16461
16478
  size: size,
16462
- color: color
16479
+ variant: variant
16463
16480
  });
16464
- }), [ useVanillaJS, valueProp, defaultValue, maxValue, allowHalf, readOnly, size, color ]);
16481
+ }), [ useVanillaJS, valueProp, defaultValue, maxValue, allowHalf, readOnly, size, variant ]);
16465
16482
  // Determine CSS classes
16466
- const ratingClasses = [ "c-rating", "sm" === size ? RATING.CLASSES.SMALL : "", "lg" === size ? RATING.CLASSES.LARGE : "", color ? `c-rating--${color}` : "", className ].filter(Boolean).join(" ");
16483
+ const ratingClasses = [ "c-rating", "sm" === size ? RATING.CLASSES.SMALL : "", "lg" === size ? RATING.CLASSES.LARGE : "", variant ? `c-rating--${variant}` : "", className ].filter(Boolean).join(" ");
16467
16484
  // If using vanilla JS, just render the container
16468
16485
  if (useVanillaJS) return jsxRuntime.jsx("div", {
16469
16486
  className: ratingClasses,
@@ -16487,7 +16504,7 @@ const Rating = React.forwardRef((({value: valueProp = 0, defaultValue: defaultV
16487
16504
  const stars = [], roundedValue = allowHalf ? Math.floor(2 * effectiveValue) / 2 : Math.round(effectiveValue), componentId = id || `rating-${Math.random().toString(36).substring(2, 9)}`;
16488
16505
  for (let i = 1; i <= maxValue; i++) {
16489
16506
  // For half-star support
16490
- const isFullStar = i <= Math.floor(roundedValue), isHalfStar = allowHalf && i - .5 === roundedValue, starClass = [ "c-rating__star", isFullStar ? RATING.CLASSES.FULL : "", isHalfStar ? RATING.CLASSES.HALF : "", color ? `c-rating__star--${color}` : "", focusedIndex === i ? "c-rating__star--focused" : "" ].filter(Boolean).join(" "), starId = `${componentId}-star-${i}`;
16507
+ const isFullStar = i <= Math.floor(roundedValue), isHalfStar = allowHalf && i - .5 === roundedValue, starClass = [ "c-rating__star", isFullStar ? RATING.CLASSES.FULL : "", isHalfStar ? RATING.CLASSES.HALF : "", variant ? `c-rating__star--${variant}` : "", focusedIndex === i ? "c-rating__star--focused" : "" ].filter(Boolean).join(" "), starId = `${componentId}-star-${i}`;
16491
16508
  stars.push(jsxRuntime.jsx("div", {
16492
16509
  id: starId,
16493
16510
  className: starClass,
@@ -16567,8 +16584,8 @@ const Rating = React.forwardRef((({value: valueProp = 0, defaultValue: defaultV
16567
16584
  * <Rating value={3} onChange={handleRatingChange} />
16568
16585
  *
16569
16586
  * @example
16570
- * // Read-only with custom color
16571
- * <Rating value={4.5} readOnly color="warning" />
16587
+ * // Read-only with custom variant
16588
+ * <Rating value={4.5} readOnly variant="warning" />
16572
16589
  *
16573
16590
  * @example
16574
16591
  * // With half-star support
@@ -16642,7 +16659,7 @@ const ProductReview = ({productName: productName, productImage: productImage, in
16642
16659
  allowHalf: allowHalf,
16643
16660
  maxValue: maxRating,
16644
16661
  size: "lg",
16645
- color: ratingColor
16662
+ variant: ratingColor
16646
16663
  }), jsxRuntime.jsx("span", {
16647
16664
  className: "c-rating__value",
16648
16665
  children: rating > 0 ? rating.toFixed(1) : "Select a rating"
@@ -16680,7 +16697,7 @@ ProductReview.displayName = "ProductReview";
16680
16697
  /**
16681
16698
  * Hook for managing Progress component state and behavior
16682
16699
  */
16683
- const Progress = React.memo( React.forwardRef((({value: value, variant: variant = "primary", size: size = "md", className: className = "", style: style, disabled: disabled = !1, ariaLabel: ariaLabel = PROGRESS.DEFAULTS.ARIA_LABEL, glass: glass}, ref) => {
16700
+ const Progress = React.memo( React.forwardRef((({value: value, variant: variant = "primary", size: size = "md", className: className = "", style: style, disabled: disabled = !1, "aria-label": ariaLabel = PROGRESS.DEFAULTS.ARIA_LABEL, glass: glass}, ref) => {
16684
16701
  const {progressValue: progressValue, progressStyle: progressStyle, progressClasses: progressClasses} = (({value: value, variant: variant = "primary", size: size = "md", className: className = ""}) => {
16685
16702
  // Clamp value between 0 and 100
16686
16703
  const progressValue = Math.min(Math.max(value, 0), 100), baseClass = "c-progress";
@@ -17370,28 +17387,29 @@ Todo.displayName = "Todo";
17370
17387
  /**
17371
17388
  * Toggle component for switching between two states
17372
17389
  */
17373
- const Toggle = ({initialOn: initialOn = !1, onToggleOn: onToggleOn, onToggleOff: onToggleOff, disabled: disabled = !1, className: className = "", style: style, glass: glass}) => {
17374
- const [isOn, setIsOn] = React.useState(initialOn), handleClick = () => {
17390
+ const Toggle = ({checked: controlledChecked, defaultChecked: defaultChecked = !1, onChange: onChange, disabled: disabled = !1, className: className = "", style: style, glass: glass, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy}) => {
17391
+ const isControlled = void 0 !== controlledChecked, [internalChecked, setInternalChecked] = React.useState(defaultChecked), isChecked = isControlled ? controlledChecked : internalChecked, handleClick = React.useCallback((() => {
17375
17392
  if (disabled) return;
17376
- const newState = !isOn;
17377
- setIsOn(newState), newState ? onToggleOn && onToggleOn() : onToggleOff && onToggleOff();
17378
- }, toggleContent = jsxRuntime.jsx("div", {
17379
- className: `c-toggle ${isOn ? TOGGLE.CLASSES.IS_ON : ""} ${disabled ? "is-disabled" : ""} ${className}`,
17393
+ const nextChecked = !isChecked;
17394
+ isControlled || setInternalChecked(nextChecked), onChange?.(nextChecked);
17395
+ }), [ disabled, isChecked, isControlled, onChange ]), toggleClass = [ "c-toggle", isChecked && TOGGLE.CLASSES.IS_ON, disabled && "is-disabled", className ].filter(Boolean).join(" "), toggleContent = jsxRuntime.jsx("div", {
17396
+ className: toggleClass,
17380
17397
  style: style,
17381
17398
  onClick: handleClick,
17382
17399
  onKeyDown: e => {
17383
17400
  disabled || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), handleClick());
17384
17401
  },
17385
17402
  role: "switch",
17386
- "aria-checked": isOn,
17403
+ "aria-checked": isChecked,
17387
17404
  tabIndex: disabled ? -1 : 0,
17388
17405
  "aria-disabled": disabled,
17406
+ "aria-label": ariaLabel,
17407
+ "aria-describedby": ariaDescribedBy,
17389
17408
  children: jsxRuntime.jsx("div", {
17390
17409
  className: "c-toggle__switch"
17391
17410
  })
17392
17411
  });
17393
- // Handle toggle click
17394
- if (glass) {
17412
+ if (glass) {
17395
17413
  // Default glass settings for toggles
17396
17414
  const defaultGlassProps = {
17397
17415
  displacementScale: 60,
@@ -17537,7 +17555,7 @@ const Tooltip = React.memo((({content: content, children: children, position: p
17537
17555
  delay: delay
17538
17556
  });
17539
17557
  return jsxRuntime.jsxs("div", {
17540
- className: "u-position-relative u-d-inline-block",
17558
+ className: "u-position-relative u-inline-block",
17541
17559
  style: style,
17542
17560
  ...wrapperProps,
17543
17561
  children: [ jsxRuntime.jsx("div", {
@@ -19192,6 +19210,14 @@ const defaultTokens = {
19192
19210
  ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
19193
19211
  /** CSS injection failed */
19194
19212
  ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
19213
+ /** Invalid color format */
19214
+ ThemeErrorCode.INVALID_COLOR_FORMAT = "INVALID_COLOR_FORMAT",
19215
+ /** Missing required token */
19216
+ ThemeErrorCode.MISSING_REQUIRED_TOKEN = "MISSING_REQUIRED_TOKEN",
19217
+ /** Accessibility contrast violation */
19218
+ ThemeErrorCode.CONTRAST_VIOLATION = "CONTRAST_VIOLATION",
19219
+ /** Invalid token type */
19220
+ ThemeErrorCode.INVALID_TOKEN_TYPE = "INVALID_TOKEN_TYPE",
19195
19221
  /** Unknown error */
19196
19222
  ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
19197
19223
  }(ThemeErrorCode || (ThemeErrorCode = {}));
@@ -19493,27 +19519,6 @@ class ThemeLogger {
19493
19519
  return Object.keys(registry).length;
19494
19520
  }
19495
19521
 
19496
- /**
19497
- * Core Theme Engine
19498
- *
19499
- * Core theme creation, composition, and registry functionality
19500
- */ var index = Object.freeze({
19501
- __proto__: null,
19502
- clearThemes: clearThemes,
19503
- createTheme: createTheme,
19504
- createThemeRegistry: createThemeRegistry,
19505
- deepMerge: deepMerge,
19506
- extendTheme: extendTheme,
19507
- getAllThemes: getAllThemes,
19508
- getTheme: getTheme,
19509
- getThemeCount: getThemeCount,
19510
- getThemeIds: getThemeIds,
19511
- hasTheme: hasTheme,
19512
- mergeTheme: mergeTheme,
19513
- registerTheme: registerTheme,
19514
- unregisterTheme: unregisterTheme
19515
- });
19516
-
19517
19522
  /**
19518
19523
  * CSS Injection Utilities
19519
19524
  *
@@ -19684,7 +19689,7 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
19684
19689
  // ============================================================================
19685
19690
  /**
19686
19691
  * Convert hex color to RGB object
19687
- */ function hexToRgb(hex) {
19692
+ */ function hexToRgb$1(hex) {
19688
19693
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
19689
19694
  return result ? {
19690
19695
  r: parseInt(result[1], 16),
@@ -19704,7 +19709,7 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
19704
19709
  * Calculate relative luminance of a color
19705
19710
  * Used for determining contrast ratios
19706
19711
  */ function getLuminance(color) {
19707
- const rgb = hexToRgb(color);
19712
+ const rgb = hexToRgb$1(color);
19708
19713
  if (!rgb) return 0;
19709
19714
  const {r: r, g: g, b: b} = rgb, [rs, gs, bs] = [ r ?? 0, g ?? 0, b ?? 0 ].map((c => {
19710
19715
  const val = c / 255;
@@ -19734,7 +19739,7 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
19734
19739
  * @param amount - Amount to lighten (0-1), default 0.2
19735
19740
  * @returns Lightened hex color
19736
19741
  */ function lighten(color, amount = .2) {
19737
- const rgb = hexToRgb(color);
19742
+ const rgb = hexToRgb$1(color);
19738
19743
  if (!rgb) return color;
19739
19744
  const {r: r, g: g, b: b} = rgb, lightenValue = val => Math.min(255, Math.round(val + (255 - val) * amount));
19740
19745
  return rgbToHex(lightenValue(r), lightenValue(g), lightenValue(b));
@@ -19747,7 +19752,7 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
19747
19752
  * @param amount - Amount to darken (0-1), default 0.2
19748
19753
  * @returns Darkened hex color
19749
19754
  */ function darken(color, amount = .2) {
19750
- const rgb = hexToRgb(color);
19755
+ const rgb = hexToRgb$1(color);
19751
19756
  if (!rgb) return color;
19752
19757
  const {r: r, g: g, b: b} = rgb, darkenValue = val => Math.max(0, Math.round(val * (1 - amount)));
19753
19758
  return rgbToHex(darkenValue(r), darkenValue(g), darkenValue(b));
@@ -19760,7 +19765,7 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
19760
19765
  * @param opacity - Opacity value (0-1)
19761
19766
  * @returns RGBA color string
19762
19767
  */ function alpha(color, opacity) {
19763
- const rgb = hexToRgb(color);
19768
+ const rgb = hexToRgb$1(color);
19764
19769
  if (!rgb) return color;
19765
19770
  const {r: r, g: g, b: b} = rgb;
19766
19771
  return `rgba(${r}, ${g}, ${b}, ${Math.max(0, Math.min(1, opacity))})`;
@@ -19779,7 +19784,7 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
19779
19784
  */
19780
19785
  function generateColorScale(baseColor, prefix, colorName) {
19781
19786
  const vars = {};
19782
- if (!hexToRgb(baseColor)) return vars;
19787
+ if (!hexToRgb$1(baseColor)) return vars;
19783
19788
  // Generate 10-step scale
19784
19789
  // Steps 1-5: lighter variations
19785
19790
  // Step 6: base color
@@ -19825,7 +19830,7 @@ function generateCSSVariables(theme, options = {}) {
19825
19830
  // Main color (flat structure, matches SCSS: --atomix-primary)
19826
19831
  vars[`${prefix}-${key}`] = color.main;
19827
19832
  // Generate RGB for transparency support (matches SCSS: --atomix-primary-rgb)
19828
- const rgb = hexToRgb(color.main);
19833
+ const rgb = hexToRgb$1(color.main);
19829
19834
  // Generate full color scale (1-10) - matches SCSS: --atomix-primary-1 through --atomix-primary-10
19830
19835
  // Only for primary, secondary, error, warning, info, success (not for light/dark)
19831
19836
  if (rgb && (vars[`${prefix}-${key}-rgb`] = `${rgb.r}, ${rgb.g}, ${rgb.b}`), "light" !== key && "dark" !== key) {
@@ -19908,11 +19913,11 @@ function generateCSSVariables(theme, options = {}) {
19908
19913
  // Heading color (defaults to text primary) - matches SCSS: --atomix-heading-color
19909
19914
  palette.text && (vars[`${prefix}-heading-color`] = palette.text.primary), palette.primary) {
19910
19915
  vars[`${prefix}-link-color`] = palette.primary.main;
19911
- const linkRgb = hexToRgb(palette.primary.main);
19916
+ const linkRgb = hexToRgb$1(palette.primary.main);
19912
19917
  linkRgb && (vars[`${prefix}-link-color-rgb`] = `${linkRgb.r}, ${linkRgb.g}, ${linkRgb.b}`),
19913
19918
  // Link hover color (slightly darker)
19914
19919
  vars[`${prefix}-link-hover-color`] = palette.primary.dark || darken(palette.primary.main, .1);
19915
- const linkHoverRgb = hexToRgb(palette.primary.dark || darken(palette.primary.main, .1));
19920
+ const linkHoverRgb = hexToRgb$1(palette.primary.dark || darken(palette.primary.main, .1));
19916
19921
  linkHoverRgb && (vars[`${prefix}-link-hover-color-rgb`] = `${linkHoverRgb.r}, ${linkHoverRgb.g}, ${linkHoverRgb.b}`),
19917
19922
  // Link decoration (default: none, matching tokens list)
19918
19923
  vars[`${prefix}-link-decoration`] = "none";
@@ -20370,17 +20375,292 @@ function generateClassName(block, element, modifiers) {
20370
20375
  ThemeContext.displayName = "ThemeContext";
20371
20376
 
20372
20377
  /**
20373
- * Theme Provider
20378
+ * Theme Validation Utilities
20374
20379
  *
20375
- * React context provider for theme management with separated concerns.
20376
- * Simplified version focusing on core functionality:
20377
- * - String-based themes (CSS files)
20378
- * - DesignTokens (dynamic themes)
20379
- * - Persistence via localStorage
20380
- *
20381
- * Falls back to 'default' theme if no configuration is found.
20380
+ * Comprehensive validation utilities for DesignTokens objects.
20381
+ * Includes color format validation, accessibility checks, and required properties verification.
20382
20382
  */
20383
- 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}) => {
20383
+ const logger$1 = getLogger(), COLOR_PATTERNS = {
20384
+ /** Hex color: #RGB, #RRGGBB, #RRGGBBAA */
20385
+ hex: /^#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{4}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$/,
20386
+ /** RGB color: rgb(r, g, b) or rgb(r, g, b, a) */
20387
+ rgb: /^rgb\(\s*(\d{1,3}(?:\.\d+)?)\s*,\s*(\d{1,3}(?:\.\d+)?)\s*,\s*(\d{1,3}(?:\.\d+)?)\s*(?:,\s*([01]?\.?\d+))?\s*\)$/,
20388
+ /** RGBA color: rgba(r, g, b, a) */
20389
+ rgba: /^rgba\(\s*(\d{1,3}(?:\.\d+)?)\s*,\s*(\d{1,3}(?:\.\d+)?)\s*,\s*(\d{1,3}(?:\.\d+)?)\s*,\s*([01]?\.?\d+)\s*\)$/,
20390
+ /** HSL color: hsl(h, s%, l%) */
20391
+ hsl: /^hsl\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*\)$/,
20392
+ /** HSLA color: hsla(h, s%, l%, a) */
20393
+ hsla: /^hsla\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*,\s*([01]?\.?\d+)\s*\)$/
20394
+ }, REQUIRED_COLOR_TOKENS = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ], REQUIRED_TEXT_EMPHASIS_TOKENS = [ "primary-text-emphasis", "secondary-text-emphasis", "tertiary-text-emphasis", "disabled-text-emphasis" ], ACCESSIBILITY_CHECKS = [ {
20395
+ text: "primary-text-emphasis",
20396
+ background: "primary-bg-subtle",
20397
+ name: "Primary text on subtle background"
20398
+ }, {
20399
+ text: "secondary-text-emphasis",
20400
+ background: "secondary-bg-subtle",
20401
+ name: "Secondary text on subtle background"
20402
+ }, {
20403
+ text: "error-text-emphasis",
20404
+ background: "error-bg-subtle",
20405
+ name: "Error text on subtle background"
20406
+ }, {
20407
+ text: "success-text-emphasis",
20408
+ background: "success-bg-subtle",
20409
+ name: "Success text on subtle background"
20410
+ } ];
20411
+
20412
+ /**
20413
+ * Color format validation patterns
20414
+ */
20415
+ /**
20416
+ * Parse RGB/RGBA color string to RGB values
20417
+ */
20418
+ function rgbToRgb(rgb) {
20419
+ const match = rgb.match(COLOR_PATTERNS.rgb) || rgb.match(COLOR_PATTERNS.rgba);
20420
+ if (!match) return null;
20421
+ const r = parseInt(match[1] ?? "0", 10), g = parseInt(match[2] ?? "0", 10), b = parseInt(match[3] ?? "0", 10);
20422
+ // Validate RGB ranges
20423
+ return r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255 ? null : {
20424
+ r: r,
20425
+ g: g,
20426
+ b: b
20427
+ };
20428
+ }
20429
+
20430
+ /**
20431
+ * Parse HSL/HSLA color string to RGB values
20432
+ */ function hslToRgb(hsl) {
20433
+ const match = hsl.match(COLOR_PATTERNS.hsl) || hsl.match(COLOR_PATTERNS.hsla);
20434
+ if (!match) return null;
20435
+ let h = parseInt(match[1] ?? "0", 10) / 360, s = parseInt(match[2] ?? "0", 10) / 100, l = parseInt(match[3] ?? "0", 10) / 100;
20436
+ // Validate HSL ranges
20437
+ if (h < 0 || h > 1 || s < 0 || s > 1 || l < 0 || l > 1) return null;
20438
+ const hue2rgb = (p, q, t) => (t < 0 && (t += 1), t > 1 && (t -= 1), t < 1 / 6 ? p + 6 * (q - p) * t : t < .5 ? q : t < 2 / 3 ? p + (q - p) * (2 / 3 - t) * 6 : p);
20439
+ let r, g, b;
20440
+ if (0 === s) r = g = b = l; // achromatic
20441
+ else {
20442
+ const q = l < .5 ? l * (1 + s) : l + s - l * s, p = 2 * l - q;
20443
+ r = hue2rgb(p, q, h + 1 / 3), g = hue2rgb(p, q, h), b = hue2rgb(p, q, h - 1 / 3);
20444
+ }
20445
+ return {
20446
+ r: Math.round(255 * r),
20447
+ g: Math.round(255 * g),
20448
+ b: Math.round(255 * b)
20449
+ };
20450
+ }
20451
+
20452
+ /**
20453
+ * Convert any valid color format to RGB values
20454
+ */ function colorToRgb(color) {
20455
+ // Try hex first
20456
+ return COLOR_PATTERNS.hex.test(color) ?
20457
+ /**
20458
+ * Convert hex color to RGB values
20459
+ */
20460
+ function(hex) {
20461
+ const result = COLOR_PATTERNS.hex.exec(hex);
20462
+ if (!result || !result[1]) return null;
20463
+ const digits = result[1];
20464
+ let r, g, b;
20465
+ switch (digits.length) {
20466
+ case 3:
20467
+ case 4:
20468
+ // #RGBA (ignore alpha)
20469
+ r = parseInt((digits[0] ?? "0") + (digits[0] ?? "0"), 16), g = parseInt((digits[1] ?? "0") + (digits[1] ?? "0"), 16),
20470
+ b = parseInt((digits[2] ?? "0") + (digits[2] ?? "0"), 16);
20471
+ break;
20472
+
20473
+ case 6:
20474
+ case 8:
20475
+ // #RRGGBBAA (ignore alpha)
20476
+ r = parseInt(digits.slice(0, 2), 16), g = parseInt(digits.slice(2, 4), 16), b = parseInt(digits.slice(4, 6), 16);
20477
+ break;
20478
+
20479
+ default:
20480
+ return null;
20481
+ }
20482
+ return {
20483
+ r: r,
20484
+ g: g,
20485
+ b: b
20486
+ };
20487
+ }(color) :
20488
+ // Try RGB/RGBA
20489
+ color.startsWith("rgb") ? rgbToRgb(color) :
20490
+ // Try HSL/HSLA
20491
+ color.startsWith("hsl") ? hslToRgb(color) : null;
20492
+ }
20493
+
20494
+ /**
20495
+ * Validate that a color string is in a valid format (hex, rgb, hsl, etc.)
20496
+ * Includes validation of value ranges for RGB and HSL
20497
+ */
20498
+ /**
20499
+ * Calculate relative luminance of a color
20500
+ * Based on WCAG guidelines: https://www.w3.org/TR/WCAG20-TECHS/G17.html
20501
+ */
20502
+ function getRelativeLuminance(r, g, b) {
20503
+ const normalize = val => (val /= 255) <= .03928 ? val / 12.92 : Math.pow((val + .055) / 1.055, 2.4);
20504
+ return .2126 * normalize(r) + .7152 * normalize(g) + .0722 * normalize(b);
20505
+ }
20506
+
20507
+ /**
20508
+ * Calculate contrast ratio between two colors (supports multiple formats)
20509
+ */
20510
+ /**
20511
+ * Check if contrast ratio meets WCAG AA standards
20512
+ * AA requires 4.5:1 for normal text, 3:1 for large text
20513
+ */
20514
+ function validateContrastRatio(foreground, background, isLargeText = !1) {
20515
+ const ratio = function(color1, color2) {
20516
+ const rgb1 = colorToRgb(color1), rgb2 = colorToRgb(color2);
20517
+ if (!rgb1 || !rgb2) return null;
20518
+ const lum1 = getRelativeLuminance(rgb1.r, rgb1.g, rgb1.b), lum2 = getRelativeLuminance(rgb2.r, rgb2.g, rgb2.b);
20519
+ return (Math.max(lum1, lum2) + .05) / (Math.min(lum1, lum2) + .05);
20520
+ }(foreground, background);
20521
+ if (null === ratio) return {
20522
+ valid: !1,
20523
+ ratio: 0,
20524
+ requiredRatio: isLargeText ? 3 : 4.5
20525
+ };
20526
+ const requiredRatio = isLargeText ? 3 : 4.5;
20527
+ return {
20528
+ valid: ratio >= requiredRatio,
20529
+ ratio: ratio,
20530
+ requiredRatio: requiredRatio
20531
+ };
20532
+ }
20533
+
20534
+ /**
20535
+ * Validate all color formats in DesignTokens
20536
+ */
20537
+ /**
20538
+ * Comprehensive validation of DesignTokens
20539
+ */
20540
+ function validateDesignTokens(tokens, options = {}) {
20541
+ const results = [];
20542
+ options.skipRequiredTokens || results.push(
20543
+ /**
20544
+ * Validate that all required tokens are present
20545
+ */
20546
+ function(tokens) {
20547
+ const errors = [], warnings = [];
20548
+ // Check required color tokens
20549
+ for (const token of REQUIRED_COLOR_TOKENS) token in tokens || errors.push(`Required color token '${token}' is missing`);
20550
+ // Check required text emphasis tokens
20551
+ for (const token of REQUIRED_TEXT_EMPHASIS_TOKENS) token in tokens || errors.push(`Required text emphasis token '${token}' is missing`);
20552
+ // Check for RGB versions of base colors
20553
+ for (const token of REQUIRED_COLOR_TOKENS) {
20554
+ const rgbToken = `${token}-rgb`;
20555
+ rgbToken in tokens || warnings.push(`RGB version of '${token}' token '${rgbToken}' is missing`);
20556
+ }
20557
+ return {
20558
+ valid: 0 === errors.length,
20559
+ errors: errors,
20560
+ warnings: warnings
20561
+ };
20562
+ }
20563
+ /**
20564
+ * Validate accessibility contrast ratios
20565
+ */ (tokens)), options.skipColorValidation || results.push(function(tokens) {
20566
+ const errors = [], colorTokenKeys = new Set([
20567
+ // Base colors
20568
+ "primary", "secondary", "success", "info", "warning", "error", "light", "dark",
20569
+ // Text emphasis
20570
+ "primary-text-emphasis", "secondary-text-emphasis", "tertiary-text-emphasis", "disabled-text-emphasis", "invert-text-emphasis", "brand-text-emphasis", "error-text-emphasis", "success-text-emphasis", "warning-text-emphasis", "info-text-emphasis", "light-text-emphasis", "dark-text-emphasis",
20571
+ // Background subtle
20572
+ "primary-bg-subtle", "secondary-bg-subtle", "tertiary-bg-subtle", "invert-bg-subtle", "brand-bg-subtle", "error-bg-subtle", "success-bg-subtle", "warning-bg-subtle", "info-bg-subtle", "light-bg-subtle", "dark-bg-subtle",
20573
+ // Border subtle
20574
+ "primary-border-subtle", "secondary-border-subtle", "success-border-subtle", "error-border-subtle", "warning-border-subtle", "info-border-subtle", "brand-border-subtle", "light-border-subtle", "dark-border-subtle",
20575
+ // Hover states
20576
+ "primary-hover", "secondary-hover", "light-hover", "dark-hover", "error-hover", "success-hover", "warning-hover", "info-hover",
20577
+ // Colors from scales (primary, red, green, blue, yellow)
20578
+ ...Array.from({
20579
+ length: 10
20580
+ }, ((_, i) => [ `primary-${i + 1}`, `red-${i + 1}`, `green-${i + 1}`, `blue-${i + 1}`, `yellow-${i + 1}` ])).flat(),
20581
+ // Gray scale
20582
+ ...Array.from({
20583
+ length: 10
20584
+ }, ((_, i) => `gray-${i + 1}`)),
20585
+ // Body colors
20586
+ "body-color", "heading-color",
20587
+ // Link colors
20588
+ "link-color", "link-hover-color",
20589
+ // Highlight & code
20590
+ "highlight-bg", "code-color",
20591
+ // Border colors
20592
+ "border-color", "border-color-translucent",
20593
+ // Focus ring
20594
+ "focus-border-color",
20595
+ // Form validation
20596
+ "form-valid-color", "form-valid-border-color", "form-invalid-color", "form-invalid-border-color" ]);
20597
+ for (const key of colorTokenKeys) {
20598
+ if (!(key in tokens)) continue;
20599
+ // Skip if token not present
20600
+ const value = tokens[key];
20601
+ "string" == typeof value ? (color = value,
20602
+ // Check hex first (regex is sufficient)
20603
+ COLOR_PATTERNS.hex.test(color) || (
20604
+ // Check RGB/RGBA with value validation
20605
+ COLOR_PATTERNS.rgb.test(color) || COLOR_PATTERNS.rgba.test(color) ? null !== rgbToRgb(color) :
20606
+ // Check HSL/HSLA with value validation
20607
+ (COLOR_PATTERNS.hsl.test(color) || COLOR_PATTERNS.hsla.test(color)) && null !== hslToRgb(color)) || errors.push(`Token '${key}' has invalid color format: '${value}'`)) : errors.push(`Token '${key}' must be a string, got ${typeof value}`);
20608
+ }
20609
+ var color;
20610
+ return {
20611
+ valid: 0 === errors.length,
20612
+ errors: errors,
20613
+ warnings: []
20614
+ };
20615
+ }(tokens)), options.skipAccessibility || results.push(function(tokens) {
20616
+ const errors = [], warnings = [];
20617
+ for (const check of ACCESSIBILITY_CHECKS) {
20618
+ const textColor = tokens[check.text], bgColor = tokens[check.background];
20619
+ if (!textColor || !bgColor) {
20620
+ warnings.push(`Cannot validate contrast for ${check.name}: missing tokens`);
20621
+ continue;
20622
+ }
20623
+ const contrast = validateContrastRatio(textColor, bgColor);
20624
+ if (!contrast.valid) {
20625
+ const level = 3 === contrast.requiredRatio ? "large text (AA)" : "normal text (AA)";
20626
+ errors.push(`${check.name}: contrast ratio ${contrast.ratio.toFixed(2)}:1 is below required ${contrast.requiredRatio}:1 for ${level}`);
20627
+ }
20628
+ }
20629
+ return {
20630
+ valid: 0 === errors.length,
20631
+ errors: errors,
20632
+ warnings: warnings
20633
+ };
20634
+ }(tokens));
20635
+ const allErrors = results.flatMap((r => r.errors)), allWarnings = results.flatMap((r => r.warnings)), valid = 0 === allErrors.length;
20636
+ // Log validation results
20637
+ return valid ? allWarnings.length > 0 ? logger$1.warn(`DesignTokens validation passed with ${allWarnings.length} warnings`, {
20638
+ warnings: allWarnings
20639
+ }) : logger$1.debug("DesignTokens validation passed") : logger$1.error("DesignTokens validation failed", new Error(`Validation failed with ${allErrors.length} errors and ${allWarnings.length} warnings`), {
20640
+ errors: allErrors,
20641
+ warnings: allWarnings,
20642
+ tokenCount: Object.keys(tokens).length
20643
+ }), {
20644
+ valid: valid,
20645
+ errors: allErrors,
20646
+ warnings: allWarnings
20647
+ };
20648
+ }
20649
+
20650
+ /**
20651
+ * Safely validate and merge partial tokens with defaults
20652
+ */ function validateAndMergeTokens(partialTokens) {
20653
+ const merged = {
20654
+ ...defaultTokens,
20655
+ ...partialTokens
20656
+ };
20657
+ return {
20658
+ tokens: merged,
20659
+ validation: validateDesignTokens(merged)
20660
+ };
20661
+ }
20662
+
20663
+ const logger = getLogger(), 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}) => {
20384
20664
  // Store callbacks in refs to avoid recreating when they change
20385
20665
  const onThemeChangeRef = React.useRef(onThemeChange), onErrorRef = React.useRef(onError);
20386
20666
  // Update ref when callback changes
@@ -20401,12 +20681,20 @@ const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes:
20401
20681
  // If defaultTheme is provided, use it
20402
20682
  return null != defaultTheme ? defaultTheme : "default";
20403
20683
  // Default fallback
20404
- }), [ defaultTheme, enablePersistence, storageKey ]), [currentTheme, setCurrentTheme] = React.useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : "tokens-theme")), [activeTokens, setActiveTokens] = React.useState((() =>
20405
- // If defaultTheme is DesignTokens, store them
20406
- defaultTheme && "string" != typeof defaultTheme ? createTokens(defaultTheme) : null)), [isLoading, setIsLoading] = React.useState(!1), [error, setError] = React.useState(null), loadedThemesRef = React.useRef(new Set), themePromisesRef = React.useRef({}), abortControllerRef = React.useRef(null);
20684
+ }), [ defaultTheme, enablePersistence, storageKey ]), [currentTheme, setCurrentTheme] = React.useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : "tokens-theme")), [activeTokens, setActiveTokens] = React.useState((() => {
20685
+ // If defaultTheme is DesignTokens, validate and store them
20686
+ if (defaultTheme && "string" != typeof defaultTheme) {
20687
+ const {tokens: tokens, validation: validation} = validateAndMergeTokens(defaultTheme);
20688
+ return validation.valid ? tokens : (logger.warn("Invalid default theme tokens, using defaults", {
20689
+ errors: validation.errors,
20690
+ warnings: validation.warnings
20691
+ }), createTokens({}));
20692
+ }
20693
+ return null;
20694
+ })), [isLoading, setIsLoading] = React.useState(!1), [error, setError] = React.useState(null), loadedThemesRef = React.useRef(new Set), themePromisesRef = React.useRef({}), abortControllerRef = React.useRef(null);
20407
20695
  // Handle initial DesignTokens defaultTheme
20408
20696
  React.useEffect((() => {
20409
- defaultTheme && "string" != typeof defaultTheme && activeTokens && !isServer() && injectCSS$1(createTheme(defaultTheme), "theme-tokens-theme");
20697
+ defaultTheme && "string" != typeof defaultTheme && activeTokens && !isServer() && injectCSS$1(createTheme(activeTokens), "theme-tokens-theme");
20410
20698
  }), [ defaultTheme, activeTokens ]), // Run when defaultTheme or activeTokens change
20411
20699
  // Apply initial theme attributes to document element
20412
20700
  React.useEffect((() => {
@@ -20436,21 +20724,42 @@ const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes:
20436
20724
  if ("string" != typeof theme) {
20437
20725
  // Check if aborted before processing
20438
20726
  if (abortController.signal.aborted) return;
20439
- // For DesignTokens, create CSS and inject it
20440
- const {createTheme: createTheme} = await Promise.resolve().then((function() {
20441
- return index;
20442
- })), css = createTheme(theme), themeId = "tokens-theme";
20727
+ // Validate and merge DesignTokens
20728
+ const {tokens: validatedTokens, validation: validation} = validateAndMergeTokens(theme);
20729
+ if (!validation.valid) {
20730
+ const errorMsg = `Invalid DesignTokens provided: ${validation.errors.join(", ")}`, validationError = new Error(errorMsg);
20731
+ // Default to true
20732
+ if (logger.error("Theme validation failed", validationError, {
20733
+ errors: validation.errors,
20734
+ warnings: validation.warnings
20735
+ }), !1 !== options?.fallbackOnError) {
20736
+ logger.warn("Falling back to default theme due to validation errors");
20737
+ // Use default tokens instead
20738
+ const {tokens: defaultTokens} = validateAndMergeTokens({}), css = createTheme(defaultTokens), themeId = "tokens-theme-fallback";
20739
+ // Check if aborted before state update
20740
+ if (abortController.signal.aborted) return;
20741
+ // Remove any previously loaded theme CSS
20742
+ return removeCSS(`theme-${currentTheme}`),
20743
+ // Inject new theme CSS
20744
+ injectCSS$1(css, `theme-${themeId}`),
20745
+ // Store default tokens
20746
+ setActiveTokens(defaultTokens), setCurrentTheme(themeId), handleThemeChange(defaultTokens),
20747
+ handleError(validationError, themeId), void setIsLoading(!1);
20748
+ }
20749
+ // No fallback, throw the error
20750
+ throw validationError;
20751
+ }
20752
+ // For valid DesignTokens, create CSS and inject it
20753
+ const css = createTheme(validatedTokens), themeId = "tokens-theme";
20443
20754
  // Check if aborted after async operation
20444
20755
  if (abortController.signal.aborted) return;
20445
20756
  // Remove any previously loaded theme CSS
20446
- removeCSS(`theme-${currentTheme}`),
20447
- // Inject new theme CSS
20448
- injectCSS$1(css, `theme-${themeId}`);
20449
- // Store tokens for reference
20450
- const fullTokens = createTokens(theme);
20757
+ // Store validated tokens for reference
20451
20758
  // Check if aborted before state update
20452
- if (abortController.signal.aborted) return;
20453
- return setActiveTokens(fullTokens), setCurrentTheme(themeId), handleThemeChange(fullTokens),
20759
+ if (removeCSS(`theme-${currentTheme}`),
20760
+ // Inject new theme CSS
20761
+ injectCSS$1(css, `theme-${themeId}`), abortController.signal.aborted) return;
20762
+ return setActiveTokens(validatedTokens), setCurrentTheme(themeId), handleThemeChange(validatedTokens),
20454
20763
  void setIsLoading(!1);
20455
20764
  }
20456
20765
  // If it's a string theme name, load the associated CSS
@@ -20465,32 +20774,35 @@ const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes:
20465
20774
  // If previous load failed, continue with new load
20466
20775
  }
20467
20776
  // Load CSS theme
20468
- const themeLoadPromise = new Promise((async (resolve, reject) => {
20469
- try {
20470
- // Check if aborted
20471
- if (abortController.signal.aborted) return void resolve();
20472
- if (!themes[theme]) throw new Error(`Theme metadata not found for theme: ${theme}`);
20473
- {
20474
- // Build CSS path using utility function
20475
- const cssPath = buildThemePath(theme, basePath, useMinified, cdnPath);
20777
+ const themeLoadPromise = new Promise(((resolve, reject) => {
20778
+ // Start the async operation
20779
+ (async () => {
20780
+ try {
20476
20781
  // Check if aborted
20477
- if (abortController.signal.aborted) return void resolve();
20478
- // Load CSS file (using loadThemeCSS from domUtils)
20479
- const {loadThemeCSS: loadThemeCSS} = await Promise.resolve().then((function() {
20480
- return domUtils;
20481
- }));
20482
- // Check if aborted after async operation
20483
- if (await loadThemeCSS(cssPath, `theme-${theme}`), abortController.signal.aborted) return void resolve();
20484
- // Remove any previously loaded theme CSS
20485
- removeCSS(`theme-${String(currentTheme)}`), loadedThemesRef.current.add(theme),
20486
- setCurrentTheme(theme), setActiveTokens(null), handleThemeChange(theme), resolve();
20782
+ if (abortController.signal.aborted) return void resolve();
20783
+ if (!themes[theme]) throw new Error(`Theme metadata not found for theme: ${theme}`);
20784
+ {
20785
+ // Build CSS path using utility function
20786
+ const cssPath = buildThemePath(theme, basePath, useMinified, cdnPath);
20787
+ // Check if aborted
20788
+ if (abortController.signal.aborted) return void resolve();
20789
+ // Load CSS file (using loadThemeCSS from domUtils)
20790
+ const {loadThemeCSS: loadThemeCSS} = await Promise.resolve().then((function() {
20791
+ return domUtils;
20792
+ }));
20793
+ // Check if aborted after async operation
20794
+ if (await loadThemeCSS(cssPath, `theme-${theme}`), abortController.signal.aborted) return void resolve();
20795
+ // Remove any previously loaded theme CSS
20796
+ removeCSS(`theme-${String(currentTheme)}`), loadedThemesRef.current.add(theme),
20797
+ setCurrentTheme(theme), setActiveTokens(null), handleThemeChange(theme), resolve();
20798
+ }
20799
+ } catch (err) {
20800
+ // Don't reject if aborted
20801
+ if (abortController.signal.aborted) return void resolve();
20802
+ const error = err instanceof Error ? err : new Error(String(err));
20803
+ setError(error), handleError(error, String(theme)), reject(error);
20487
20804
  }
20488
- } catch (err) {
20489
- // Don't reject if aborted
20490
- if (abortController.signal.aborted) return void resolve();
20491
- const error = err instanceof Error ? err : new Error(String(err));
20492
- setError(error), handleError(error, String(theme)), reject(error);
20493
- }
20805
+ })();
20494
20806
  }));
20495
20807
  themePromisesRef.current[theme] = themeLoadPromise;
20496
20808
  try {
@@ -20555,6 +20867,17 @@ const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes:
20555
20867
  });
20556
20868
  };
20557
20869
 
20870
+ /**
20871
+ * Theme Provider
20872
+ *
20873
+ * React context provider for theme management with separated concerns.
20874
+ * Simplified version focusing on core functionality:
20875
+ * - String-based themes (CSS files)
20876
+ * - DesignTokens (dynamic themes)
20877
+ * - Persistence via localStorage
20878
+ *
20879
+ * Falls back to 'default' theme if no configuration is found.
20880
+ */
20558
20881
  /**
20559
20882
  * useTheme Hook
20560
20883
  *
@@ -20580,7 +20903,8 @@ const ThemeProvider = ({children: children, defaultTheme: defaultTheme, themes:
20580
20903
  * );
20581
20904
  * }
20582
20905
  * ```
20583
- */ function useTheme() {
20906
+ */
20907
+ function useTheme() {
20584
20908
  const context = React.useContext(ThemeContext);
20585
20909
  if (!context) throw new Error("useTheme must be used within a ThemeProvider");
20586
20910
  return {
@@ -22597,8 +22921,8 @@ function createPaletteColor(color) {
22597
22921
  * @returns Complete theme object
22598
22922
  */
22599
22923
  function createThemeObject(...options) {
22600
- // Merge all options
22601
- const mergedOptions = _reduceInstanceProperty(options).call(options, ((acc, option) => deepMerge(acc, option)), {}), palette = {
22924
+ // Merge all options by spreading them into a single object
22925
+ const mergedOptions = _reduceInstanceProperty(options).call(options, ((acc, option) => deepMerge(acc, option || {})), {}), palette = {
22602
22926
  primary: createPaletteColor(mergedOptions.palette?.primary || DEFAULT_PALETTE.primary),
22603
22927
  secondary: createPaletteColor(mergedOptions.palette?.secondary || DEFAULT_PALETTE.secondary),
22604
22928
  error: createPaletteColor(mergedOptions.palette?.error || DEFAULT_PALETTE.error),
@@ -22783,43 +23107,45 @@ function createThemeObject(...options) {
22783
23107
 
22784
23108
  case "hsl":
22785
23109
  case "hsla":
22786
- // Convert RGB to HSL (simplified)
22787
- const hsl =
22788
- /**
23110
+ {
23111
+ // Convert RGB to HSL (simplified)
23112
+ const hsl =
23113
+ /**
22789
23114
  * Convert RGB to HSL
22790
23115
  */
22791
- function(r, g, b) {
22792
- r /= 255, g /= 255, b /= 255;
22793
- const max = Math.max(r, g, b), min = Math.min(r, g, b);
22794
- let h = 0, s = 0;
22795
- const l = (max + min) / 2;
22796
- if (max !== min) {
22797
- const d = max - min;
22798
- switch (s = l > .5 ? d / (2 - max - min) : d / (max + min), max) {
22799
- case r:
22800
- h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
22801
- break;
22802
-
22803
- case g:
22804
- h = ((b - r) / d + 2) / 6;
22805
- break;
22806
-
22807
- case b:
22808
- h = ((r - g) / d + 4) / 6;
23116
+ function(r, g, b) {
23117
+ r /= 255, g /= 255, b /= 255;
23118
+ const max = Math.max(r, g, b), min = Math.min(r, g, b);
23119
+ let h = 0, s = 0;
23120
+ const l = (max + min) / 2;
23121
+ if (max !== min) {
23122
+ const d = max - min;
23123
+ switch (s = l > .5 ? d / (2 - max - min) : d / (max + min), max) {
23124
+ case r:
23125
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
23126
+ break;
23127
+
23128
+ case g:
23129
+ h = ((b - r) / d + 2) / 6;
23130
+ break;
23131
+
23132
+ case b:
23133
+ h = ((r - g) / d + 4) / 6;
23134
+ }
22809
23135
  }
23136
+ return {
23137
+ h: Math.round(360 * h),
23138
+ s: Math.round(100 * s),
23139
+ l: Math.round(100 * l)
23140
+ };
22810
23141
  }
22811
- return {
22812
- h: Math.round(360 * h),
22813
- s: Math.round(100 * s),
22814
- l: Math.round(100 * l)
22815
- };
22816
- }
22817
- /**
23142
+ /**
22818
23143
  * Theme Live Editor Component
22819
23144
  *
22820
23145
  * Allows live editing of theme properties with instant preview
22821
23146
  */ (r, g, b);
22822
- return "hsl" === format ? `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)` : `hsla(${hsl.h}, ${hsl.s}%, ${hsl.l}%, ${a})`;
23147
+ return "hsl" === format ? `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)` : `hsla(${hsl.h}, ${hsl.s}%, ${hsl.l}%, ${a})`;
23148
+ }
22823
23149
 
22824
23150
  default:
22825
23151
  return color;
@@ -23145,8 +23471,312 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
23145
23471
  children: "\n .atomix-theme-live-editor {\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n background: white;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n .editor-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 24px;\n border-bottom: 1px solid #e0e0e0;\n background: #f5f5f5;\n border-radius: 8px 8px 0 0;\n }\n\n .editor-header h2 {\n margin: 0;\n font-size: 20px;\n color: #333;\n }\n\n .editor-controls {\n display: flex;\n gap: 12px;\n align-items: center;\n }\n\n .history-controls,\n .mode-controls,\n .action-controls {\n display: flex;\n gap: 8px;\n }\n\n .history-button,\n .mode-button,\n .export-button,\n .copy-button {\n padding: 8px 16px;\n border: 1px solid #e0e0e0;\n background: white;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n transition: all 0.2s;\n }\n\n .history-button:hover:not(:disabled),\n .mode-button:hover,\n .export-button:hover,\n .copy-button:hover {\n background: #f5f5f5;\n }\n\n .history-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .mode-button.active {\n background: #2196f3;\n color: white;\n border-color: #2196f3;\n }\n\n .export-button {\n background: #4caf50;\n color: white;\n border-color: #4caf50;\n }\n\n .copy-button {\n background: #ff9800;\n color: white;\n border-color: #ff9800;\n }\n\n .editor-content {\n display: flex;\n position: relative;\n min-height: 600px;\n }\n\n .editor-panel,\n .preview-panel {\n overflow-y: auto;\n padding: 24px;\n }\n\n .resizer {\n width: 4px;\n background: #e0e0e0;\n cursor: col-resize;\n position: relative;\n flex-shrink: 0;\n transition: background 0.2s;\n }\n\n .resizer:hover,\n .resizer.resizing {\n background: #2196f3;\n }\n\n .resizer::before {\n content: '';\n position: absolute;\n left: -2px;\n right: -2px;\n top: 0;\n bottom: 0;\n }\n\n .editor-panel h3,\n .preview-panel h3 {\n margin: 0 0 16px 0;\n font-size: 16px;\n color: #333;\n border-bottom: 2px solid #2196f3;\n padding-bottom: 8px;\n }\n\n .visual-editor {\n display: flex;\n flex-direction: column;\n gap: 24px;\n }\n\n .editor-section {\n display: flex;\n flex-direction: column;\n gap: 16px;\n }\n\n .color-format-selector {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 8px;\n }\n\n .color-format-selector label {\n font-size: 14px;\n font-weight: 500;\n color: #666;\n }\n\n .color-format-selector select {\n padding: 6px 12px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n font-size: 14px;\n background: white;\n cursor: pointer;\n }\n\n .editor-field {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .editor-field label {\n font-size: 14px;\n font-weight: 500;\n color: #666;\n }\n\n .color-input-group {\n display: flex;\n gap: 8px;\n align-items: center;\n }\n\n .color-input-group input[type=\"color\"] {\n width: 50px;\n height: 40px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n cursor: pointer;\n }\n\n .color-input-group input[type=\"text\"],\n .editor-field input[type=\"text\"],\n .editor-field input[type=\"number\"] {\n flex: 1;\n padding: 8px 12px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n font-size: 14px;\n font-family: 'Monaco', 'Menlo', monospace;\n }\n\n .json-editor {\n height: 100%;\n display: flex;\n flex-direction: column;\n }\n\n .json-editor textarea {\n flex: 1;\n padding: 16px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n font-family: 'Monaco', 'Menlo', monospace;\n font-size: 12px;\n line-height: 1.5;\n resize: none;\n }\n\n .error-message {\n padding: 12px;\n background: #ffebee;\n color: #d32f2f;\n border-radius: 4px;\n margin-top: 8px;\n font-size: 14px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .error-dismiss {\n background: none;\n border: none;\n color: #d32f2f;\n font-size: 20px;\n cursor: pointer;\n padding: 0;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .error-dismiss:hover {\n background: rgba(211, 47, 47, 0.1);\n border-radius: 50%;\n }\n\n .preview-panel {\n border-left: 1px solid #e0e0e0;\n }\n "
23146
23472
  }) ]
23147
23473
  });
23474
+ }, DesignTokensCustomizer = ({initialTokens: initialTokens = {}, onTokensChange: onTokensChange, className: className, style: style}) => {
23475
+ // Current tokens state
23476
+ const [tokens, setTokens] = React.useState((() => createTokens(initialTokens))), [colorFormat, setColorFormat] = React.useState("hex"), [activeCategory, setActiveCategory] = React.useState("colors"), [cssPreview, setCssPreview] = React.useState("");
23477
+ // Generate CSS when tokens change
23478
+ React.useEffect((() => {
23479
+ const css = createTheme(tokens, {
23480
+ selector: ":root",
23481
+ prefix: "atomix-preview"
23482
+ });
23483
+ setCssPreview(css), onTokensChange?.(tokens);
23484
+ }), [ tokens, onTokensChange ]);
23485
+ // Create theme object for preview
23486
+ const previewTheme = React.useMemo((() => createThemeObject({
23487
+ palette: {
23488
+ primary: {
23489
+ main: tokens.primary
23490
+ },
23491
+ secondary: {
23492
+ main: tokens.secondary
23493
+ },
23494
+ error: {
23495
+ main: tokens.error
23496
+ },
23497
+ warning: {
23498
+ main: tokens.warning
23499
+ },
23500
+ info: {
23501
+ main: tokens.info
23502
+ },
23503
+ success: {
23504
+ main: tokens.success
23505
+ },
23506
+ background: {
23507
+ default: "#ffffff",
23508
+ subtle: tokens["secondary-bg-subtle"] || "#f3f4f6"
23509
+ },
23510
+ text: {
23511
+ primary: tokens["primary-text-emphasis"] || "#111827",
23512
+ secondary: tokens["secondary-text-emphasis"] || "#374151",
23513
+ disabled: tokens["disabled-text-emphasis"] || "#9ca3af"
23514
+ }
23515
+ },
23516
+ typography: {
23517
+ fontFamily: tokens["body-font-family"] || '"Roboto", sans-serif',
23518
+ fontSize: parseInt(tokens["body-font-size"] || "16")
23519
+ },
23520
+ spacing: factor => .25 * factor + "rem"
23521
+ })), [ tokens ]), updateToken = React.useCallback(((key, value) => {
23522
+ setTokens((prev => ({
23523
+ ...prev,
23524
+ [key]: value
23525
+ })));
23526
+ }), []), convertColorFormat = React.useCallback(((color, format) => {
23527
+ // Parse current color
23528
+ const temp = document.createElement("div");
23529
+ temp.style.color = color, document.body.appendChild(temp);
23530
+ const computed = window.getComputedStyle(temp).color;
23531
+ document.body.removeChild(temp);
23532
+ const rgbMatch = computed.match(/\d+/g);
23533
+ if (!rgbMatch || rgbMatch.length < 3) return color;
23534
+ const r = parseInt(rgbMatch[0] || "0", 10), g = parseInt(rgbMatch[1] || "0", 10), b = parseInt(rgbMatch[2] || "0", 10), a = rgbMatch[3] ? parseFloat(rgbMatch[3]) : 1;
23535
+ switch (format) {
23536
+ case "hex":
23537
+ return `#${[ r, g, b ].map((x => x.toString(16).padStart(2, "0"))).join("")}`;
23538
+
23539
+ case "rgb":
23540
+ return `rgb(${r}, ${g}, ${b})`;
23541
+
23542
+ case "rgba":
23543
+ return `rgba(${r}, ${g}, ${b}, ${a})`;
23544
+
23545
+ case "hsl":
23546
+ case "hsla":
23547
+ {
23548
+ const hsl =
23549
+ // RGB to HSL conversion
23550
+ function(r, g, b) {
23551
+ r /= 255, g /= 255, b /= 255;
23552
+ const max = Math.max(r, g, b), min = Math.min(r, g, b);
23553
+ let h = 0, s = 0;
23554
+ const l = (max + min) / 2;
23555
+ if (max !== min) {
23556
+ const d = max - min;
23557
+ switch (s = l > .5 ? d / (2 - max - min) : d / (max + min), max) {
23558
+ case r:
23559
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
23560
+ break;
23561
+
23562
+ case g:
23563
+ h = ((b - r) / d + 2) / 6;
23564
+ break;
23565
+
23566
+ case b:
23567
+ h = ((r - g) / d + 4) / 6;
23568
+ }
23569
+ }
23570
+ return {
23571
+ h: Math.round(360 * h),
23572
+ s: Math.round(100 * s),
23573
+ l: Math.round(100 * l)
23574
+ };
23575
+ }
23576
+ // Export functions
23577
+ (r, g, b);
23578
+ return "hsl" === format ? `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)` : `hsla(${hsl.h}, ${hsl.s}%, ${hsl.l}%, ${a})`;
23579
+ }
23580
+
23581
+ default:
23582
+ return color;
23583
+ }
23584
+ }), []), exportTokens = React.useCallback((() => {
23585
+ const dataStr = JSON.stringify(tokens, null, 2), dataUri = "data:application/json;charset=utf-8," + encodeURIComponent(dataStr), linkElement = document.createElement("a");
23586
+ linkElement.setAttribute("href", dataUri), linkElement.setAttribute("download", "design-tokens.json"),
23587
+ linkElement.click();
23588
+ }), [ tokens ]), exportTheme = React.useCallback((() => {
23589
+ const themeCss = createTheme(tokens), dataUri = "data:text/css;charset=utf-8," + encodeURIComponent(themeCss), linkElement = document.createElement("a");
23590
+ linkElement.setAttribute("href", dataUri), linkElement.setAttribute("download", "theme.css"),
23591
+ linkElement.click();
23592
+ }), [ tokens ]), copyToClipboard = React.useCallback((() => {
23593
+ navigator.clipboard?.writeText(JSON.stringify(tokens, null, 2));
23594
+ }), [ tokens ]), resetToDefaults = React.useCallback((() => {
23595
+ setTokens(defaultTokens);
23596
+ }), []), loadTokensFromFile = React.useCallback((event => {
23597
+ const file = event.target.files?.[0];
23598
+ if (!file) return;
23599
+ const reader = new FileReader;
23600
+ reader.onload = e => {
23601
+ try {
23602
+ const content = e.target?.result, mergedTokens = createTokens(JSON.parse(content));
23603
+ setTokens(mergedTokens);
23604
+ } catch (error) {
23605
+ console.error("Failed to load tokens:", error), alert("Invalid JSON file. Please select a valid design tokens JSON file.");
23606
+ }
23607
+ }, reader.readAsText(file);
23608
+ }), []), tokenCategories = {
23609
+ colors: {
23610
+ label: "Colors",
23611
+ tokens: [
23612
+ // Base colors
23613
+ "primary", "secondary", "success", "info", "warning", "error", "light", "dark",
23614
+ // RGB versions
23615
+ "primary-rgb", "secondary-rgb", "success-rgb", "info-rgb", "warning-rgb", "error-rgb", "light-rgb", "dark-rgb",
23616
+ // Gray scale
23617
+ "gray-1", "gray-2", "gray-3", "gray-4", "gray-5", "gray-6", "gray-7", "gray-8", "gray-9", "gray-10",
23618
+ // Primary scale
23619
+ "primary-1", "primary-2", "primary-3", "primary-4", "primary-5", "primary-6", "primary-7", "primary-8", "primary-9", "primary-10",
23620
+ // Text emphasis
23621
+ "primary-text-emphasis", "secondary-text-emphasis", "tertiary-text-emphasis", "disabled-text-emphasis", "invert-text-emphasis", "brand-text-emphasis", "error-text-emphasis", "success-text-emphasis", "warning-text-emphasis", "info-text-emphasis", "light-text-emphasis", "dark-text-emphasis",
23622
+ // Background subtle
23623
+ "primary-bg-subtle", "secondary-bg-subtle", "tertiary-bg-subtle", "invert-bg-subtle", "brand-bg-subtle", "error-bg-subtle", "success-bg-subtle", "warning-bg-subtle", "info-bg-subtle", "light-bg-subtle", "dark-bg-subtle",
23624
+ // Border subtle
23625
+ "primary-border-subtle", "secondary-border-subtle", "success-border-subtle", "error-border-subtle", "warning-border-subtle", "info-border-subtle", "brand-border-subtle", "light-border-subtle", "dark-border-subtle",
23626
+ // Hover states
23627
+ "primary-hover", "secondary-hover", "light-hover", "dark-hover", "error-hover", "success-hover", "warning-hover", "info-hover",
23628
+ // Gradients
23629
+ "primary-gradient", "secondary-gradient", "light-gradient", "dark-gradient", "success-gradient", "info-gradient", "warning-gradient", "error-gradient", "gradient" ]
23630
+ },
23631
+ typography: {
23632
+ label: "Typography",
23633
+ tokens: [ "font-sans-serif", "font-monospace", "body-font-family", "body-font-size", "body-font-weight", "body-line-height", "body-color", "body-bg", "heading-color", "font-size-xl", "font-size-2xl", "display-1", "font-weight-light", "font-weight-normal", "font-weight-medium", "font-weight-semibold", "font-weight-bold", "font-weight-heavy", "font-weight-black", "line-height-base", "line-height-sm", "line-height-lg", "letter-spacing-h1", "letter-spacing-h2", "letter-spacing-h3", "letter-spacing-h4", "letter-spacing-h5", "letter-spacing-h6", "link-color", "link-color-rgb", "link-decoration", "link-hover-color", "link-hover-color-rgb", "highlight-bg", "code-color" ]
23634
+ },
23635
+ spacing: {
23636
+ label: "Spacing",
23637
+ tokens: [ "spacing-0", "spacing-1", "spacing-px-6", "spacing-2", "spacing-px-10", "spacing-3", "spacing-px-14", "spacing-4", "spacing-5", "spacing-px-22", "spacing-6", "spacing-7", "spacing-px-30", "spacing-8", "spacing-9", "spacing-10", "spacing-11", "spacing-12", "spacing-14", "spacing-16", "spacing-20", "spacing-24", "spacing-28", "spacing-32", "spacing-36", "spacing-40", "spacing-44", "spacing-48", "spacing-52", "spacing-56", "spacing-60", "spacing-64", "spacing-72", "spacing-80", "spacing-90", "spacing-200" ]
23638
+ },
23639
+ shadows: {
23640
+ label: "Shadows",
23641
+ tokens: [ "box-shadow", "box-shadow-xs", "box-shadow-sm", "box-shadow-lg", "box-shadow-xl", "box-shadow-inset" ]
23642
+ },
23643
+ borders: {
23644
+ label: "Borders",
23645
+ tokens: [ "border-width", "border-style", "border-color", "border-color-translucent", "border-radius", "border-radius-sm", "border-radius-lg", "border-radius-xl", "border-radius-xxl", "border-radius-2xl", "border-radius-3xl", "border-radius-4xl", "border-radius-pill", "focus-border-color", "focus-ring-width", "focus-ring-offset", "focus-ring-opacity", "form-valid-color", "form-valid-border-color", "form-invalid-color", "form-invalid-border-color" ]
23646
+ },
23647
+ transitions: {
23648
+ label: "Transitions",
23649
+ tokens: [ "transition-duration-fast", "transition-duration-base", "transition-duration-slow", "transition-duration-slower", "easing-base", "easing-ease-in-out", "easing-ease-out", "easing-ease-in", "easing-ease-linear", "transition-fast", "transition-base", "transition-slow" ]
23650
+ },
23651
+ zindex: {
23652
+ label: "Z-Index",
23653
+ tokens: [ "z-n1", "z-0", "z-1", "z-2", "z-3", "z-4", "z-5", "z-dropdown", "z-sticky", "z-fixed", "z-modal", "z-popover", "z-tooltip", "z-drawer" ]
23654
+ },
23655
+ breakpoints: {
23656
+ label: "Breakpoints",
23657
+ tokens: [ "breakpoint-xs", "breakpoint-sm", "breakpoint-md", "breakpoint-lg", "breakpoint-xl", "breakpoint-xxl" ]
23658
+ }
23659
+ };
23660
+ // Update token value
23661
+ return jsxRuntime.jsxs("div", {
23662
+ className: `design-tokens-customizer ${className || ""}`,
23663
+ style: style,
23664
+ children: [ jsxRuntime.jsxs("div", {
23665
+ className: "customizer-header",
23666
+ children: [ jsxRuntime.jsx("h2", {
23667
+ children: "Interactive Theme Customizer"
23668
+ }), jsxRuntime.jsxs("div", {
23669
+ className: "customizer-controls",
23670
+ children: [ jsxRuntime.jsxs("select", {
23671
+ value: colorFormat,
23672
+ onChange: e => setColorFormat(e.target.value),
23673
+ children: [ jsxRuntime.jsx("option", {
23674
+ value: "hex",
23675
+ children: "HEX"
23676
+ }), jsxRuntime.jsx("option", {
23677
+ value: "rgb",
23678
+ children: "RGB"
23679
+ }), jsxRuntime.jsx("option", {
23680
+ value: "rgba",
23681
+ children: "RGBA"
23682
+ }), jsxRuntime.jsx("option", {
23683
+ value: "hsl",
23684
+ children: "HSL"
23685
+ }), jsxRuntime.jsx("option", {
23686
+ value: "hsla",
23687
+ children: "HSLA"
23688
+ }) ]
23689
+ }), jsxRuntime.jsx("button", {
23690
+ onClick: resetToDefaults,
23691
+ children: "Reset to Defaults"
23692
+ }), jsxRuntime.jsxs("label", {
23693
+ className: "file-input-button",
23694
+ children: [ "Load Tokens", jsxRuntime.jsx("input", {
23695
+ type: "file",
23696
+ accept: ".json",
23697
+ onChange: loadTokensFromFile,
23698
+ style: {
23699
+ display: "none"
23700
+ }
23701
+ }) ]
23702
+ }), jsxRuntime.jsx("button", {
23703
+ onClick: copyToClipboard,
23704
+ children: "Copy Tokens"
23705
+ }), jsxRuntime.jsx("button", {
23706
+ onClick: exportTokens,
23707
+ children: "Export Tokens"
23708
+ }), jsxRuntime.jsx("button", {
23709
+ onClick: exportTheme,
23710
+ children: "Export Theme CSS"
23711
+ }) ]
23712
+ }) ]
23713
+ }), jsxRuntime.jsxs("div", {
23714
+ className: "customizer-content",
23715
+ children: [ jsxRuntime.jsx("div", {
23716
+ className: "customizer-sidebar",
23717
+ children: Object.entries(tokenCategories).map((([key, category]) => jsxRuntime.jsx("button", {
23718
+ className: "category-button " + (activeCategory === key ? "active" : ""),
23719
+ onClick: () => setActiveCategory(key),
23720
+ children: category.label
23721
+ }, key)))
23722
+ }), jsxRuntime.jsxs("div", {
23723
+ className: "customizer-editor",
23724
+ children: [ jsxRuntime.jsx("h3", {
23725
+ children: tokenCategories[activeCategory].label
23726
+ }), jsxRuntime.jsx("div", {
23727
+ className: "tokens-grid",
23728
+ children: tokenCategories[activeCategory].tokens.map((tokenKey => {
23729
+ var _context;
23730
+ const value = tokens[tokenKey] || "", isColor = _includesInstanceProperty(tokenKey).call(tokenKey, "color") || _includesInstanceProperty(tokenKey).call(tokenKey, "bg") || _includesInstanceProperty(tokenKey).call(tokenKey, "gradient") || _includesInstanceProperty(_context = [ "primary", "secondary", "success", "info", "warning", "error", "light", "dark" ]).call(_context, tokenKey) || tokenKey.match(/^(gray|primary|red|green|blue|yellow)-\d+$/);
23731
+ return jsxRuntime.jsxs("div", {
23732
+ className: "token-item",
23733
+ children: [ jsxRuntime.jsx("label", {
23734
+ children: tokenKey
23735
+ }), isColor ? jsxRuntime.jsxs("div", {
23736
+ className: "color-input-group",
23737
+ children: [ jsxRuntime.jsx("input", {
23738
+ type: "color",
23739
+ value: value.startsWith("#") ? value : convertColorFormat(value, "hex"),
23740
+ onChange: e => updateToken(tokenKey, e.target.value)
23741
+ }), jsxRuntime.jsx("input", {
23742
+ type: "text",
23743
+ value: convertColorFormat(value, colorFormat),
23744
+ onChange: e => {
23745
+ const converted = convertColorFormat(e.target.value, "hex");
23746
+ updateToken(tokenKey, converted);
23747
+ }
23748
+ }) ]
23749
+ }) : jsxRuntime.jsx("input", {
23750
+ type: "text",
23751
+ value: value,
23752
+ onChange: e => updateToken(tokenKey, e.target.value)
23753
+ }) ]
23754
+ }, tokenKey);
23755
+ }))
23756
+ }) ]
23757
+ }), jsxRuntime.jsxs("div", {
23758
+ className: "customizer-preview",
23759
+ children: [ jsxRuntime.jsx("h3", {
23760
+ children: "Live Preview"
23761
+ }), jsxRuntime.jsx("style", {
23762
+ children: cssPreview
23763
+ }), jsxRuntime.jsx(ThemePreview, {
23764
+ theme: previewTheme,
23765
+ showDetails: !1,
23766
+ showPalette: !0,
23767
+ showTypography: !0,
23768
+ showSpacing: !0
23769
+ }) ]
23770
+ }) ]
23771
+ }), jsxRuntime.jsx("style", {
23772
+ children: "\n .design-tokens-customizer {\n display: flex;\n flex-direction: column;\n height: 100vh;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n .customizer-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 24px;\n border-bottom: 1px solid #e0e0e0;\n background: #f5f5f5;\n }\n\n .customizer-header h2 {\n margin: 0;\n font-size: 24px;\n color: #333;\n }\n\n .customizer-controls {\n display: flex;\n gap: 8px;\n align-items: center;\n }\n\n .customizer-controls select,\n .customizer-controls button {\n padding: 8px 12px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n background: white;\n cursor: pointer;\n }\n\n .customizer-controls button:hover,\n .file-input-button:hover {\n background: #f0f0f0;\n }\n\n .file-input-button {\n padding: 8px 12px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n background: white;\n cursor: pointer;\n font-size: 14px;\n display: inline-block;\n }\n\n .customizer-content {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n\n .customizer-sidebar {\n width: 200px;\n border-right: 1px solid #e0e0e0;\n padding: 16px;\n background: #fafafa;\n overflow-y: auto;\n }\n\n .category-button {\n display: block;\n width: 100%;\n padding: 12px;\n margin-bottom: 8px;\n border: none;\n background: white;\n border-radius: 4px;\n cursor: pointer;\n text-align: left;\n font-size: 14px;\n }\n\n .category-button:hover,\n .category-button.active {\n background: #e0e0e0;\n }\n\n .customizer-editor {\n flex: 1;\n padding: 24px;\n overflow-y: auto;\n }\n\n .customizer-editor h3 {\n margin-top: 0;\n margin-bottom: 16px;\n color: #333;\n }\n\n .tokens-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 16px;\n }\n\n .token-item {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .token-item label {\n font-size: 14px;\n font-weight: 500;\n color: #666;\n }\n\n .color-input-group {\n display: flex;\n gap: 8px;\n align-items: center;\n }\n\n .color-input-group input[type=\"color\"] {\n width: 50px;\n height: 40px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n cursor: pointer;\n }\n\n .color-input-group input[type=\"text\"],\n .token-item input[type=\"text\"] {\n flex: 1;\n padding: 8px 12px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n font-size: 14px;\n font-family: 'Monaco', 'Menlo', monospace;\n }\n\n .customizer-preview {\n width: 400px;\n border-left: 1px solid #e0e0e0;\n padding: 24px;\n overflow-y: auto;\n background: #fafafa;\n }\n\n .customizer-preview h3 {\n margin-top: 0;\n margin-bottom: 16px;\n color: #333;\n }\n "
23773
+ }) ]
23774
+ });
23148
23775
  };
23149
23776
 
23777
+ /**
23778
+ * Design Tokens Customizer Component
23779
+ */
23150
23780
  /**
23151
23781
  * Theme Adapter
23152
23782
  *
@@ -23157,7 +23787,8 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
23157
23787
  *
23158
23788
  * @param tokens - DesignTokens object
23159
23789
  * @returns CSS variables object compatible with Theme.cssVars
23160
- */ function designTokensToCSSVars(tokens) {
23790
+ */
23791
+ function designTokensToCSSVars(tokens) {
23161
23792
  const cssVars = {};
23162
23793
  return Object.entries(tokens).forEach((([key, value]) => {
23163
23794
  void 0 !== value && (cssVars[`--atomix-${key}`] = String(value));
@@ -23743,6 +24374,7 @@ function mergePartStyles(base, override) {
23743
24374
  // Export as namespaces with explicit typing
23744
24375
  const composables = composablesImport, utils = utilsImport, types = typesImport, constants = constantsImport, theme = Object.freeze({
23745
24376
  __proto__: null,
24377
+ DesignTokensCustomizer: DesignTokensCustomizer,
23746
24378
  RTLManager: RTLManager,
23747
24379
  ThemeApplicator: ThemeApplicator,
23748
24380
  ThemeComparator: ThemeComparator,
@@ -23827,9 +24459,10 @@ exports.Countdown = Countdown, exports.DATA_TABLE_CLASSES = DATA_TABLE_CLASSES,
23827
24459
  exports.DATA_TABLE_SELECTORS = DATA_TABLE_SELECTORS, exports.DATEPICKER = DATEPICKER,
23828
24460
  exports.DEFAULT_ATOMIX_FONTS = DEFAULT_ATOMIX_FONTS, exports.DOTS = "...", exports.DROPDOWN = DROPDOWN,
23829
24461
  exports.DROPDOWN_CSS_VARS = DROPDOWN_CSS_VARS, exports.DataTable = DataTable, exports.DatePicker = DatePicker,
23830
- exports.DonutChart = DonutChart, exports.Dropdown = Dropdown, exports.EDGE_PANEL = EDGE_PANEL,
23831
- exports.EdgePanel = EdgePanel, exports.ElevationCard = ElevationCard, exports.FOOTER = FOOTER,
23832
- exports.FORM = FORM, exports.FORM_GROUP = FORM_GROUP, exports.Footer = Footer, exports.FooterLink = FooterLink,
24462
+ exports.DesignTokensCustomizer = DesignTokensCustomizer, exports.DonutChart = DonutChart,
24463
+ exports.Dropdown = Dropdown, exports.EDGE_PANEL = EDGE_PANEL, exports.EdgePanel = EdgePanel,
24464
+ exports.ElevationCard = ElevationCard, exports.FOOTER = FOOTER, exports.FORM = FORM,
24465
+ exports.FORM_GROUP = FORM_GROUP, exports.Footer = Footer, exports.FooterLink = FooterLink,
23833
24466
  exports.FooterSection = FooterSection, exports.FooterSocialLink = FooterSocialLink,
23834
24467
  exports.Form = Form, exports.FormGroup = FormGroup, exports.FunnelChart = FunnelChart,
23835
24468
  exports.GLASS_CONTAINER = GLASS_CONTAINER, exports.GaugeChart = GaugeChart, exports.Grid = Grid,
@@ -23938,20 +24571,53 @@ exports.createDarkVariant =
23938
24571
  * Create a dark theme variant from a light theme
23939
24572
  */
23940
24573
  function(lightTheme) {
23941
- return extendTheme(lightTheme, {
24574
+ // We'll extend the theme by merging the new properties with the existing theme
24575
+ const darkVariant = {
23942
24576
  name: `${lightTheme.name} Dark`,
23943
24577
  palette: {
23944
24578
  mode: "dark",
24579
+ primary: lightTheme.palette?.primary,
24580
+ // Preserve original primary
24581
+ secondary: lightTheme.palette?.secondary,
24582
+ // Preserve original secondary
24583
+ error: lightTheme.palette?.error,
24584
+ // Preserve original error
24585
+ warning: lightTheme.palette?.warning,
24586
+ // Preserve original warning
24587
+ info: lightTheme.palette?.info,
24588
+ // Preserve original info
24589
+ success: lightTheme.palette?.success,
24590
+ // Preserve original success
23945
24591
  background: {
23946
24592
  default: "#121212",
24593
+ paper: "#1e1e1e",
24594
+ // Added missing paper property
23947
24595
  subtle: "#1e1e1e"
23948
24596
  },
23949
24597
  text: {
23950
24598
  primary: "#ffffff",
23951
- secondary: "rgba(255, 255, 255, 0.7)"
24599
+ secondary: "rgba(255, 255, 255, 0.7)",
24600
+ disabled: "rgba(255, 255, 255, 0.38)"
23952
24601
  }
23953
24602
  }
23954
- });
24603
+ };
24604
+ // Create a new theme by extending the light theme with the dark variant
24605
+ return {
24606
+ ...lightTheme,
24607
+ ...darkVariant,
24608
+ palette: {
24609
+ ...lightTheme.palette,
24610
+ ...darkVariant.palette,
24611
+ background: {
24612
+ ...lightTheme.palette?.background,
24613
+ ...darkVariant.palette?.background
24614
+ },
24615
+ text: {
24616
+ ...lightTheme.palette?.text,
24617
+ ...darkVariant.palette?.text
24618
+ }
24619
+ }
24620
+ };
23955
24621
  }
23956
24622
  /**
23957
24623
  * Validate theme structure