@shohojdhara/atomix 0.5.1 → 0.5.4

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 (145) hide show
  1. package/atomix.config.ts +45 -33
  2. package/build-tools/webpack-loader.js +5 -4
  3. package/dist/atomix.css +138 -17
  4. package/dist/atomix.css.map +1 -1
  5. package/dist/atomix.min.css +1 -1
  6. package/dist/atomix.min.css.map +1 -1
  7. package/dist/build-tools/webpack-loader.js +5 -4
  8. package/dist/charts.d.ts +23 -23
  9. package/dist/charts.js +40 -37
  10. package/dist/charts.js.map +1 -1
  11. package/dist/config.d.ts +699 -0
  12. package/dist/config.js +17 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/core.d.ts +2 -2
  15. package/dist/core.js +111 -50
  16. package/dist/core.js.map +1 -1
  17. package/dist/forms.d.ts +3 -6
  18. package/dist/forms.js +2 -2
  19. package/dist/forms.js.map +1 -1
  20. package/dist/heavy.d.ts +1 -1
  21. package/dist/heavy.js +173 -111
  22. package/dist/heavy.js.map +1 -1
  23. package/dist/index.d.ts +1881 -790
  24. package/dist/index.esm.js +2713 -816
  25. package/dist/index.esm.js.map +1 -1
  26. package/dist/index.js +2693 -780
  27. package/dist/index.js.map +1 -1
  28. package/dist/index.min.js +1 -1
  29. package/dist/index.min.js.map +1 -1
  30. package/dist/layout.js +59 -60
  31. package/dist/layout.js.map +1 -1
  32. package/dist/theme.d.ts +1390 -276
  33. package/dist/theme.js +2133 -625
  34. package/dist/theme.js.map +1 -1
  35. package/package.json +14 -9
  36. package/scripts/atomix-cli.js +15 -1
  37. package/scripts/cli/__tests__/complexity-utils.test.js +24 -0
  38. package/scripts/cli/__tests__/detector.test.js +50 -0
  39. package/scripts/cli/__tests__/template-engine.test.js +23 -0
  40. package/scripts/cli/__tests__/test-setup.js +3 -0
  41. package/scripts/cli/commands/doctor.js +15 -3
  42. package/scripts/cli/commands/generate.js +113 -51
  43. package/scripts/cli/internal/ai-engine.js +30 -10
  44. package/scripts/cli/internal/complexity-utils.js +60 -0
  45. package/scripts/cli/internal/component-validator.js +49 -16
  46. package/scripts/cli/internal/config-loader.js +30 -20
  47. package/scripts/cli/internal/generator.js +89 -36
  48. package/scripts/cli/internal/hook-generator.js +5 -2
  49. package/scripts/cli/internal/itcss-generator.js +16 -12
  50. package/scripts/cli/templates/next-templates.js +81 -30
  51. package/scripts/cli/templates/storybook-templates.js +12 -2
  52. package/scripts/cli/utils/detector.js +45 -7
  53. package/scripts/cli/utils/diagnostics.js +78 -0
  54. package/scripts/cli/utils/telemetry.js +13 -0
  55. package/src/components/Accordion/Accordion.stories.tsx +4 -0
  56. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +1 -1
  57. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +219 -0
  58. package/src/components/AtomixGlass/glass-utils.ts +1 -1
  59. package/src/components/Button/Button.tsx +114 -57
  60. package/src/components/Callout/Callout.tsx +4 -4
  61. package/src/components/Chart/ChartRenderer.tsx +1 -1
  62. package/src/components/Chart/DonutChart.tsx +11 -8
  63. package/src/components/EdgePanel/EdgePanel.tsx +119 -115
  64. package/src/components/Form/Select.tsx +4 -4
  65. package/src/components/List/List.tsx +4 -4
  66. package/src/components/Navigation/SideMenu/SideMenu.tsx +6 -6
  67. package/src/components/PhotoViewer/PhotoViewerImage.tsx +1 -1
  68. package/src/components/ProductReview/ProductReview.tsx +4 -2
  69. package/src/components/Rating/Rating.tsx +4 -2
  70. package/src/components/SectionIntro/SectionIntro.tsx +4 -2
  71. package/src/components/Steps/Steps.tsx +1 -1
  72. package/src/components/Tabs/Tabs.tsx +5 -5
  73. package/src/components/Testimonial/Testimonial.tsx +4 -2
  74. package/src/components/VideoPlayer/VideoPlayer.tsx +4 -2
  75. package/src/layouts/CssGrid/CssGrid.stories.tsx +464 -0
  76. package/src/layouts/CssGrid/CssGrid.tsx +215 -0
  77. package/src/layouts/CssGrid/index.ts +8 -0
  78. package/src/layouts/CssGrid/scripts/CssGrid.js +284 -0
  79. package/src/layouts/CssGrid/scripts/index.js +43 -0
  80. package/src/layouts/Grid/scripts/Container.js +139 -0
  81. package/src/layouts/Grid/scripts/Grid.js +184 -0
  82. package/src/layouts/Grid/scripts/GridCol.js +273 -0
  83. package/src/layouts/Grid/scripts/Row.js +154 -0
  84. package/src/layouts/Grid/scripts/index.js +48 -0
  85. package/src/layouts/MasonryGrid/MasonryGrid.tsx +71 -59
  86. package/src/lib/composables/atomix-glass/useGlassSize.ts +1 -1
  87. package/src/lib/composables/useAccordion.ts +5 -5
  88. package/src/lib/composables/useAtomixGlass.ts +3 -3
  89. package/src/lib/composables/useBarChart.ts +2 -2
  90. package/src/lib/composables/useChart.ts +3 -2
  91. package/src/lib/composables/useChartToolbar.ts +48 -66
  92. package/src/lib/composables/useDataTable.ts +1 -1
  93. package/src/lib/composables/useDatePicker.ts +2 -2
  94. package/src/lib/composables/useEdgePanel.ts +45 -54
  95. package/src/lib/composables/useHeroBackgroundSlider.ts +5 -5
  96. package/src/lib/composables/usePhotoViewer.ts +2 -3
  97. package/src/lib/composables/usePieChart.ts +1 -1
  98. package/src/lib/composables/usePopover.ts +151 -139
  99. package/src/lib/composables/useSideMenu.ts +28 -41
  100. package/src/lib/composables/useSlider.ts +2 -6
  101. package/src/lib/composables/useTooltip.ts +2 -2
  102. package/src/lib/config/index.ts +38 -323
  103. package/src/lib/config/loader.ts +419 -0
  104. package/src/lib/config/public-api.ts +43 -0
  105. package/src/lib/config/types.ts +389 -0
  106. package/src/lib/config/validator.ts +305 -0
  107. package/src/lib/theme/adapters/index.ts +1 -1
  108. package/src/lib/theme/adapters/themeAdapter.ts +358 -229
  109. package/src/lib/theme/components/ThemeToggle.tsx +276 -0
  110. package/src/lib/theme/config/configLoader.ts +351 -0
  111. package/src/lib/theme/config/loader.ts +221 -0
  112. package/src/lib/theme/core/createTheme.ts +126 -50
  113. package/src/lib/theme/core/createThemeObject.ts +7 -4
  114. package/src/lib/theme/devtools/Comparator.tsx +1 -1
  115. package/src/lib/theme/devtools/Inspector.tsx +1 -1
  116. package/src/lib/theme/devtools/LiveEditor.tsx +1 -1
  117. package/src/lib/theme/hooks/useThemeSwitcher.ts +164 -0
  118. package/src/lib/theme/index.ts +322 -38
  119. package/src/lib/theme/runtime/ThemeProvider.tsx +45 -11
  120. package/src/lib/theme/runtime/__tests__/ThemeProvider.test.tsx +44 -393
  121. package/src/lib/theme/runtime/useTheme.ts +1 -0
  122. package/src/lib/theme/tokens/tokens.ts +101 -1
  123. package/src/lib/theme/types.ts +91 -0
  124. package/src/lib/theme/utils/performanceMonitor.ts +315 -0
  125. package/src/lib/theme/utils/responsive.ts +280 -0
  126. package/src/lib/theme/utils/themeUtils.ts +531 -117
  127. package/src/styles/01-settings/_index.scss +1 -0
  128. package/src/styles/01-settings/_settings.atomix-glass.scss +174 -0
  129. package/src/styles/01-settings/_settings.masonry-grid.scss +42 -6
  130. package/src/styles/02-tools/_tools.glass.scss +6 -0
  131. package/src/styles/05-objects/_objects.masonry-grid.scss +162 -24
  132. package/src/styles/06-components/_components.atomix-glass.scss +4 -4
  133. package/src/lib/composables/useBreadcrumb.ts +0 -81
  134. package/src/lib/composables/useChartInteractions.ts +0 -123
  135. package/src/lib/composables/useChartPerformance.ts +0 -347
  136. package/src/lib/composables/useDropdown.ts +0 -338
  137. package/src/lib/composables/useModal.ts +0 -110
  138. package/src/lib/hooks/usePerformanceMonitor.ts +0 -148
  139. package/src/lib/utils/displacement-generator.ts +0 -92
  140. package/src/lib/utils/memoryMonitor.ts +0 -191
  141. package/src/styles/01-settings/_settings.testtypecheck.scss +0 -53
  142. package/src/styles/01-settings/_settings.typedbutton.scss +0 -53
  143. package/src/styles/06-components/_components.testbutton.scss +0 -212
  144. package/src/styles/06-components/_components.testtypecheck.scss +0 -212
  145. package/src/styles/06-components/_components.typedbutton.scss +0 -212
package/dist/index.esm.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
 
3
- import React, { useState, useRef, useEffect, memo, forwardRef, useId, useMemo, useCallback, Children, isValidElement, cloneElement, createContext, useContext, useImperativeHandle, Component } from "react";
3
+ import React, { useState, useRef, useCallback, useEffect, memo, forwardRef, useId, useMemo, Children, isValidElement, cloneElement, createContext, useContext, useImperativeHandle, Component } from "react";
4
4
 
5
5
  import * as PhosphorIcons from "@phosphor-icons/react";
6
6
 
@@ -8,6 +8,10 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
8
8
 
9
9
  import { createPortal } from "react-dom";
10
10
 
11
+ import { existsSync } from "fs";
12
+
13
+ import { join } from "path";
14
+
11
15
  var commonjsGlobal = "undefined" != typeof globalThis ? globalThis : "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof self ? self : {};
12
16
 
13
17
  function getDefaultExportFromCjs(x) {
@@ -1965,19 +1969,19 @@ function useAccordion(initialProps) {
1965
1969
  disabled: !1,
1966
1970
  iconPosition: "right",
1967
1971
  ...initialProps
1968
- }, isControlled = "boolean" == typeof defaultProps.isOpen, [internalOpen, setInternalOpen] = useState(defaultProps.defaultOpen || !1), isOpen = isControlled ? defaultProps.isOpen : internalOpen, [panelHeight, setPanelHeight] = useState(isOpen ? "auto" : "0px"), panelRef = useRef(null), contentRef = useRef(null), updatePanelHeight = () => {
1972
+ }, isControlled = "boolean" == typeof defaultProps.isOpen, [internalOpen, setInternalOpen] = useState(defaultProps.defaultOpen || !1), isOpen = isControlled ? defaultProps.isOpen : internalOpen, [panelHeight, setPanelHeight] = useState(isOpen ? "auto" : "0px"), panelRef = useRef(null), contentRef = useRef(null), updatePanelHeight = useCallback((() => {
1969
1973
  if (contentRef.current && panelRef.current) {
1970
1974
  const height = isOpen ? `${contentRef.current.clientHeight}px` : "0px";
1971
1975
  panelRef.current.style.setProperty(ACCORDION.CSS_VARS.PANEL_HEIGHT, height), setPanelHeight(height);
1972
1976
  }
1973
- };
1977
+ }), [ isOpen ]);
1974
1978
  // Controlled/uncontrolled open state
1975
1979
  /**
1976
1980
  * Effect to update panel height when open state changes
1977
1981
  */
1978
1982
  return useEffect((() => {
1979
1983
  updatePanelHeight();
1980
- }), [ isOpen ]),
1984
+ }), [ isOpen, updatePanelHeight ]),
1981
1985
  /**
1982
1986
  * Effect to handle window resize and update panel height
1983
1987
  */
@@ -1986,7 +1990,7 @@ function useAccordion(initialProps) {
1986
1990
  isOpen && updatePanelHeight();
1987
1991
  };
1988
1992
  return window.addEventListener("resize", handleResize), () => window.removeEventListener("resize", handleResize);
1989
- }), [ isOpen ]), {
1993
+ }), [ isOpen, updatePanelHeight ]), {
1990
1994
  state: {
1991
1995
  isOpen: isOpen,
1992
1996
  panelHeight: panelHeight
@@ -3562,7 +3566,7 @@ function useResponsiveGlass({baseParams: baseParams, breakpoints: breakpoints =
3562
3566
  * @param config Monitor configuration
3563
3567
  * @returns Performance metrics and controls
3564
3568
  */
3565
- function usePerformanceMonitor(config = {}) {
3569
+ function usePerformanceMonitor$1(config = {}) {
3566
3570
  const {enabled: enabled = !0, targetFps: targetFps = 60, minFps: minFps = 45, scaleUpThreshold: scaleUpThreshold = 58, lowFpsFrames: lowFpsFrames = 3, highFpsFrames: highFpsFrames = 10, debug: debug = !1, showOverlay: showOverlay = !1} = config, [metrics, setMetrics] = useState({
3567
3571
  fps: 0,
3568
3572
  frameTime: 0,
@@ -4118,7 +4122,7 @@ function getDevicePreset(presetName) {
4118
4122
  debug: !1
4119
4123
  });
4120
4124
  // Performance monitoring - tracks FPS, frame time, memory usage
4121
- const {metrics: performanceMetrics, toggleMonitoring: toggleMonitoring} = usePerformanceMonitor({
4125
+ const {metrics: performanceMetrics, toggleMonitoring: toggleMonitoring} = usePerformanceMonitor$1({
4122
4126
  enabled: debugPerformance,
4123
4127
  // Enable when debugPerformance is true
4124
4128
  debug: !1,
@@ -5111,7 +5115,7 @@ const BreadcrumbItem = forwardRef((({children: children, href: href, active: ac
5111
5115
 
5112
5116
  BreadcrumbItem.displayName = "BreadcrumbItem";
5113
5117
 
5114
- const Breadcrumb = memo((function({items: items, divider: divider, className: className = "", "aria-label": ariaLabel = "Breadcrumb", linkComponent: linkComponent, style: style, children: children}) {
5118
+ const BreadcrumbComponent = memo((function({items: items, divider: divider, className: className = "", "aria-label": ariaLabel = "Breadcrumb", linkComponent: linkComponent, style: style, children: children}) {
5115
5119
  const breadcrumbClasses = [ BREADCRUMB.CLASSES.BASE, className ].filter(Boolean).join(" ");
5116
5120
  let content;
5117
5121
  if (items && items.length > 0)
@@ -5151,7 +5155,7 @@ const Breadcrumb = memo((function({items: items, divider: divider, className: c
5151
5155
  children: content
5152
5156
  })
5153
5157
  });
5154
- }));
5158
+ })), Breadcrumb = BreadcrumbComponent;
5155
5159
 
5156
5160
  /**
5157
5161
  * Spinner state and functionality
@@ -5311,7 +5315,152 @@ class ThemeNaming {
5311
5315
 
5312
5316
  ThemeNaming.prefix = "atomix";
5313
5317
 
5314
- const Button = React.memo( 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) => {
5318
+ var aCallable = aCallable$3, toObject = toObject$2, IndexedObject = indexedObject, lengthOfArrayLike = lengthOfArrayLike$2, $TypeError = TypeError, REDUCE_EMPTY = "Reduce of empty array with no initial value", createMethod = function(IS_RIGHT) {
5319
+ return function(that, callbackfn, argumentsLength, memo) {
5320
+ var O = toObject(that), self = IndexedObject(O), length = lengthOfArrayLike(O);
5321
+ if (aCallable(callbackfn), 0 === length && argumentsLength < 2) throw new $TypeError(REDUCE_EMPTY);
5322
+ var index = IS_RIGHT ? length - 1 : 0, i = IS_RIGHT ? -1 : 1;
5323
+ if (argumentsLength < 2) for (;;) {
5324
+ if (index in self) {
5325
+ memo = self[index], index += i;
5326
+ break;
5327
+ }
5328
+ if (index += i, IS_RIGHT ? index < 0 : length <= index) throw new $TypeError(REDUCE_EMPTY);
5329
+ }
5330
+ for (;IS_RIGHT ? index >= 0 : length > index; index += i) index in self && (memo = callbackfn(memo, self[index], index, O));
5331
+ return memo;
5332
+ };
5333
+ }, arrayReduce = {
5334
+ // `Array.prototype.reduce` method
5335
+ // https://tc39.es/ecma262/#sec-array.prototype.reduce
5336
+ left: createMethod(!1),
5337
+ // `Array.prototype.reduceRight` method
5338
+ // https://tc39.es/ecma262/#sec-array.prototype.reduceright
5339
+ right: createMethod(!0)
5340
+ }, fails = fails$9, globalThis$1 = globalThis_1, userAgent = environmentUserAgent, classof = classofRaw$2, userAgentStartsWith = function(string) {
5341
+ return userAgent.slice(0, string.length) === string;
5342
+ }, environment = userAgentStartsWith("Bun/") ? "BUN" : userAgentStartsWith("Cloudflare-Workers") ? "CLOUDFLARE" : userAgentStartsWith("Deno/") ? "DENO" : userAgentStartsWith("Node.js/") ? "NODE" : globalThis$1.Bun && "string" == typeof Bun.version ? "BUN" : globalThis$1.Deno && "object" == typeof Deno.version ? "DENO" : "process" === classof(globalThis$1.process) ? "NODE" : globalThis$1.window && globalThis$1.document ? "BROWSER" : "REST", $reduce = arrayReduce.left;
5343
+
5344
+ // `Array.prototype.reduce` method
5345
+ // https://tc39.es/ecma262/#sec-array.prototype.reduce
5346
+ _export({
5347
+ target: "Array",
5348
+ proto: !0,
5349
+ forced: !("NODE" === environment) && environmentV8Version > 79 && environmentV8Version < 83 || !function(METHOD_NAME, argument) {
5350
+ var method = [][METHOD_NAME];
5351
+ return !!method && fails((function() {
5352
+ // eslint-disable-next-line no-useless-call -- required for testing
5353
+ method.call(null, argument || function() {
5354
+ return 1;
5355
+ }, 1);
5356
+ }));
5357
+ }("reduce")
5358
+ }, {
5359
+ reduce: function(callbackfn /* , initialValue */) {
5360
+ var length = arguments.length;
5361
+ return $reduce(this, callbackfn, length, length > 1 ? arguments[1] : void 0);
5362
+ }
5363
+ });
5364
+
5365
+ var reduce$3 = getBuiltInPrototypeMethod$3("Array", "reduce"), isPrototypeOf = objectIsPrototypeOf, method = reduce$3, ArrayPrototype = Array.prototype;
5366
+
5367
+ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
5368
+ var own = it.reduce;
5369
+ return it === ArrayPrototype || isPrototypeOf(ArrayPrototype, it) && own === ArrayPrototype.reduce ? method : own;
5370
+ }));
5371
+
5372
+ /**
5373
+ * Render a slot with the given props
5374
+ *
5375
+ * Priority order:
5376
+ * 1. render function
5377
+ * 2. component
5378
+ * 3. children
5379
+ * 4. fallback
5380
+ *
5381
+ * @example
5382
+ * renderSlot(
5383
+ * { render: (props) => <CustomButton {...props} /> },
5384
+ * { onClick: handleClick, children: 'Click me' }
5385
+ * )
5386
+ */ function renderSlot(slot, props, fallback) {
5387
+ // No slot provided, use fallback
5388
+ if (!slot) return fallback;
5389
+ // Slot is a plain React node
5390
+ if ( React.isValidElement(slot) || "string" == typeof slot || "number" == typeof slot) return slot;
5391
+ // Slot is an object with rendering options
5392
+ if ("object" == typeof slot && null !== slot) {
5393
+ const slotObj = slot;
5394
+ // Priority 1: render function
5395
+ if (slotObj.render && "function" == typeof slotObj.render) return slotObj.render(props);
5396
+ // Priority 2: component
5397
+ if (slotObj.component) {
5398
+ const Component = slotObj.component;
5399
+ return jsx(Component, {
5400
+ ...props
5401
+ });
5402
+ }
5403
+ // Priority 3: children
5404
+ if (void 0 !== slotObj.children) return slotObj.children;
5405
+ }
5406
+ // Fallback
5407
+ return fallback;
5408
+ }
5409
+
5410
+ /**
5411
+ * Check if a value is a slot configuration
5412
+ */ function isSlot(value) {
5413
+ return "object" == typeof value && null !== value && ("render" in value || "component" in value || "children" in value);
5414
+ }
5415
+
5416
+ /**
5417
+ * Merge multiple slot configurations
5418
+ * Later slots override earlier ones
5419
+ */ function mergeSlots(...slots) {
5420
+ const filtered = slots.filter((s => void 0 !== s));
5421
+ if (0 !== filtered.length) return 1 === filtered.length ? filtered[0] : _reduceInstanceProperty(filtered).call(filtered, ((acc, slot) => ({
5422
+ ...acc,
5423
+ ...slot
5424
+ })));
5425
+ }
5426
+
5427
+ /**
5428
+ * Create a slot wrapper component
5429
+ *
5430
+ * @example
5431
+ * const ButtonSlot = createSlotComponent<ButtonSlotProps>('button')
5432
+ *
5433
+ * <ButtonSlot slot={customSlot} {...props}>
5434
+ * Default content
5435
+ * </ButtonSlot>
5436
+ */ function createSlotComponent(defaultElement = "div") {
5437
+ return function({slot: slot, children: children, ...props}) {
5438
+ const slotProps = props;
5439
+ return slot ? jsx(Fragment, {
5440
+ children: renderSlot(slot, slotProps, children)
5441
+ }) : jsx(defaultElement, "string" == typeof defaultElement ? {
5442
+ ...props,
5443
+ children: children
5444
+ } : {
5445
+ ...slotProps,
5446
+ children: children
5447
+ });
5448
+ };
5449
+ }
5450
+
5451
+ /**
5452
+ * Utility to create typed slot props
5453
+ */ function createSlotProps(props) {
5454
+ return props;
5455
+ }
5456
+
5457
+ /**
5458
+ * Hook to manage slot rendering
5459
+ */ function useSlot(slot, props, fallback) {
5460
+ return React.useMemo((() => renderSlot(slot, props, fallback)), [ slot, props, fallback ]);
5461
+ }
5462
+
5463
+ const Button = React.memo( 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, slots: slots, ...props}, ref) => {
5315
5464
  const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href), iconElement = iconName ? jsx(Icon, {
5316
5465
  name: iconName,
5317
5466
  size: iconSize
@@ -5327,17 +5476,28 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
5327
5476
  children: [ loading && jsx("span", {
5328
5477
  className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.SPINNER_ELEMENT),
5329
5478
  "aria-hidden": "true",
5330
- children: jsx(Spinner, {
5479
+ children: renderSlot(slots?.spinner, {
5480
+ className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.SPINNER_ELEMENT),
5331
5481
  size: spinnerSize,
5332
5482
  variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
5333
- })
5483
+ }, jsx(Spinner, {
5484
+ size: spinnerSize,
5485
+ variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
5486
+ }))
5334
5487
  }), iconElement && !loading && jsx("span", {
5335
5488
  className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.ICON_ELEMENT),
5336
5489
  "aria-hidden": "true",
5337
- children: iconElement
5490
+ children: renderSlot(slots?.icon, {
5491
+ className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.ICON_ELEMENT),
5492
+ children: iconElement,
5493
+ size: iconSize
5494
+ }, iconElement)
5338
5495
  }), !iconOnly && buttonText && jsx("span", {
5339
5496
  className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.LABEL_ELEMENT),
5340
- children: buttonText
5497
+ children: renderSlot(slots?.label, {
5498
+ className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.LABEL_ELEMENT),
5499
+ children: buttonText
5500
+ }, buttonText)
5341
5501
  }) ]
5342
5502
  }), buttonProps = {
5343
5503
  className: buttonClass,
@@ -5354,48 +5514,59 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
5354
5514
  tabIndex: void 0 !== tabIndex ? tabIndex : isDisabled ? -1 : 0,
5355
5515
  style: style,
5356
5516
  ...props
5357
- };
5358
- // Determine if we should render as a link
5359
- // If disabled, we still check href, but we might want to render as button or anchor with aria-disabled
5360
- // The previous logic was Boolean(href && !isDisabled). This meant if disabled, it renders as <button>.
5361
- // This is a safe fallback for disabled links.
5362
- let content;
5363
- // Render as anchor if href is provided
5364
- if (shouldRenderAsLink)
5365
- // Use custom linkComponent if provided (e.g., Next.js Link)
5366
- if (linkComponent) {
5367
- const LinkComp = linkComponent, linkProps = {
5517
+ }, buttonChildren = renderSlot(slots?.root, {
5518
+ className: buttonClass,
5519
+ children: buttonContent,
5520
+ disabled: isDisabled,
5521
+ loading: loading,
5522
+ onClick: handleClickEvent,
5523
+ type: type,
5524
+ "aria-label": safeAriaLabel,
5525
+ "aria-disabled": isDisabled,
5526
+ "aria-busy": loading
5527
+ }, (() => {
5528
+ // Render as anchor if href is provided
5529
+ if (shouldRenderAsLink) {
5530
+ // Use custom linkComponent if provided (e.g., Next.js Link)
5531
+ if (linkComponent) {
5532
+ const LinkComp = linkComponent, linkProps = {
5533
+ ...buttonProps,
5534
+ ref: ref,
5535
+ // linkComponent usually forwards ref to anchor
5536
+ href: isDisabled ? void 0 : href,
5537
+ to: isDisabled ? void 0 : href,
5538
+ target: target,
5539
+ rel: "_blank" === target ? "noopener noreferrer" : void 0
5540
+ };
5541
+ return jsx(LinkComp, {
5542
+ ...linkProps,
5543
+ children: buttonContent
5544
+ });
5545
+ }
5546
+ // Fallback to regular anchor tag
5547
+ return jsx("a", {
5548
+ ...buttonProps,
5549
+ ref: ref,
5550
+ href: isDisabled ? void 0 : href,
5551
+ target: target,
5552
+ rel: "_blank" === target ? "noopener noreferrer" : void 0,
5553
+ children: buttonContent
5554
+ });
5555
+ }
5556
+ // Default button rendering
5557
+ return jsx(Component, {
5368
5558
  ...buttonProps,
5369
5559
  ref: ref,
5370
- // linkComponent usually forwards ref to anchor
5371
- href: isDisabled ? void 0 : href,
5372
- to: isDisabled ? void 0 : href,
5373
- target: target,
5374
- rel: "_blank" === target ? "noopener noreferrer" : void 0
5375
- };
5376
- content = jsx(LinkComp, {
5377
- ...linkProps,
5560
+ type: "button" === Component ? type : void 0,
5561
+ disabled: isDisabled,
5378
5562
  children: buttonContent
5379
5563
  });
5380
- } else
5381
- // Fallback to regular anchor tag
5382
- content = jsx("a", {
5383
- ...buttonProps,
5384
- ref: ref,
5385
- href: isDisabled ? void 0 : href,
5386
- target: target,
5387
- rel: "_blank" === target ? "noopener noreferrer" : void 0,
5388
- children: buttonContent
5389
- }); else
5390
- // Default button rendering
5391
- content = jsx(Component, {
5392
- ...buttonProps,
5393
- ref: ref,
5394
- type: "button" === Component ? type : void 0,
5395
- disabled: isDisabled,
5396
- children: buttonContent
5397
- });
5398
- if (glass) {
5564
+ })());
5565
+ // Determine if we should render as a link
5566
+ // If disabled, we still check href, but we might want to render as button or anchor with aria-disabled
5567
+ // The previous logic was Boolean(href && !isDisabled). This meant if disabled, it renders as <button>.
5568
+ // This is a safe fallback for disabled links.
5569
+ if (glass) {
5399
5570
  // Default glass props
5400
5571
  const defaultGlassProps = {
5401
5572
  displacementScale: 20,
@@ -5408,10 +5579,10 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
5408
5579
  };
5409
5580
  return jsx(AtomixGlass, {
5410
5581
  ...glassProps,
5411
- children: content
5582
+ children: buttonChildren
5412
5583
  });
5413
5584
  }
5414
- return content;
5585
+ return buttonChildren;
5415
5586
  })));
5416
5587
 
5417
5588
  Button.displayName = "Button";
@@ -5923,67 +6094,12 @@ const ElevationCard = ({elevationClass: elevationClass = "is-elevated", classNam
5923
6094
  });
5924
6095
  };
5925
6096
 
5926
- ElevationCard.displayName = "ElevationCard";
5927
-
5928
- var aCallable = aCallable$3, toObject = toObject$2, IndexedObject = indexedObject, lengthOfArrayLike = lengthOfArrayLike$2, $TypeError = TypeError, REDUCE_EMPTY = "Reduce of empty array with no initial value", createMethod = function(IS_RIGHT) {
5929
- return function(that, callbackfn, argumentsLength, memo) {
5930
- var O = toObject(that), self = IndexedObject(O), length = lengthOfArrayLike(O);
5931
- if (aCallable(callbackfn), 0 === length && argumentsLength < 2) throw new $TypeError(REDUCE_EMPTY);
5932
- var index = IS_RIGHT ? length - 1 : 0, i = IS_RIGHT ? -1 : 1;
5933
- if (argumentsLength < 2) for (;;) {
5934
- if (index in self) {
5935
- memo = self[index], index += i;
5936
- break;
5937
- }
5938
- if (index += i, IS_RIGHT ? index < 0 : length <= index) throw new $TypeError(REDUCE_EMPTY);
5939
- }
5940
- for (;IS_RIGHT ? index >= 0 : length > index; index += i) index in self && (memo = callbackfn(memo, self[index], index, O));
5941
- return memo;
5942
- };
5943
- }, arrayReduce = {
5944
- // `Array.prototype.reduce` method
5945
- // https://tc39.es/ecma262/#sec-array.prototype.reduce
5946
- left: createMethod(!1),
5947
- // `Array.prototype.reduceRight` method
5948
- // https://tc39.es/ecma262/#sec-array.prototype.reduceright
5949
- right: createMethod(!0)
5950
- }, fails = fails$9, globalThis$1 = globalThis_1, userAgent = environmentUserAgent, classof = classofRaw$2, userAgentStartsWith = function(string) {
5951
- return userAgent.slice(0, string.length) === string;
5952
- }, environment = userAgentStartsWith("Bun/") ? "BUN" : userAgentStartsWith("Cloudflare-Workers") ? "CLOUDFLARE" : userAgentStartsWith("Deno/") ? "DENO" : userAgentStartsWith("Node.js/") ? "NODE" : globalThis$1.Bun && "string" == typeof Bun.version ? "BUN" : globalThis$1.Deno && "object" == typeof Deno.version ? "DENO" : "process" === classof(globalThis$1.process) ? "NODE" : globalThis$1.window && globalThis$1.document ? "BROWSER" : "REST", $reduce = arrayReduce.left;
5953
-
5954
- // `Array.prototype.reduce` method
5955
- // https://tc39.es/ecma262/#sec-array.prototype.reduce
5956
- _export({
5957
- target: "Array",
5958
- proto: !0,
5959
- forced: !("NODE" === environment) && environmentV8Version > 79 && environmentV8Version < 83 || !function(METHOD_NAME, argument) {
5960
- var method = [][METHOD_NAME];
5961
- return !!method && fails((function() {
5962
- // eslint-disable-next-line no-useless-call -- required for testing
5963
- method.call(null, argument || function() {
5964
- return 1;
5965
- }, 1);
5966
- }));
5967
- }("reduce")
5968
- }, {
5969
- reduce: function(callbackfn /* , initialValue */) {
5970
- var length = arguments.length;
5971
- return $reduce(this, callbackfn, length, length > 1 ? arguments[1] : void 0);
5972
- }
5973
- });
5974
-
5975
- var reduce$3 = getBuiltInPrototypeMethod$3("Array", "reduce"), isPrototypeOf = objectIsPrototypeOf, method = reduce$3, ArrayPrototype = Array.prototype;
5976
-
5977
- const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
5978
- var own = it.reduce;
5979
- return it === ArrayPrototype || isPrototypeOf(ArrayPrototype, it) && own === ArrayPrototype.reduce ? method : own;
5980
- }));
5981
-
5982
6097
  /**
5983
6098
  * Comprehensive chart hook with shared functionality
5984
6099
  * @param initialProps - Initial chart properties
5985
6100
  * @returns Chart state and methods
5986
- */ function useChart(initialProps) {
6101
+ */
6102
+ function useChart(initialProps) {
5987
6103
  const [interactionState, setInteractionState] = useState({
5988
6104
  hoveredPoint: null,
5989
6105
  selectedPoints: [],
@@ -6015,8 +6131,11 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
6015
6131
  }), animationFrameRef = useRef(null);
6016
6132
  // Default chart properties
6017
6133
  // Cleanup animation frame on unmount
6018
- useEffect((() => () => {
6019
- animationFrameRef.current && cancelAnimationFrame(animationFrameRef.current);
6134
+ useEffect((() => {
6135
+ const currentRef = animationFrameRef.current;
6136
+ return () => {
6137
+ currentRef && cancelAnimationFrame(currentRef);
6138
+ };
6020
6139
  }), []);
6021
6140
  /**
6022
6141
  * Point interaction handlers
@@ -6407,7 +6526,9 @@ function getDatasetBounds(data) {
6407
6526
 
6408
6527
  /**
6409
6528
  * Hook for managing chart toolbar state and generating chart-specific configurations
6410
- */ const ChartToolbar = memo( forwardRef((({chartType: chartType = "line", groups: groups = [], enableDefaults: enableDefaults = !0, defaults: defaults = {
6529
+ */ ElevationCard.displayName = "ElevationCard";
6530
+
6531
+ const ChartToolbar = memo( forwardRef((({chartType: chartType = "line", groups: groups = [], enableDefaults: enableDefaults = !0, defaults: defaults = {
6411
6532
  refresh: !0,
6412
6533
  export: !0,
6413
6534
  fullscreen: !0,
@@ -6897,8 +7018,8 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
6897
7018
  }), [ chartType ]), finalDefaults = useMemo((() => ({
6898
7019
  ...getChartDefaults(),
6899
7020
  ...defaults
6900
- })), [ getChartDefaults, defaults ]), enhancedHandlers = {
6901
- onRefresh: useCallback((() => {
7021
+ })), [ getChartDefaults, defaults ]), enhancedHandlers = useMemo((() => ({
7022
+ onRefresh: () => {
6902
7023
  setState((prev => ({
6903
7024
  ...prev,
6904
7025
  isRefreshing: !0
@@ -6908,8 +7029,8 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
6908
7029
  isRefreshing: !1
6909
7030
  })));
6910
7031
  }), 1e3);
6911
- }), [ handlers.onRefresh ]),
6912
- onExport: useCallback((async format => {
7032
+ },
7033
+ onExport: async format => {
6913
7034
  setState((prev => ({
6914
7035
  ...prev,
6915
7036
  isExporting: !0
@@ -6922,70 +7043,70 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
6922
7043
  isExporting: !1
6923
7044
  })));
6924
7045
  }
6925
- }), [ handlers.onExport ]),
6926
- onFullscreen: useCallback((isFullscreen => {
7046
+ },
7047
+ onFullscreen: isFullscreen => {
6927
7048
  setState((prev => ({
6928
7049
  ...prev,
6929
7050
  isFullscreen: isFullscreen
6930
7051
  }))), handlers.onFullscreen?.(isFullscreen);
6931
- }), [ handlers.onFullscreen ]),
6932
- onZoomIn: useCallback((() => {
7052
+ },
7053
+ onZoomIn: () => {
6933
7054
  setState((prev => ({
6934
7055
  ...prev,
6935
7056
  zoomLevel: Math.min(1.2 * prev.zoomLevel, 5)
6936
7057
  }))), handlers.onZoomIn?.();
6937
- }), [ handlers.onZoomIn ]),
6938
- onZoomOut: useCallback((() => {
7058
+ },
7059
+ onZoomOut: () => {
6939
7060
  setState((prev => ({
6940
7061
  ...prev,
6941
7062
  zoomLevel: Math.max(prev.zoomLevel / 1.2, .2)
6942
7063
  }))), handlers.onZoomOut?.();
6943
- }), [ handlers.onZoomOut ]),
6944
- onZoomReset: useCallback((() => {
7064
+ },
7065
+ onZoomReset: () => {
6945
7066
  setState((prev => ({
6946
7067
  ...prev,
6947
7068
  zoomLevel: 1
6948
7069
  }))), handlers.onZoomReset?.();
6949
- }), [ handlers.onZoomReset ]),
6950
- onPanToggle: useCallback((enabled => {
7070
+ },
7071
+ onPanToggle: enabled => {
6951
7072
  setState((prev => ({
6952
7073
  ...prev,
6953
7074
  panEnabled: enabled
6954
7075
  }))), handlers.onPanToggle?.(enabled);
6955
- }), [ handlers.onPanToggle ]),
6956
- onReset: useCallback((() => {
7076
+ },
7077
+ onReset: () => {
6957
7078
  setState((prev => ({
6958
7079
  ...prev,
6959
7080
  zoomLevel: 1,
6960
7081
  panEnabled: !1
6961
7082
  }))), handlers.onReset?.();
6962
- }), [ handlers.onReset ]),
6963
- onGridToggle: useCallback((show => {
7083
+ },
7084
+ onGridToggle: show => {
6964
7085
  setState((prev => ({
6965
7086
  ...prev,
6966
7087
  showGrid: show
6967
7088
  }))), handlers.onGridToggle?.(show);
6968
- }), [ handlers.onGridToggle ]),
6969
- onLegendToggle: useCallback((show => {
7089
+ },
7090
+ onLegendToggle: show => {
6970
7091
  setState((prev => ({
6971
7092
  ...prev,
6972
7093
  showLegend: show
6973
7094
  }))), handlers.onLegendToggle?.(show);
6974
- }), [ handlers.onLegendToggle ]),
6975
- onTooltipsToggle: useCallback((show => {
7095
+ },
7096
+ onTooltipsToggle: show => {
6976
7097
  setState((prev => ({
6977
7098
  ...prev,
6978
7099
  showTooltips: show
6979
7100
  }))), handlers.onTooltipsToggle?.(show);
6980
- }), [ handlers.onTooltipsToggle ]),
6981
- onAnimationsToggle: useCallback((enabled => {
7101
+ },
7102
+ onAnimationsToggle: enabled => {
6982
7103
  setState((prev => ({
6983
7104
  ...prev,
6984
7105
  animationsEnabled: enabled
6985
7106
  }))), handlers.onAnimationsToggle?.(enabled);
6986
- }), [ handlers.onAnimationsToggle ]),
6987
- onSettings: useCallback((() => {}), [])
6988
- }, generateToolbarGroups = useCallback((() => {
7107
+ },
7108
+ onSettings: () => {}
7109
+ })), [ handlers ]), generateToolbarGroups = useCallback((() => {
6989
7110
  const groups = [], dataActions = [];
6990
7111
  // Data actions group
6991
7112
  finalDefaults.refresh && dataActions.push({
@@ -7110,7 +7231,7 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
7110
7231
  actions: customActions
7111
7232
  });
7112
7233
  return groups;
7113
- }), [ chartType, finalDefaults, state, enhancedHandlers, customActions, customGroups ]);
7234
+ }), [ finalDefaults, state, enhancedHandlers, customActions, customGroups ]);
7114
7235
  // Keyboard shortcuts
7115
7236
  return useEffect((() => {
7116
7237
  const handleKeyDown = event => {
@@ -7702,7 +7823,7 @@ const ChartRenderer = memo( forwardRef((({datasets: datasets = [], config: conf
7702
7823
  announcement: announcement,
7703
7824
  focusedPoint: focusedPoint,
7704
7825
  getAccessibleDescription: () => "Chart description"
7705
- })), [ announcement, focusedPoint ]), transform = useMemo((() => chartContext ? `translate(${chartContext.panOffset.x}px, ${chartContext.panOffset.y}px) scale(${chartContext.zoomLevel})` : ""), [ chartContext?.panOffset.x, chartContext?.panOffset.y, chartContext?.zoomLevel ]), chartData = useMemo((() => {
7826
+ })), [ announcement, focusedPoint ]), transform = useMemo((() => chartContext ? `translate(${chartContext.panOffset.x}px, ${chartContext.panOffset.y}px) scale(${chartContext.zoomLevel})` : ""), [ chartContext ]), chartData = useMemo((() => {
7706
7827
  // Return null if dimensions not ready to prevent calculation with invalid dimensions
7707
7828
  if (!isInitialized || 0 === dimensions.width || 0 === dimensions.height) return null;
7708
7829
  const scales = calculateScales(processedData, dimensions.width, dimensions.height, void 0, config);
@@ -8115,7 +8236,7 @@ function useBarChart(datasets, options = {}) {
8115
8236
  opacity: .4
8116
8237
  } ]
8117
8238
  };
8118
- })) : []), [ options.useGradients ]), formatValue = useCallback((value => options.valueFormatter ? options.valueFormatter(value) : value.toString()), [ options.valueFormatter ]);
8239
+ })) : []), [ options.useGradients ]), formatValue = useCallback((value => options.valueFormatter ? options.valueFormatter(value) : value.toString()), [ options ]);
8119
8240
  return {
8120
8241
  // State
8121
8242
  hoveredBar: hoveredBar,
@@ -8141,7 +8262,7 @@ function useBarChart(datasets, options = {}) {
8141
8262
  y: horizontal ? y + height / 2 : y - 5
8142
8263
  };
8143
8264
  }
8144
- }), [ options.dataLabelPosition ]),
8265
+ }), [ options ]),
8145
8266
  // Handlers
8146
8267
  handleBarHover: handleBarHover,
8147
8268
  handleBarLeave: handleBarLeave,
@@ -8450,13 +8571,13 @@ const DonutChart = memo( forwardRef((({datasets: datasets = [], config: config
8450
8571
  roundedCorners: !0
8451
8572
  }, onDataPointClick: onDataPointClick, ...props}, ref) => {
8452
8573
  // Use the first dataset for donut chart
8453
- const dataset = datasets.length > 0 ? datasets[0] : {
8574
+ const dataset = useMemo((() => datasets.length > 0 ? datasets[0] : {
8454
8575
  label: "",
8455
8576
  data: []
8456
- }, chartData = useMemo((() => {
8577
+ }), [ datasets ]), chartData = useMemo((() => {
8457
8578
  if (!dataset?.data?.length) return null;
8458
8579
  // Filter out invalid data points
8459
- const validDataPoints = dataset?.data?.filter((point => "number" == typeof point.value && !isNaN(point.value) && isFinite(point.value) && point.value > 0));
8580
+ const validDataPoints = (dataset?.data || []).filter((point => "number" == typeof point.value && !isNaN(point.value) && isFinite(point.value) && point.value > 0));
8460
8581
  return validDataPoints.length ? {
8461
8582
  validDataPoints: validDataPoints
8462
8583
  } : null;
@@ -9412,7 +9533,7 @@ function usePieChart(data, options = {}) {
9412
9533
  const parts = [];
9413
9534
  return !1 !== options.showLabels && parts.push(slice.label), options.showPercentages && parts.push(`${Math.round(slice.percentage)}%`),
9414
9535
  options.showValues && parts.push(slice.value.toString()), parts.join(" - ");
9415
- }), [ options.labelFormatter, options.showLabels, options.showPercentages, options.showValues ]), getSliceTransform = useCallback(((slice, isHovered) => isHovered && options.enableHoverEffects && options.hoverOffset ? `translate(${Math.cos(slice.midAngle) * options.hoverOffset}, ${Math.sin(slice.midAngle) * options.hoverOffset})` : ""), [ options.enableHoverEffects, options.hoverOffset ]), isSliceSelected = useCallback((index => selectedSlices.has(index)), [ selectedSlices ]);
9536
+ }), [ options ]), getSliceTransform = useCallback(((slice, isHovered) => isHovered && options.enableHoverEffects && options.hoverOffset ? `translate(${Math.cos(slice.midAngle) * options.hoverOffset}, ${Math.sin(slice.midAngle) * options.hoverOffset})` : ""), [ options.enableHoverEffects, options.hoverOffset ]), isSliceSelected = useCallback((index => selectedSlices.has(index)), [ selectedSlices ]);
9416
9537
  return {
9417
9538
  // Data
9418
9539
  processedData: processedData,
@@ -10839,7 +10960,7 @@ const DataTable = memo((({data: data, columns: columns, className: className, s
10839
10960
  const newOrder = columns.map((col => col.key)), currentOrderSet = new Set(columnOrder), newOrderSet = new Set(newOrder);
10840
10961
  // Only update if there are actual differences
10841
10962
  newOrder.length === columnOrder.length && newOrder.every((key => currentOrderSet.has(key))) && columnOrder.every((key => newOrderSet.has(key))) || setColumnOrder(newOrder);
10842
- }), [ columns ]),
10963
+ }), [ columns, columnOrder ]),
10843
10964
  // Update column visibility when columns prop changes
10844
10965
  useEffect((() => {
10845
10966
  setColumnVisibility((prev => {
@@ -11384,7 +11505,7 @@ function formatDate(date, format) {
11384
11505
  /**
11385
11506
  * Check if a date is within a min and max range
11386
11507
  */ function useDatePicker({value: value, onChange: onChange, selectionMode: selectionMode = "single", startDate: startDate, endDate: endDate, onRangeChange: onRangeChange, format: format = "MM/dd/yyyy", minDate: minDate, maxDate: maxDate, inline: inline = !1} = {}) {
11387
- const [isOpen, setIsOpen] = useState(inline), [inputValue, setInputValue] = useState(value ? formatDate(value, format) : ""), [rangeInputValue, setRangeInputValue] = useState(startDate && endDate ? `${formatDate(startDate, format)} - ${formatDate(endDate, format)}` : startDate ? `${formatDate(startDate, format)} - Select end date` : ""), [viewDate, setViewDate] = useState(value || startDate || new Date), [viewMode, setViewMode] = useState("days"), [rangeSelectionState, setRangeSelectionState] = useState(!startDate || startDate && endDate ? "start" : "end"), datePickerRef = useRef(null), inputRef = useRef(null), today = new Date, currentMonth = viewDate.getMonth(), currentYear = viewDate.getFullYear(), daysInMonth = getDaysInMonth(currentYear, currentMonth), firstDayOfMonth = new Date(currentYear, currentMonth, 1).getDay();
11508
+ const [isOpen, setIsOpen] = useState(inline), [inputValue, setInputValue] = useState(value ? formatDate(value, format) : ""), [rangeInputValue, setRangeInputValue] = useState(startDate && endDate ? `${formatDate(startDate, format)} - ${formatDate(endDate, format)}` : startDate ? `${formatDate(startDate, format)} - Select end date` : ""), [viewDate, setViewDate] = useState(value || startDate || new Date), [viewMode, setViewMode] = useState("days"), [rangeSelectionState, setRangeSelectionState] = useState(!startDate || startDate && endDate ? "start" : "end"), datePickerRef = useRef(null), inputRef = useRef(null), today = useMemo((() => new Date), []), currentMonth = viewDate.getMonth(), currentYear = viewDate.getFullYear(), daysInMonth = getDaysInMonth(currentYear, currentMonth), firstDayOfMonth = new Date(currentYear, currentMonth, 1).getDay();
11388
11509
  // Update input value when value or range dates change externally
11389
11510
  useEffect((() => {
11390
11511
  "single" === selectionMode ? setInputValue(value ? formatDate(value, format) : "") : (setRangeInputValue(startDate && endDate ? `${formatDate(startDate, format)} - ${formatDate(endDate, format)}` : startDate ? `${formatDate(startDate, format)} - Select end date` : ""),
@@ -11907,21 +12028,11 @@ const DatePicker = forwardRef((({value: value, onChange: onChange, selectionMod
11907
12028
  * @returns EdgePanel state and methods
11908
12029
  */
11909
12030
  function useEdgePanel(initialProps) {
11910
- // Default EdgePanel properties
11911
- const defaultProps = {
11912
- position: "start",
11913
- mode: "slide",
11914
- isOpen: !1,
11915
- backdrop: !0,
11916
- closeOnBackdropClick: !0,
11917
- closeOnEscape: !0,
11918
- glass: void 0,
11919
- ...initialProps
11920
- }, [isOpen, setIsOpen] = useState(defaultProps.isOpen || !1), containerRef = useRef(null), backdropRef = useRef(null), adjustBodyPadding = useCallback((() => {
11921
- if (!containerRef.current || "push" !== defaultProps.mode) return;
11922
- const {position: position} = defaultProps, size = "top" === position || "bottom" === position ? containerRef.current.clientHeight : containerRef.current.clientWidth;
12031
+ const {position: position = "start", mode: mode = "slide", isOpen: propIsOpen = !1, backdrop: backdrop = !0, closeOnBackdropClick: closeOnBackdropClick = !0, closeOnEscape: closeOnEscape = !0, glass: glass, onOpenChange: onOpenChange, className: className = ""} = initialProps || {}, [isOpen, setIsOpen] = useState(propIsOpen || !1), containerRef = useRef(null), backdropRef = useRef(null), adjustBodyPadding = useCallback((() => {
12032
+ if (!containerRef.current || "push" !== mode) return;
12033
+ const size = "top" === position || "bottom" === position ? containerRef.current.clientHeight : containerRef.current.clientWidth;
11923
12034
  // Map position to CSS padding property
11924
- let paddingProperty;
12035
+ let paddingProperty;
11925
12036
  switch (position) {
11926
12037
  case "start":
11927
12038
  paddingProperty = "paddingLeft";
@@ -11936,9 +12047,8 @@ function useEdgePanel(initialProps) {
11936
12047
  paddingProperty = `padding${position.charAt(0).toUpperCase() + position.slice(1)}`;
11937
12048
  }
11938
12049
  document.body.style[paddingProperty] = `${size}px`, document.body.classList.add("is-pushed");
11939
- }), [ defaultProps.mode, defaultProps.position ]), resetBodyPadding = useCallback((() => {
11940
- if ("push" !== defaultProps.mode) return;
11941
- const {position: position} = defaultProps;
12050
+ }), [ mode, position ]), resetBodyPadding = useCallback((() => {
12051
+ if ("push" !== mode) return;
11942
12052
  // Map position to CSS padding property
11943
12053
  let paddingProperty;
11944
12054
  switch (position) {
@@ -11955,11 +12065,10 @@ function useEdgePanel(initialProps) {
11955
12065
  paddingProperty = `padding${position.charAt(0).toUpperCase() + position.slice(1)}`;
11956
12066
  }
11957
12067
  document.body.style[paddingProperty] = "", document.body.classList.remove("is-pushed");
11958
- }), [ defaultProps.mode, defaultProps.position ]), openPanel = useCallback(((useFadeAnimation = !1) => {
12068
+ }), [ mode, position ]), openPanel = useCallback(((useFadeAnimation = !1) => {
11959
12069
  if (setIsOpen(!0), document.body.classList.add("is-edgepanel-open"), containerRef.current) {
11960
- const {mode: mode} = defaultProps;
11961
12070
  // Only add animation if not in 'none' mode
11962
- if ("none" !== mode) if (useFadeAnimation) {
12071
+ if ("none" !== mode) if (useFadeAnimation) {
11963
12072
  // Add fade animation class
11964
12073
  containerRef.current.classList.add("is-fade-animating"), containerRef.current.offsetHeight;
11965
12074
  // Remove animation class after animation completes
@@ -11979,14 +12088,13 @@ function useEdgePanel(initialProps) {
11979
12088
  // Set transform or opacity based on animation type
11980
12089
  useFadeAnimation ? (containerRef.current.style.opacity = "1", containerRef.current.style.transform = "") : containerRef.current.style.transform = "translate(0)",
11981
12090
  // If push mode, adjust body padding
11982
- "push" === defaultProps.mode && adjustBodyPadding();
12091
+ "push" === mode && adjustBodyPadding();
11983
12092
  }
11984
- defaultProps.onOpenChange && defaultProps.onOpenChange(!0);
11985
- }), [ defaultProps, adjustBodyPadding ]), closePanel = useCallback(((useFadeAnimation = !1) => {
12093
+ onOpenChange && onOpenChange(!0);
12094
+ }), [ mode, adjustBodyPadding, onOpenChange ]), closePanel = useCallback(((useFadeAnimation = !1) => {
11986
12095
  if (containerRef.current) {
11987
- const {position: position, mode: mode} = defaultProps;
11988
12096
  // Only add animation if not in 'none' mode
11989
- if ("none" !== mode) if (useFadeAnimation) {
12097
+ if ("none" !== mode) if (useFadeAnimation) {
11990
12098
  // Add fade out animation class
11991
12099
  containerRef.current.classList.add("is-fade-animating-out");
11992
12100
  // Capture container for setTimeout
@@ -12008,46 +12116,42 @@ function useEdgePanel(initialProps) {
12008
12116
  // Then set transform
12009
12117
  containerRef.current.style.transform = position ? EDGE_PANEL.TRANSFORM_VALUES[position] : "",
12010
12118
  // Reset body padding if push mode
12011
- "push" === defaultProps.mode && resetBodyPadding(), setTimeout((() => {
12012
- setIsOpen(!1), document.body.classList.remove("is-edgepanel-open"), defaultProps.onOpenChange && defaultProps.onOpenChange(!1);
12119
+ "push" === mode && resetBodyPadding(), setTimeout((() => {
12120
+ setIsOpen(!1), document.body.classList.remove("is-edgepanel-open"), onOpenChange && onOpenChange(!1);
12013
12121
  }), "none" === mode ? 0 : EDGE_PANEL.ANIMATION_DURATION);
12014
- } else setIsOpen(!1), document.body.classList.remove("is-edgepanel-open"), defaultProps.onOpenChange && defaultProps.onOpenChange(!1);
12015
- }), [ defaultProps, resetBodyPadding ]), handleEscapeKey = useCallback((event => {
12016
- defaultProps.closeOnEscape && "Escape" === event.key && isOpen && closePanel();
12017
- }), [ closePanel, defaultProps.closeOnEscape, isOpen ]), handleBackdropClick = useCallback((event => {
12018
- defaultProps.closeOnBackdropClick && event.target === event.currentTarget && closePanel();
12019
- }), [ closePanel, defaultProps.closeOnBackdropClick ]);
12122
+ } else setIsOpen(!1), document.body.classList.remove("is-edgepanel-open"), onOpenChange && onOpenChange(!1);
12123
+ }), [ mode, position, onOpenChange, resetBodyPadding ]), handleEscapeKey = useCallback((event => {
12124
+ closeOnEscape && "Escape" === event.key && isOpen && closePanel();
12125
+ }), [ closePanel, closeOnEscape, isOpen ]), handleBackdropClick = useCallback((event => {
12126
+ closeOnBackdropClick && event.target === event.currentTarget && closePanel();
12127
+ }), [ closePanel, closeOnBackdropClick ]);
12020
12128
  /**
12021
12129
  * Set up event listeners for keyboard events
12022
12130
  */
12023
- return useEffect((() => (isOpen && defaultProps.closeOnEscape && document.addEventListener("keydown", handleEscapeKey),
12131
+ return useEffect((() => (isOpen && closeOnEscape && document.addEventListener("keydown", handleEscapeKey),
12024
12132
  () => {
12025
12133
  document.removeEventListener("keydown", handleEscapeKey);
12026
- })), [ isOpen, handleEscapeKey, defaultProps.closeOnEscape ]),
12134
+ })), [ isOpen, handleEscapeKey, closeOnEscape ]),
12027
12135
  /**
12028
12136
  * Set initial transform values
12029
12137
  */
12030
12138
  useEffect((() => {
12031
- if (containerRef.current) {
12032
- const {position: position, mode: mode} = defaultProps;
12033
- isOpen || "slide" !== mode && "push" !== mode || !position || (containerRef.current.style.transform = EDGE_PANEL.TRANSFORM_VALUES[position],
12034
- // Set initial opacity for fade animations
12035
- defaultProps.glass && (containerRef.current.style.opacity = "0"));
12036
- }
12037
- }), [ defaultProps.mode, defaultProps.position, defaultProps.glass, isOpen ]),
12139
+ containerRef.current && (isOpen || "slide" !== mode && "push" !== mode || !position || (containerRef.current.style.transform = EDGE_PANEL.TRANSFORM_VALUES[position],
12140
+ // Set initial opacity for fade animations
12141
+ glass && (containerRef.current.style.opacity = "0")));
12142
+ }), [ mode, position, glass, isOpen ]),
12038
12143
  /**
12039
12144
  * Sync with prop changes
12040
12145
  */
12041
12146
  useEffect((() => {
12042
- void 0 !== defaultProps.isOpen && defaultProps.isOpen !== isOpen && (defaultProps.isOpen ? openPanel(!!defaultProps.glass) : closePanel(!!defaultProps.glass));
12043
- }), [ defaultProps.isOpen, closePanel, isOpen, openPanel, defaultProps.glass ]),
12044
- {
12147
+ void 0 !== propIsOpen && propIsOpen !== isOpen && (propIsOpen ? openPanel(!!glass) : closePanel(!!glass));
12148
+ }), [ propIsOpen, closePanel, isOpen, openPanel, glass ]), {
12045
12149
  isOpen: isOpen,
12046
12150
  containerRef: containerRef,
12047
12151
  backdropRef: backdropRef,
12048
12152
  generateEdgePanelClass: props => {
12049
- const {position: position = defaultProps.position, className: className = "", isOpen: propIsOpen} = props, baseClass = EDGE_PANEL.CLASSES.BASE;
12050
- return `${baseClass} ${position ? `${baseClass}--${position}` : ""} ${propIsOpen ?? isOpen ? EDGE_PANEL.CLASSES.IS_OPEN : ""} ${className}`.trim();
12153
+ const {position: propPosition = position, className: propClassName = className, isOpen: argIsOpen} = props, baseClass = EDGE_PANEL.CLASSES.BASE;
12154
+ return `${baseClass} ${propPosition ? `${baseClass}--${propPosition}` : ""} ${argIsOpen ?? isOpen ? EDGE_PANEL.CLASSES.IS_OPEN : ""} ${propClassName}`.trim();
12051
12155
  },
12052
12156
  openPanel: openPanel,
12053
12157
  closePanel: closePanel,
@@ -12429,7 +12533,7 @@ function useHero(initialProps) {
12429
12533
  * @returns Slider state and methods
12430
12534
  */
12431
12535
  function(config) {
12432
- const {slides: slides, autoplay: autoplay, loop: loop = !0, transition: transition = "fade", transitionDuration: transitionDuration = 1e3} = config, [currentIndex, setCurrentIndex] = useState(0), [isTransitioning, setIsTransitioning] = useState(!1), autoplayRef = useRef(null), isPausedRef = useRef(!1), callbackRef = useRef(), slideRefs = useMemo((() => slides.map((() => React.createRef()))), [ slides.length ]), videoRefs = useMemo((() => slides.map((() => React.createRef()))), [ slides.length ]), handleSlideTransition = useCallback((nextIndex => {
12536
+ const {slides: slides, autoplay: autoplay, loop: loop = !0, transition: transition = "fade", transitionDuration: transitionDuration = 1e3} = config, [currentIndex, setCurrentIndex] = useState(0), [isTransitioning, setIsTransitioning] = useState(!1), autoplayRef = useRef(null), isPausedRef = useRef(!1), callbackRef = useRef(void 0), slideRefs = useMemo((() => slides.map((() => React.createRef()))), [ slides ]), videoRefs = useMemo((() => slides.map((() => React.createRef()))), [ slides ]), handleSlideTransition = useCallback((nextIndex => {
12433
12537
  if (nextIndex === currentIndex || isTransitioning) return;
12434
12538
  if (nextIndex < 0 || nextIndex >= slides.length) return;
12435
12539
  setIsTransitioning(!0),
@@ -12748,22 +12852,15 @@ function useHero(initialProps) {
12748
12852
  * @param initialProps - Initial side menu properties
12749
12853
  * @returns SideMenu state and methods
12750
12854
  */ function useSideMenu(initialProps) {
12751
- // Default side menu properties
12752
- const defaultProps = {
12753
- collapsible: !0,
12754
- collapsibleDesktop: !1,
12755
- defaultCollapsedDesktop: !1,
12756
- isOpen: !1,
12757
- ...initialProps
12758
- }, [isOpenState, setIsOpenState] = useState(void 0 !== defaultProps.defaultCollapsedDesktop ? !defaultProps.defaultCollapsedDesktop : defaultProps.isOpen || !1), wrapperRef = useRef(null), innerRef = useRef(null), sideMenuRef = useRef(null);
12855
+ const {collapsible: collapsible = !0, collapsibleDesktop: collapsibleDesktop = !1, defaultCollapsedDesktop: defaultCollapsedDesktop = !1, isOpen: isOpen, onToggle: onToggle, disabled: disabled = !1} = initialProps || {}, [isOpenState, setIsOpenState] = useState(void 0 !== defaultCollapsedDesktop ? !defaultCollapsedDesktop : isOpen || !1), wrapperRef = useRef(null), innerRef = useRef(null), sideMenuRef = useRef(null);
12759
12856
  // Local open state for when not controlled externally
12760
12857
  // Update local state when external state changes
12761
12858
  useEffect((() => {
12762
- void 0 !== defaultProps.isOpen ? setIsOpenState(defaultProps.isOpen) : void 0 !== defaultProps.defaultCollapsedDesktop && setIsOpenState(!defaultProps.defaultCollapsedDesktop);
12763
- }), [ defaultProps.isOpen, defaultProps.defaultCollapsedDesktop ]),
12859
+ void 0 !== isOpen ? setIsOpenState(isOpen) : void 0 !== defaultCollapsedDesktop && setIsOpenState(!defaultCollapsedDesktop);
12860
+ }), [ isOpen, defaultCollapsedDesktop ]),
12764
12861
  // Set initial height on mount
12765
12862
  useEffect((() => {
12766
- const shouldCollapse = window.innerWidth < 768 ? defaultProps.collapsible : defaultProps.collapsibleDesktop, currentOpen = void 0 !== defaultProps.isOpen ? defaultProps.isOpen : isOpenState;
12863
+ const shouldCollapse = window.innerWidth < 768 ? collapsible : collapsibleDesktop, currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
12767
12864
  if (shouldCollapse && wrapperRef.current && innerRef.current) {
12768
12865
  // Use setTimeout to ensure DOM is fully rendered
12769
12866
  const timeoutId = setTimeout((() => {
@@ -12772,14 +12869,14 @@ function useHero(initialProps) {
12772
12869
  return () => clearTimeout(timeoutId);
12773
12870
  }
12774
12871
  !shouldCollapse && wrapperRef.current && (wrapperRef.current.style.height = "auto");
12775
- }), []), // Only run on mount
12872
+ }), [ collapsible, collapsibleDesktop, isOpen, isOpenState ]),
12776
12873
  // Handle responsive behavior - vertical collapse for both mobile and desktop
12777
12874
  useEffect((() => {
12778
12875
  const handleResize = () => {
12779
- if (window.innerWidth < 768 ? defaultProps.collapsible : defaultProps.collapsibleDesktop) {
12876
+ if (window.innerWidth < 768 ? collapsible : collapsibleDesktop) {
12780
12877
  if (wrapperRef.current && innerRef.current) {
12781
12878
  // Set proper height for vertical animation (both mobile and desktop)
12782
- const currentOpen = void 0 !== defaultProps.isOpen ? defaultProps.isOpen : isOpenState;
12879
+ const currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
12783
12880
  // Use requestAnimationFrame to ensure DOM is ready
12784
12881
  requestAnimationFrame((() => {
12785
12882
  wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
@@ -12793,12 +12890,12 @@ function useHero(initialProps) {
12793
12890
  return window.addEventListener("resize", handleResize), () => {
12794
12891
  clearTimeout(timeoutId), window.removeEventListener("resize", handleResize);
12795
12892
  };
12796
- }), [ defaultProps.collapsible, defaultProps.collapsibleDesktop, defaultProps.isOpen, defaultProps.onToggle, isOpenState ]),
12893
+ }), [ collapsible, collapsibleDesktop, isOpen, onToggle, isOpenState ]),
12797
12894
  // Update wrapper height when open state changes (both mobile and desktop)
12798
12895
  useEffect((() => {
12799
- const shouldCollapse = window.innerWidth < 768 ? defaultProps.collapsible : defaultProps.collapsibleDesktop;
12896
+ const shouldCollapse = window.innerWidth < 768 ? collapsible : collapsibleDesktop;
12800
12897
  if (shouldCollapse && wrapperRef.current && innerRef.current) {
12801
- const currentOpen = void 0 !== defaultProps.isOpen ? defaultProps.isOpen : isOpenState;
12898
+ const currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
12802
12899
  // Use requestAnimationFrame to ensure DOM is ready
12803
12900
  requestAnimationFrame((() => {
12804
12901
  wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
@@ -12806,26 +12903,25 @@ function useHero(initialProps) {
12806
12903
  } else !shouldCollapse && wrapperRef.current && (
12807
12904
  // Not collapsible - always show content
12808
12905
  wrapperRef.current.style.height = "auto");
12809
- }), [ defaultProps.isOpen, isOpenState, defaultProps.collapsible, defaultProps.collapsibleDesktop ]);
12906
+ }), [ isOpen, isOpenState, collapsible, collapsibleDesktop ]);
12810
12907
  /**
12811
12908
  * Generate side menu class based on properties
12812
12909
  * @param props - Side menu properties
12813
12910
  * @returns Class string
12814
12911
  */
12815
12912
  const handleToggle = () => {
12816
- if (defaultProps.disabled) return;
12817
- const newState = void 0 !== defaultProps.isOpen ? !defaultProps.isOpen : !isOpenState;
12818
- "function" == typeof defaultProps.onToggle ?
12913
+ if (disabled) return;
12914
+ const newState = void 0 !== isOpen ? !isOpen : !isOpenState;
12915
+ "function" == typeof onToggle ?
12819
12916
  // Controlled component
12820
- defaultProps.onToggle(newState) :
12917
+ onToggle(newState) :
12821
12918
  // Uncontrolled component
12822
12919
  setIsOpenState(newState);
12823
- }, getCurrentOpenState = () => void 0 !== defaultProps.isOpen ? defaultProps.isOpen : isOpenState;
12920
+ }, getCurrentOpenState = () => void 0 !== isOpen ? isOpen : isOpenState;
12824
12921
  /**
12825
12922
  * Generate wrapper class
12826
12923
  * @returns Class string
12827
12924
  */ return {
12828
- defaultProps: defaultProps,
12829
12925
  isOpenState: getCurrentOpenState(),
12830
12926
  wrapperRef: wrapperRef,
12831
12927
  innerRef: innerRef,
@@ -13410,21 +13506,21 @@ function useTodo(initialProps) {
13410
13506
  const [interaction, setInteraction] = useState({
13411
13507
  hoveredIndex: null,
13412
13508
  selectedIndex: null
13413
- });
13509
+ }), handlePointHover = useCallback((index => {
13510
+ setInteraction((prev => ({
13511
+ ...prev,
13512
+ hoveredIndex: index
13513
+ })));
13514
+ }), []), handlePointClick = useCallback((index => {
13515
+ setInteraction((prev => ({
13516
+ ...prev,
13517
+ selectedIndex: prev.selectedIndex === index ? null : index
13518
+ })));
13519
+ }), []);
13414
13520
  return {
13415
13521
  interaction: interaction,
13416
- handlePointHover: useCallback((index => {
13417
- setInteraction((prev => ({
13418
- ...prev,
13419
- hoveredIndex: index
13420
- })));
13421
- }), []),
13422
- handlePointClick: useCallback((index => {
13423
- setInteraction((prev => ({
13424
- ...prev,
13425
- selectedIndex: prev.selectedIndex === index ? null : index
13426
- })));
13427
- }), []),
13522
+ handlePointHover: handlePointHover,
13523
+ handlePointClick: handlePointClick,
13428
13524
  clearInteraction: useCallback((() => {
13429
13525
  setInteraction({
13430
13526
  hoveredIndex: null,
@@ -13467,7 +13563,7 @@ const composablesImport = Object.freeze( Object.defineProperty({
13467
13563
  useNavDropdown: useNavDropdown,
13468
13564
  useNavItem: useNavItem,
13469
13565
  useNavbar: useNavbar,
13470
- usePerformanceMonitor: usePerformanceMonitor,
13566
+ usePerformanceMonitor: usePerformanceMonitor$1,
13471
13567
  usePieChart: usePieChart,
13472
13568
  useRadio: useRadio,
13473
13569
  useResponsiveGlass: useResponsiveGlass,
@@ -13530,7 +13626,7 @@ SelectOption.displayName = "SelectOption";
13530
13626
  /**
13531
13627
  * Select - A component for dropdown selection
13532
13628
  */
13533
- const Select = 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, children: children}) => {
13629
+ const SelectComponentBase = ({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, children: children}) => {
13534
13630
  const {generateSelectClass: generateSelectClass} = useSelect({
13535
13631
  size: size,
13536
13632
  disabled: disabled,
@@ -13721,7 +13817,7 @@ const Select = memo((({options: options, value: value, onChange: onChange, onBl
13721
13817
  });
13722
13818
  }
13723
13819
  return selectContent;
13724
- }));
13820
+ }, Select = memo(SelectComponentBase);
13725
13821
 
13726
13822
  Select.displayName = "Select", Select.Option = SelectOption;
13727
13823
 
@@ -14288,7 +14384,7 @@ Footer.displayName = "Footer";
14288
14384
  */
14289
14385
  const MasonryGrid = forwardRef((({children: children, className: className = "", xs: xs = 1, sm: sm, md: md, lg: lg, xl: xl, xxl: xxl, gap: gap = 16, animate: animate = !0, imagesLoaded: imagesLoaded = !0, onLayoutComplete: onLayoutComplete, onImageLoad: onImageLoad, ...props}, ref) => {
14290
14386
  // === REFS & STATE ===
14291
- const [columns, setColumns] = useState(xs), [positions, setPositions] = useState([]), [layoutComplete, setLayoutComplete] = useState(!1), [loadingImages, setLoadingImages] = useState(!1), containerRef = useRef(null), columnHeights = useRef([]), imagesLoadedCount = useRef(0), totalImagesCount = useRef(0), imageElements = useRef(new Map);
14387
+ const [columns, setColumns] = useState(xs), [positions, setPositions] = useState([]), [, setLayoutComplete] = useState(!1), [loadingImages, setLoadingImages] = useState(!1), containerRef = useRef(null), columnHeights = useRef([]), imagesLoadedCount = useRef(0), totalImagesCount = useRef(0), imageElements = useRef(new Map);
14292
14388
  useEffect((() => {
14293
14389
  setLoadingImages(!!imagesLoaded);
14294
14390
  }), [ columns, imagesLoaded ]),
@@ -14317,34 +14413,45 @@ const MasonryGrid = forwardRef((({children: children, className: className = ""
14317
14413
  });
14318
14414
  })), setItems(newItems);
14319
14415
  }), [ children ]);
14320
- // === TRACK & MANAGE IMAGES ===
14321
- const handleImageLoad = useCallback((img => {
14322
- if (!imageElements.current.get(img)) {
14323
- // Add loaded class for animation
14324
- if (imageElements.current.set(img, !0), imagesLoadedCount.current += 1, containerRef.current && imagesLoaded) {
14325
- const itemElement = img.closest(".o-masonry-grid > div");
14326
- itemElement && (itemElement.offsetHeight, itemElement.classList.add("o-masonry-grid__item-loaded"),
14327
- itemElement.classList.remove("o-masonry-grid__item-loading"));
14416
+ // === MANAGE ITEM LAYOUT ===
14417
+ const calculateLayout = useCallback((() => {
14418
+ if (!containerRef.current || 0 === items.length) return;
14419
+ const colWidth = (containerRef.current.offsetWidth - gap * (columns - 1)) / columns;
14420
+ columnHeights.current = Array(columns).fill(0);
14421
+ const newPositions = [];
14422
+ items.forEach(((item, index) => {
14423
+ if (item.ref.current) {
14424
+ // Find the shortest column
14425
+ const shortestCol = columnHeights.current.indexOf(Math.min(...columnHeights.current)), left = shortestCol * (colWidth + gap), top = columnHeights.current[shortestCol] ?? 0, height = item.ref.current.offsetHeight;
14426
+ columnHeights.current[shortestCol] = top + height + gap, newPositions[index] = {
14427
+ left: left,
14428
+ top: top,
14429
+ width: colWidth,
14430
+ height: height
14431
+ };
14328
14432
  }
14329
- // Ensure layout is recalculated after DOM paints the item image (prevents overlap on slow/late image loads)
14330
- requestAnimationFrame((() => {
14331
- requestAnimationFrame((() => {
14332
- calculateLayout();
14333
- }));
14334
- })), onImageLoad?.(imagesLoadedCount.current, totalImagesCount.current),
14335
- // If all images have loaded, update loading state and complete layout
14336
- imagesLoadedCount.current >= totalImagesCount.current && totalImagesCount.current > 0 && (setLayoutComplete(!0),
14337
- setLoadingImages(!1), // This ensures the loading class is removed *immediately* after images load
14338
- // Force a double requestAnimationFrame for final layout calculation after all images are loaded (guarantees DOM paint)
14339
- requestAnimationFrame((() => {
14340
- requestAnimationFrame((() => {
14341
- calculateLayout(),
14342
- // As a failsafe, if still present for some render lag, force another setLoadingImages(false)
14343
- setLoadingImages(!1);
14344
- }));
14345
- })), onLayoutComplete?.());
14433
+ })), setPositions(newPositions);
14434
+ }), [ items, columns, gap ]), handleImageLoad = useCallback((img => {
14435
+ if (imageElements.current.get(img)) return;
14436
+ // Add loaded class for animation
14437
+ if (imageElements.current.set(img, !0), imagesLoadedCount.current += 1, containerRef.current && imagesLoaded) {
14438
+ const itemElement = img.closest(".o-masonry-grid > div");
14439
+ itemElement && (itemElement.offsetHeight, itemElement.classList.add("o-masonry-grid__item-loaded"),
14440
+ itemElement.classList.remove("o-masonry-grid__item-loading"));
14346
14441
  }
14347
- }), [ onImageLoad, onLayoutComplete, imagesLoaded ]), trackImages = useCallback((() => {
14442
+ // Schedule layout recalculation after next paint to prevent overlap
14443
+ const scheduleLayoutUpdate = () => {
14444
+ const frameId = requestAnimationFrame((() => {
14445
+ onImageLoad?.(imagesLoadedCount.current, totalImagesCount.current), calculateLayout();
14446
+ }));
14447
+ return () => cancelAnimationFrame(frameId);
14448
+ }, cleanup = scheduleLayoutUpdate();
14449
+ // Clean up previous scheduled updates
14450
+ // If all images have loaded, update loading state and complete layout
14451
+ imagesLoadedCount.current >= totalImagesCount.current && totalImagesCount.current > 0 && (setLayoutComplete(!0),
14452
+ setLoadingImages(!1), setTimeout((() => cleanup()), 0), // Clean up after current execution
14453
+ scheduleLayoutUpdate(), onLayoutComplete?.());
14454
+ }), [ onImageLoad, onLayoutComplete, imagesLoaded, calculateLayout ]), trackImages = useCallback((() => {
14348
14455
  if (!imagesLoaded || !containerRef.current) return;
14349
14456
  imageElements.current.clear(), imagesLoadedCount.current = 0;
14350
14457
  const images = containerRef.current.querySelectorAll("img");
@@ -14363,30 +14470,21 @@ const MasonryGrid = forwardRef((({children: children, className: className = ""
14363
14470
  img.removeEventListener("error", masonryImg._masonryLoadHandler), delete masonryImg._masonryLoadHandler);
14364
14471
  }));
14365
14472
  });
14366
- }), [ imagesLoaded, handleImageLoad, onLayoutComplete ]), calculateLayout = useCallback((() => {
14367
- if (!containerRef.current || 0 === items.length) return;
14368
- const colWidth = (containerRef.current.offsetWidth - gap * (columns - 1)) / columns;
14369
- columnHeights.current = Array(columns).fill(0);
14370
- const newPositions = [];
14371
- items.forEach(((item, index) => {
14372
- if (item.ref.current) {
14373
- // Find the shortest column
14374
- const shortestCol = columnHeights.current.indexOf(Math.min(...columnHeights.current)), left = shortestCol * (colWidth + gap), top = columnHeights.current[shortestCol] ?? 0, height = item.ref.current.offsetHeight;
14375
- columnHeights.current[shortestCol] = top + height + gap, newPositions[index] = {
14376
- left: left,
14377
- top: top,
14378
- width: colWidth,
14379
- height: height
14380
- };
14381
- }
14382
- })), setPositions(newPositions);
14383
- }), [ items, columns, gap ]);
14384
- // === OBSERVE CONTAINER RESIZE ===
14473
+ }), [ imagesLoaded, handleImageLoad, onLayoutComplete ]);
14474
+ // === TRACK & MANAGE IMAGES ===
14475
+ // === OBSERVE CONTAINER RESIZE ===
14385
14476
  useEffect((() => {
14386
14477
  if (!containerRef.current) return;
14387
- let animationFrame = null;
14388
- const observer = new ResizeObserver((() => {
14389
- animationFrame && cancelAnimationFrame(animationFrame), animationFrame = requestAnimationFrame((() => calculateLayout()));
14478
+ let animationFrame = null, lastWidth = 0;
14479
+ const observer = new ResizeObserver((entries => {
14480
+ const entry = entries[0];
14481
+ if (!entry) return;
14482
+ const currentWidth = entry.contentRect.width;
14483
+ // Only recalculate if width actually changed (prevents excessive calculations)
14484
+ Math.abs(currentWidth - lastWidth) > 1 && (animationFrame && cancelAnimationFrame(animationFrame),
14485
+ animationFrame = requestAnimationFrame((() => {
14486
+ calculateLayout(), lastWidth = currentWidth;
14487
+ })));
14390
14488
  }));
14391
14489
  return observer.observe(containerRef.current), () => {
14392
14490
  observer.disconnect(), animationFrame && cancelAnimationFrame(animationFrame);
@@ -14397,24 +14495,21 @@ const MasonryGrid = forwardRef((({children: children, className: className = ""
14397
14495
  setLayoutComplete(!0), void setLoadingImages(!1))
14398
14496
  // Only reset layoutComplete when items or columns change
14399
14497
  ), [ items, columns, calculateLayout, imagesLoaded, trackImages ]),
14400
- // === NEW: Add ResizeObservers to all grid items for bulletproof image+content measurement ===
14498
+ // === ADD RESIZEOBSERVERS TO GRID ITEMS FOR DYNAMIC CONTENT MEASUREMENT ===
14401
14499
  React.useEffect((() => {
14402
- // Clean up old observers if items ever change
14403
14500
  const observers = [];
14501
+ let animationFrame = null;
14502
+ // Debounced layout calculation for item resize events
14503
+ const debouncedCalculateLayout = () => {
14504
+ animationFrame && cancelAnimationFrame(animationFrame), animationFrame = requestAnimationFrame(calculateLayout);
14505
+ };
14404
14506
  return items.forEach((item => {
14405
14507
  if (item.ref.current) {
14406
- const obs = new ResizeObserver((() => {
14407
- // Double rAF: ensures layout only runs after DOM/paint/async renders
14408
- requestAnimationFrame((() => {
14409
- requestAnimationFrame((() => {
14410
- calculateLayout();
14411
- }));
14412
- }));
14413
- }));
14508
+ const obs = new ResizeObserver(debouncedCalculateLayout);
14414
14509
  obs.observe(item.ref.current), observers.push(obs);
14415
14510
  }
14416
14511
  })), () => {
14417
- observers.forEach((obs => obs.disconnect()));
14512
+ observers.forEach((obs => obs.disconnect())), animationFrame && cancelAnimationFrame(animationFrame);
14418
14513
  };
14419
14514
  }), [ items, calculateLayout ]);
14420
14515
  // Ensure loadingImages state resets when items/columns/imagesLoaded change
@@ -15851,12 +15946,12 @@ const SideMenu = forwardRef((({title: title, children: children, menuItems: men
15851
15946
  const index = Number(key);
15852
15947
  index >= currentLength && (delete nestedWrapperRefs.current[index], delete nestedInnerRefs.current[index]);
15853
15948
  })));
15854
- }), [ menuItems?.length ]);
15949
+ }), [ menuItems ]);
15855
15950
  // Helper function to update nested wrapper height
15856
- const updateNestedHeight = (index, isOpen) => {
15951
+ const updateNestedHeight = useCallback(((index, isOpen) => {
15857
15952
  const wrapper = nestedWrapperRefs.current[index], inner = nestedInnerRefs.current[index];
15858
15953
  wrapper && inner && (wrapper.style.height = isOpen ? `${inner.scrollHeight}px` : "0px");
15859
- };
15954
+ }), []);
15860
15955
  // Set initial heights for nested wrappers on mount and when menuItems change
15861
15956
  useEffect((() => {
15862
15957
  if (!menuItems?.length) return;
@@ -15870,7 +15965,7 @@ const SideMenu = forwardRef((({title: title, children: children, menuItems: men
15870
15965
  // Only run when menuItems change, nestedItemStates is read but not in deps to avoid loops
15871
15966
  // eslint-disable-next-line react-hooks/exhaustive-deps
15872
15967
  ;
15873
- }), [ menuItems?.length ]),
15968
+ }), [ menuItems, updateNestedHeight ]),
15874
15969
  // Update nested wrapper heights when state changes
15875
15970
  useEffect((() => {
15876
15971
  if (!menuItems?.length) return;
@@ -15883,7 +15978,7 @@ const SideMenu = forwardRef((({title: title, children: children, menuItems: men
15883
15978
  })), () => {
15884
15979
  frameIds.forEach((id => cancelAnimationFrame(id)));
15885
15980
  };
15886
- }), [ nestedItemStates, menuItems?.length ]);
15981
+ }), [ nestedItemStates, menuItems, updateNestedHeight ]);
15887
15982
  // Combine refs using utility
15888
15983
  const combinedRef = useForkRef(sideMenuRef, ref), sideMenuClass = generateSideMenuClass({
15889
15984
  className: className,
@@ -16770,7 +16865,7 @@ useEffect((() => {
16770
16865
  }
16771
16866
  };
16772
16867
  }));
16773
- }), [ isMounted, currentIndex, calculateBounds, constrainPosition ]), setImagePosition = useCallback((position => {
16868
+ }), [ currentIndex, calculateBounds, constrainPosition ]), setImagePosition = useCallback((position => {
16774
16869
  setImageStates((prev => {
16775
16870
  const currentState = prev[currentIndex] || {
16776
16871
  zoomLevel: 1,
@@ -16820,7 +16915,7 @@ useEffect((() => {
16820
16915
  }
16821
16916
  };
16822
16917
  }));
16823
- }), [ isMounted, currentIndex, calculateBounds, constrainPosition ]), handleWheel = useCallback((event => {
16918
+ }), [ currentIndex, calculateBounds, constrainPosition ]), handleWheel = useCallback((event => {
16824
16919
  var _context;
16825
16920
  if (!isMounted || !event || !event.currentTarget) return;
16826
16921
  // Additional safety check for the target element
@@ -17177,7 +17272,7 @@ useEffect((() => {
17177
17272
  }
17178
17273
  return prev;
17179
17274
  }));
17180
- }), [ isMounted, enableGestures, isDragging, startDragPosition, currentIndex, constrainPosition, calculateBounds ]), handleTouchEnd = useCallback((() => {
17275
+ }), [ enableGestures, isDragging, startDragPosition, currentIndex, constrainPosition, calculateBounds ]), handleTouchEnd = useCallback((() => {
17181
17276
  setIsDragging(!1), lastDistanceRef.current = null, lastMidpointRef.current = null;
17182
17277
  }), []), currentState = imageStates[currentIndex] || {
17183
17278
  zoomLevel: 1,
@@ -17381,9 +17476,9 @@ const PopoverContext = createContext({
17381
17476
  triggerType: "click"
17382
17477
  }), Popover = ({content: content, position: position = "top", trigger: trigger = "click", className: className = "", style: style, delay: delay = 0, offset: offset = 12, defaultOpen: defaultOpen = !1, isOpen: controlledIsOpen, onOpenChange: onOpenChange, closeOnClickOutside: closeOnClickOutside = !0, closeOnEscape: closeOnEscape = !0, id: id, children: children, glass: glass}) => {
17383
17478
  const {isOpen: isOpen, setIsOpen: setIsOpen, triggerRef: triggerRef, popoverRef: popoverRef, arrowRef: arrowRef, popoverId: popoverId, currentPosition: currentPosition, updatePosition: updatePosition} = (({position: position = "top", trigger: trigger = "click", offset: offset = 12, delay: delay = 0, defaultOpen: defaultOpen = !1, isOpen: controlledIsOpen, onOpenChange: onOpenChange, closeOnClickOutside: closeOnClickOutside = !0, closeOnEscape: closeOnEscape = !0, id: id}) => {
17384
- const [isOpen, setIsOpenState] = useState(defaultOpen), [currentPosition, setCurrentPosition] = useState("auto" === position ? "top" : position), triggerRef = useRef(null), popoverRef = useRef(null), arrowRef = useRef(null), timeoutRef = useRef(null), popoverId = id || `popover-${Math.random().toString(36).slice(2, 11)}`, isControlled = void 0 !== controlledIsOpen, isOpenState = isControlled ? controlledIsOpen : isOpen, setIsOpen = newIsOpen => {
17479
+ const [isOpen, setIsOpenState] = useState(defaultOpen), [currentPosition, setCurrentPosition] = useState("auto" === position ? "top" : position), triggerRef = useRef(null), popoverRef = useRef(null), arrowRef = useRef(null), timeoutRef = useRef(null), popoverId = id || `popover-${Math.random().toString(36).slice(2, 11)}`, isControlled = void 0 !== controlledIsOpen, isOpenState = isControlled ? controlledIsOpen : isOpen, setIsOpen = useCallback((newIsOpen => {
17385
17480
  isControlled || setIsOpenState(newIsOpen), onOpenChange && onOpenChange(newIsOpen);
17386
- };
17481
+ }), [ isControlled, onOpenChange ]);
17387
17482
  // Handle hover events if trigger is hover
17388
17483
  useEffect((() => {
17389
17484
  if ("hover" !== trigger || !triggerRef.current || !popoverRef.current) return;
@@ -17403,17 +17498,16 @@ const PopoverContext = createContext({
17403
17498
  setIsOpen(!1);
17404
17499
  };
17405
17500
  // Add hover event listeners
17406
- return triggerRef.current.addEventListener("mouseenter", handleTriggerMouseEnter),
17407
- triggerRef.current.addEventListener("mouseleave", handleTriggerMouseLeave), popoverRef.current.addEventListener("mouseenter", handlePopoverMouseEnter),
17408
- popoverRef.current.addEventListener("mouseleave", handlePopoverMouseLeave), () => {
17409
- triggerRef.current && (triggerRef.current.removeEventListener("mouseenter", handleTriggerMouseEnter),
17410
- triggerRef.current.removeEventListener("mouseleave", handleTriggerMouseLeave)),
17411
- popoverRef.current && (popoverRef.current.removeEventListener("mouseenter", handlePopoverMouseEnter),
17412
- popoverRef.current.removeEventListener("mouseleave", handlePopoverMouseLeave)),
17413
- null !== timeoutRef.current && window.clearTimeout(timeoutRef.current);
17501
+ triggerRef.current.addEventListener("mouseenter", handleTriggerMouseEnter), triggerRef.current.addEventListener("mouseleave", handleTriggerMouseLeave),
17502
+ popoverRef.current.addEventListener("mouseenter", handlePopoverMouseEnter), popoverRef.current.addEventListener("mouseleave", handlePopoverMouseLeave);
17503
+ const currentTrigger = triggerRef.current, currentPopover = popoverRef.current;
17504
+ return () => {
17505
+ currentTrigger && (currentTrigger.removeEventListener("mouseenter", handleTriggerMouseEnter),
17506
+ currentTrigger.removeEventListener("mouseleave", handleTriggerMouseLeave)), currentPopover && (currentPopover.removeEventListener("mouseenter", handlePopoverMouseEnter),
17507
+ currentPopover.removeEventListener("mouseleave", handlePopoverMouseLeave)), null !== timeoutRef.current && window.clearTimeout(timeoutRef.current);
17414
17508
  };
17415
- }), [ trigger, delay, isOpenState ]);
17416
- const updatePosition = event => {
17509
+ }), [ trigger, delay, isOpenState, setIsOpen ]);
17510
+ const updatePosition = useCallback((event => {
17417
17511
  if (!triggerRef.current || !popoverRef.current) return;
17418
17512
  const triggerRect = triggerRef.current.getBoundingClientRect(), popoverRect = popoverRef.current.getBoundingClientRect(), viewportWidth = window.innerWidth, viewportHeight = window.innerHeight, isNearViewportEdge = triggerRect.top < 50 || triggerRect.bottom > viewportHeight - 50 || triggerRect.left < 50 || triggerRect.right > viewportWidth - 50;
17419
17513
  // If this is a scroll update and trigger isn't near edges, skip repositioning
@@ -17474,9 +17568,9 @@ const PopoverContext = createContext({
17474
17568
  // Add scroll position to convert viewport coordinates to absolute position
17475
17569
  const absoluteTop = top + window.scrollY, absoluteLeft = left + window.scrollX;
17476
17570
  // Apply position using absolute positioning to follow when scrolling
17477
- popoverRef.current.style.position = "absolute", popoverRef.current.style.top = `${absoluteTop}px`,
17478
- popoverRef.current.style.left = `${absoluteLeft}px`;
17479
- };
17571
+ popoverRef.current && (popoverRef.current.style.position = "absolute", popoverRef.current.style.top = `${absoluteTop}px`,
17572
+ popoverRef.current.style.left = `${absoluteLeft}px`);
17573
+ }), [ position, offset ]);
17480
17574
  // Position the popover
17481
17575
  return useEffect((() => {
17482
17576
  if (!isOpenState || !triggerRef.current || !popoverRef.current) return;
@@ -17502,7 +17596,7 @@ const PopoverContext = createContext({
17502
17596
  window.removeEventListener("resize", updatePosition), window.removeEventListener("scroll", handleScroll),
17503
17597
  scrollTimeout && clearTimeout(scrollTimeout), clearInterval(intervalId);
17504
17598
  };
17505
- }), [ isOpenState, position, offset ]),
17599
+ }), [ isOpenState, updatePosition ]),
17506
17600
  // Handle click outside to close popover
17507
17601
  useEffect((() => {
17508
17602
  if (!isOpenState || !closeOnClickOutside) return;
@@ -17512,7 +17606,7 @@ const PopoverContext = createContext({
17512
17606
  return document.addEventListener("mousedown", handleClickOutside), () => {
17513
17607
  document.removeEventListener("mousedown", handleClickOutside);
17514
17608
  };
17515
- }), [ isOpenState, closeOnClickOutside ]),
17609
+ }), [ isOpenState, closeOnClickOutside, setIsOpen ]),
17516
17610
  // Handle escape key to close popover
17517
17611
  useEffect((() => {
17518
17612
  if (!isOpenState || !closeOnEscape) return;
@@ -17522,7 +17616,7 @@ const PopoverContext = createContext({
17522
17616
  return document.addEventListener("keydown", handleEscapeKey), () => {
17523
17617
  document.removeEventListener("keydown", handleEscapeKey);
17524
17618
  };
17525
- }), [ isOpenState, closeOnEscape ]),
17619
+ }), [ isOpenState, closeOnEscape, setIsOpen ]),
17526
17620
  // Clean up on unmount
17527
17621
  useEffect((() => () => {
17528
17622
  null !== timeoutRef.current && window.clearTimeout(timeoutRef.current);
@@ -17703,10 +17797,11 @@ const calculateStarValue = (e, starValue, allowHalf) => {
17703
17797
  }), [ readOnly, onChange, allowHalf ]);
17704
17798
  // Use vanilla JS implementation if specified
17705
17799
  useEffect((() => {
17706
- if (useVanillaJS && "undefined" != typeof window && internalRef.current)
17800
+ if (!useVanillaJS || "undefined" == typeof window || !internalRef.current) return;
17801
+ const currentInstance = ratingInstance.current;
17707
17802
  // Cleanup on unmount
17708
- return () => {
17709
- ratingInstance.current && ratingInstance.current.destroy();
17803
+ return () => {
17804
+ currentInstance && currentInstance.destroy();
17710
17805
  };
17711
17806
  }), [ useVanillaJS, valueProp, defaultValue, maxValue, allowHalf, readOnly, size, variant, onChange ]),
17712
17807
  // Update vanilla JS implementation when props change
@@ -17827,10 +17922,11 @@ const ProductReview = ({productName: productName, productImage: productImage, in
17827
17922
  const [rating, setRating] = useState(initialRating), [comment, setComment] = useState(""), [submitted, setSubmitted] = useState(!1), reviewRef = useRef(null), reviewInstance = useRef(null);
17828
17923
  useEffect((() => {
17829
17924
  // Only run on client-side
17830
- if ("undefined" != typeof window && reviewRef.current)
17925
+ if ("undefined" == typeof window || !reviewRef.current) return;
17926
+ const currentInstance = reviewInstance.current;
17831
17927
  // Cleanup on unmount
17832
- return () => {
17833
- reviewInstance.current && reviewInstance.current.destroy();
17928
+ return () => {
17929
+ currentInstance && currentInstance.destroy();
17834
17930
  };
17835
17931
  }), [ productName, productImage, initialRating, maxRating, allowHalf, ratingColor, onSubmit ]);
17836
17932
  const handleSubmit = e => {
@@ -18075,10 +18171,11 @@ const SectionIntro = ({title: title, label: label, text: text, actions: actions,
18075
18171
  const sectionIntroRef = useRef(null), sectionIntroInstance = useRef(null);
18076
18172
  useEffect((() => {
18077
18173
  // Only run on client-side
18078
- if ("undefined" != typeof window && sectionIntroRef.current)
18174
+ if ("undefined" == typeof window || !sectionIntroRef.current) return;
18175
+ const currentInstance = sectionIntroInstance.current;
18079
18176
  // Cleanup on unmount
18080
- return () => {
18081
- sectionIntroInstance.current && sectionIntroInstance.current.destroy();
18177
+ return () => {
18178
+ currentInstance && currentInstance.destroy();
18082
18179
  };
18083
18180
  }), [ alignment, backgroundImageSrc, showOverlay, size, skeleton ]);
18084
18181
  // Determine CSS classes
@@ -18162,7 +18259,7 @@ SectionIntro.displayName = "SectionIntro";
18162
18259
 
18163
18260
  const Slider = forwardRef(((props, ref) => {
18164
18261
  const {slides: slides = [], height: height = 300, width: width = "100%", slidesToShow: slidesToShow = 1, spaceBetween: spaceBetween = 0, loop: loop = !1, initialSlide: initialSlide = 0, direction: direction = "horizontal", speed: speed = 300, allowTouchMove: allowTouchMove = !0, threshold: threshold = 50, grabCursor: grabCursor = !0, autoplay: autoplay, navigation: navigation, pagination: pagination, className: className, style: style, onSlideChange: onSlideChange, ...rest} = props, validSlides = Array.isArray(slides) ? slides : [], slider = function(options) {
18165
- const {slides: rawSlides, slidesToShow: slidesToShow = 1, spaceBetween: spaceBetween = 0, loop: loop = !1, initialSlide: initialSlide = 0, direction: direction = "horizontal", speed: speed = 300, allowTouchMove: allowTouchMove = !0, threshold: threshold = 50, autoplay: autoplay, onSlideChange: onSlideChange} = options, slides = Array.isArray(rawSlides) ? rawSlides : [], containerRef = useRef(null), wrapperRef = useRef(null), repositioningRef = useRef(!1), autoplayRef = useRef(null), [autoplayRunning, setAutoplayRunning] = useState(!1), sliderStateRef = useRef({
18262
+ const {slides: rawSlides, slidesToShow: slidesToShow = 1, spaceBetween: spaceBetween = 0, loop: loop = !1, initialSlide: initialSlide = 0, direction: direction = "horizontal", speed: speed = 300, allowTouchMove: allowTouchMove = !0, threshold: threshold = 50, autoplay: autoplay, onSlideChange: onSlideChange} = options, slides = useMemo((() => Array.isArray(rawSlides) ? rawSlides : []), [ rawSlides ]), containerRef = useRef(null), wrapperRef = useRef(null), repositioningRef = useRef(!1), autoplayRef = useRef(null), [autoplayRunning, setAutoplayRunning] = useState(!1), sliderStateRef = useRef({
18166
18263
  isTransitioning: !1,
18167
18264
  loop: loop,
18168
18265
  slides: slides,
@@ -18297,7 +18394,7 @@ const Slider = forwardRef(((props, ref) => {
18297
18394
  setIsTransitioning(!1), onSlideChange?.(nextIndex);
18298
18395
  }), speed);
18299
18396
  }
18300
- }), [ realIndex, internalIndex, slides.length, slidesToShow, loop, isTransitioning, speed, onSlideChange, allSlides.length, loopedSlides, autoplay ]), slidePrev = useCallback((() => {
18397
+ }), [ realIndex, internalIndex, slides.length, slidesToShow, loop, isTransitioning, speed, onSlideChange, autoplay ]), slidePrev = useCallback((() => {
18301
18398
  if (!isTransitioning) if (
18302
18399
  // Stop autoplay on interaction if disableOnInteraction is true
18303
18400
  autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
@@ -18319,7 +18416,7 @@ const Slider = forwardRef(((props, ref) => {
18319
18416
  setIsTransitioning(!1), onSlideChange?.(prevIndex);
18320
18417
  }), speed);
18321
18418
  }
18322
- }), [ realIndex, internalIndex, slides.length, loop, isTransitioning, speed, onSlideChange, allSlides.length, loopedSlides, autoplay ]), goToSlide = useCallback((index => {
18419
+ }), [ realIndex, internalIndex, slides.length, loop, isTransitioning, speed, onSlideChange, autoplay ]), goToSlide = useCallback((index => {
18323
18420
  isTransitioning || index === realIndex || (
18324
18421
  // Stop autoplay on interaction if disableOnInteraction is true
18325
18422
  autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
@@ -18327,7 +18424,7 @@ const Slider = forwardRef(((props, ref) => {
18327
18424
  setRealIndex(index), setInternalIndex(loop ? slides.length + index : index), setTimeout((() => {
18328
18425
  setIsTransitioning(!1), onSlideChange?.(index);
18329
18426
  }), speed));
18330
- }), [ realIndex, isTransitioning, speed, onSlideChange, loop, loopedSlides, autoplay ]), handleTouchStart = useCallback((e => {
18427
+ }), [ realIndex, isTransitioning, speed, onSlideChange, loop, slides.length, autoplay ]), handleTouchStart = useCallback((e => {
18331
18428
  if (!allowTouchMove) return;
18332
18429
  // Stop autoplay on interaction if disableOnInteraction is true
18333
18430
  autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
@@ -18582,7 +18679,7 @@ const Steps = ({items: items, activeIndex: activeIndex = 0, vertical: vertical =
18582
18679
  let content;
18583
18680
  useEffect((() => {
18584
18681
  currentStep !== activeIndex && setCurrentStep(activeIndex);
18585
- }), [ activeIndex ]),
18682
+ }), [ activeIndex, currentStep ]),
18586
18683
  // Legacy rendering
18587
18684
  content = items && items.length > 0 ? items.map(((item, index) => jsx(StepsItem, {
18588
18685
  index: index,
@@ -18726,7 +18823,7 @@ const TabsPanel = forwardRef((({children: children, className: className = "",
18726
18823
 
18727
18824
  TabsPanel.displayName = "TabsPanel";
18728
18825
 
18729
- const Tabs = memo((({items: items, activeIndex: activeIndex = TAB.DEFAULTS.ACTIVE_INDEX, onTabChange: onTabChange, className: className = "", style: style, glass: glass, children: children}) => {
18826
+ const TabsComponentBase = ({items: items, activeIndex: activeIndex = TAB.DEFAULTS.ACTIVE_INDEX, onTabChange: onTabChange, className: className = "", style: style, glass: glass, children: children}) => {
18730
18827
  const [currentTab, setCurrentTab] = useState(activeIndex), handleTabClick = index => {
18731
18828
  setCurrentTab(index), onTabChange && onTabChange(index);
18732
18829
  }, handleKeyDown = (event, totalTabs) => {
@@ -18842,7 +18939,7 @@ const Tabs = memo((({items: items, activeIndex: activeIndex = TAB.DEFAULTS.ACTI
18842
18939
  });
18843
18940
  }
18844
18941
  return wrapper;
18845
- }));
18942
+ }, Tabs = memo(TabsComponentBase);
18846
18943
 
18847
18944
  Tabs.displayName = "Tabs", Tabs.List = TabsList, Tabs.Trigger = TabsTrigger, Tabs.Panels = TabsPanels,
18848
18945
  Tabs.Panel = TabsPanel;
@@ -18854,10 +18951,11 @@ const Testimonial = ({quote: quote, author: author, size: size = "", skeleton: s
18854
18951
  const testimonialRef = useRef(null), testimonialInstance = useRef(null);
18855
18952
  useEffect((() => {
18856
18953
  // Only run on client-side
18857
- if ("undefined" != typeof window && testimonialRef.current)
18954
+ if ("undefined" == typeof window || !testimonialRef.current) return;
18955
+ const currentInstance = testimonialInstance.current;
18858
18956
  // Cleanup on unmount
18859
- return () => {
18860
- testimonialInstance.current && testimonialInstance.current.destroy();
18957
+ return () => {
18958
+ currentInstance && currentInstance.destroy();
18861
18959
  };
18862
18960
  }), [ size, skeleton ]);
18863
18961
  // Determine CSS classes
@@ -19998,11 +20096,13 @@ const VideoPlayer = forwardRef((({src: src, type: type = "video", youtubeId: yo
19998
20096
  detectBorderRadius();
19999
20097
  // Create ResizeObserver to watch for style changes
20000
20098
  let resizeObserver = null;
20001
- return "undefined" != typeof ResizeObserver && containerRef.current && (resizeObserver = new ResizeObserver(detectBorderRadius),
20099
+ "undefined" != typeof ResizeObserver && containerRef.current && (resizeObserver = new ResizeObserver(detectBorderRadius),
20002
20100
  resizeObserver.observe(containerRef.current)),
20003
20101
  // Also listen for window resize (in case styles change)
20004
- window.addEventListener("resize", detectBorderRadius), () => {
20005
- window.removeEventListener("resize", detectBorderRadius), resizeObserver && containerRef.current && (resizeObserver.unobserve(containerRef.current),
20102
+ window.addEventListener("resize", detectBorderRadius);
20103
+ const currentContainer = containerRef.current;
20104
+ return () => {
20105
+ window.removeEventListener("resize", detectBorderRadius), resizeObserver && currentContainer && (resizeObserver.unobserve(currentContainer),
20006
20106
  resizeObserver.disconnect());
20007
20107
  };
20008
20108
  }), []);
@@ -20757,7 +20857,51 @@ const components = Object.freeze( Object.defineProperty({
20757
20857
  "breakpoint-md": "768px",
20758
20858
  "breakpoint-lg": "992px",
20759
20859
  "breakpoint-xl": "1200px",
20760
- "breakpoint-xxl": "1440px"
20860
+ "breakpoint-xxl": "1440px",
20861
+ // Advanced Features - Interactive Effects (Phase 2)
20862
+ "interactive-vortex-enabled": "false",
20863
+ "interactive-vortex-strength": "0.5",
20864
+ "interactive-vortex-radius": "100",
20865
+ "interactive-vortex-decay": "0.8",
20866
+ "interactive-chromatic-enabled": "false",
20867
+ "interactive-chromatic-mode": "lateral",
20868
+ "interactive-chromatic-red-shift": "0.02",
20869
+ "interactive-chromatic-green-shift": "0",
20870
+ "interactive-chromatic-blue-shift": "-0.02",
20871
+ "interactive-chromatic-edge-only": "false",
20872
+ "interactive-chromatic-edge-threshold": "0.5",
20873
+ "interactive-mouse-sensitivity": "1.0",
20874
+ "interactive-mouse-trail-effect": "false",
20875
+ "interactive-animation-speed-base": "1.0",
20876
+ "interactive-animation-speed-multiplier": "1.0",
20877
+ // Advanced Features - Optimization (Phase 3)
20878
+ "optimization-breakpoint-mobile": "0px",
20879
+ "optimization-breakpoint-tablet": "768px",
20880
+ "optimization-breakpoint-desktop": "1024px",
20881
+ "optimization-breakpoint-wide": "1440px",
20882
+ "optimization-device-scaling-mobile": "0.5",
20883
+ "optimization-device-scaling-tablet": "0.75",
20884
+ "optimization-device-scaling-desktop": "1.0",
20885
+ "optimization-performance-fps-target": "60",
20886
+ "optimization-auto-scaling-enabled": "false",
20887
+ "optimization-auto-scaling-low-end": "0.5",
20888
+ "optimization-auto-scaling-mid-range": "0.75",
20889
+ "optimization-auto-scaling-high-end": "1.0",
20890
+ // Advanced Features - Visual Polish (Phase 4)
20891
+ "visual-polish-border-iridescent-glow": "false",
20892
+ "visual-polish-border-shimmer-effect": "false",
20893
+ "visual-polish-border-beveled-edges": "false",
20894
+ "visual-polish-border-pulsing-glow": "false",
20895
+ "visual-polish-content-aware-blur-enabled": "false",
20896
+ "visual-polish-content-aware-depth-detection": "false",
20897
+ "visual-polish-content-aware-edge-preservation": "false",
20898
+ "visual-polish-content-aware-variable-radius": "false",
20899
+ "visual-polish-holographic-enabled": "false",
20900
+ "visual-polish-holographic-rainbow-diffraction": "false",
20901
+ "visual-polish-holographic-scanline-animation": "false",
20902
+ "visual-polish-holographic-grid-overlay": "false",
20903
+ "visual-polish-holographic-data-stream": "false",
20904
+ "visual-polish-holographic-pulse-rings": "false"
20761
20905
  };
20762
20906
 
20763
20907
  // Export all component types
@@ -20839,202 +20983,644 @@ function createTokens(overrides) {
20839
20983
  }
20840
20984
 
20841
20985
  /**
20842
- * Theme System Error Handling
20986
+ * Theme Adapter
20843
20987
  *
20844
- * Centralized error handling for the Atomix theme system.
20845
- * Provides custom error classes and logging utilities.
20988
+ * Converts between Theme objects and DesignTokens
20846
20989
  */
20847
20990
  /**
20848
- * Theme error codes
20849
- */ var ThemeErrorCode, LogLevel;
20850
-
20851
- !function(ThemeErrorCode) {
20852
- /** Theme not found in registry */
20853
- ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
20854
- /** Theme failed to load */
20855
- ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
20856
- /** Theme validation failed */
20857
- ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
20858
- /** Configuration loading failed */
20859
- ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
20860
- /** Configuration validation failed */
20861
- ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
20862
- /** Circular dependency detected */
20863
- ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
20864
- /** Missing dependency */
20865
- ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
20866
- /** Storage operation failed */
20867
- ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
20868
- /** Invalid theme name */
20869
- ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
20870
- /** CSS injection failed */
20871
- ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
20872
- /** Invalid color format */
20873
- ThemeErrorCode.INVALID_COLOR_FORMAT = "INVALID_COLOR_FORMAT",
20874
- /** Missing required token */
20875
- ThemeErrorCode.MISSING_REQUIRED_TOKEN = "MISSING_REQUIRED_TOKEN",
20876
- /** Accessibility contrast violation */
20877
- ThemeErrorCode.CONTRAST_VIOLATION = "CONTRAST_VIOLATION",
20878
- /** Invalid token type */
20879
- ThemeErrorCode.INVALID_TOKEN_TYPE = "INVALID_TOKEN_TYPE",
20880
- /** Unknown error */
20881
- ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
20882
- }(ThemeErrorCode || (ThemeErrorCode = {}));
20883
-
20884
- /**
20885
- * Custom error class for theme-related errors
20886
- */
20887
- class ThemeError extends Error {
20888
- constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
20889
- super(message), this.name = "ThemeError", this.code = code, this.context = context,
20890
- this.timestamp = Date.now(),
20891
- // Maintains proper stack trace for where our error was thrown (only available on V8)
20892
- Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
20991
+ * Convert a Theme object to DesignTokens
20992
+ */ function themeToDesignTokens(theme) {
20993
+ const tokens = {};
20994
+ // Convert colors
20995
+ if (theme.palette) {
20996
+ // Primary color
20997
+ if (theme.palette.primary) {
20998
+ const primaryMain = theme.palette.primary.main;
20999
+ tokens.primary = primaryMain;
21000
+ const rgb = hexToRgb$2(primaryMain);
21001
+ rgb && (tokens["primary-rgb"] = rgb);
21002
+ }
21003
+ // Secondary color
21004
+ if (theme.palette.secondary) {
21005
+ const secondaryMain = theme.palette.secondary.main;
21006
+ tokens.secondary = secondaryMain;
21007
+ const rgb = hexToRgb$2(secondaryMain);
21008
+ rgb && (tokens["secondary-rgb"] = rgb);
21009
+ }
21010
+ // Other colors
21011
+ const colorKeys = [ "error", "warning", "info", "success" ];
21012
+ for (const key of colorKeys) if (theme.palette[key]) {
21013
+ const colorMain = theme.palette[key].main;
21014
+ tokens[key] = colorMain;
21015
+ const rgb = hexToRgb$2(colorMain);
21016
+ rgb && (tokens[`${key}-rgb`] = rgb);
21017
+ }
21018
+ // Background colors
21019
+ theme.palette.background && (tokens["body-bg"] = theme.palette.background.default),
21020
+ // Text colors
21021
+ theme.palette.text && (tokens["body-color"] = theme.palette.text.primary);
20893
21022
  }
20894
- /**
20895
- * Convert error to JSON for logging
20896
- */ toJSON() {
20897
- return {
20898
- name: this.name,
20899
- message: this.message,
20900
- code: this.code,
20901
- context: this.context,
20902
- timestamp: this.timestamp,
20903
- stack: this.stack
20904
- };
21023
+ // Convert typography
21024
+ // Convert border radius
21025
+ if (theme.typography && (tokens["body-font-family"] = theme.typography.fontFamily,
21026
+ tokens["body-font-size"] = `${theme.typography.fontSize}px`, tokens["font-weight-normal"] = `${theme.typography.fontWeightRegular}`,
21027
+ tokens["font-weight-bold"] = `${theme.typography.fontWeightBold}`),
21028
+ // Convert spacing
21029
+ "function" == typeof theme.spacing && (
21030
+ // If spacing is a function, call it with some values to get results
21031
+ tokens["spacing-1"] = theme.spacing(1), tokens["spacing-2"] = theme.spacing(2),
21032
+ tokens["spacing-4"] = theme.spacing(4)),
21033
+ // Convert breakpoints
21034
+ theme.breakpoints?.values && (tokens["breakpoint-xs"] = `${theme.breakpoints.values.xs}px`,
21035
+ tokens["breakpoint-sm"] = `${theme.breakpoints.values.sm}px`, tokens["breakpoint-md"] = `${theme.breakpoints.values.md}px`,
21036
+ tokens["breakpoint-lg"] = `${theme.breakpoints.values.lg}px`, tokens["breakpoint-xl"] = `${theme.breakpoints.values.xl}px`),
21037
+ // Convert shadows
21038
+ theme.shadows && (tokens["box-shadow"] = theme.shadows[2], // Use a moderate shadow
21039
+ tokens["box-shadow-sm"] = theme.shadows[1], tokens["box-shadow-lg"] = theme.shadows[3]),
21040
+ // Convert transitions
21041
+ theme.transitions && (tokens["transition-duration-base"] = `${theme.transitions.duration.standard}ms`),
21042
+ // Convert z-index
21043
+ theme.zIndex && (tokens["z-modal"] = `${theme.zIndex.modal}`, tokens["z-popover"] = `${theme.zIndex.popover}`,
21044
+ tokens["z-tooltip"] = `${theme.zIndex.tooltip}`), theme.borderRadius) {
21045
+ const baseRadius = theme.borderRadius.base;
21046
+ tokens["border-radius"] = "number" == typeof baseRadius ? `${baseRadius}px` : baseRadius;
21047
+ }
21048
+ // Add advanced feature tokens if available in theme
21049
+ if (theme.custom) {
21050
+ // Interactive Effects (Phase 2)
21051
+ if (theme.custom.interactiveEffects) {
21052
+ const ie = theme.custom.interactiveEffects;
21053
+ // Vortex effects
21054
+ ie.vortex && (tokens["interactive-vortex-enabled"] = String(ie.vortex.enabled ?? !1),
21055
+ tokens["interactive-vortex-strength"] = String(ie.vortex.strength ?? .5), tokens["interactive-vortex-radius"] = String(ie.vortex.radius ?? 100),
21056
+ tokens["interactive-vortex-decay"] = String(ie.vortex.decay ?? .8)),
21057
+ // Chromatic aberration
21058
+ ie.chromaticAberration && (tokens["interactive-chromatic-enabled"] = String(ie.chromaticAberration.enabled ?? !1),
21059
+ tokens["interactive-chromatic-mode"] = ie.chromaticAberration.mode ?? "lateral",
21060
+ tokens["interactive-chromatic-red-shift"] = String(ie.chromaticAberration.redShift ?? .02),
21061
+ tokens["interactive-chromatic-green-shift"] = String(ie.chromaticAberration.greenShift ?? 0),
21062
+ tokens["interactive-chromatic-blue-shift"] = String(ie.chromaticAberration.blueShift ?? -.02),
21063
+ tokens["interactive-chromatic-edge-only"] = String(ie.chromaticAberration.edgeOnly ?? !1),
21064
+ tokens["interactive-chromatic-edge-threshold"] = String(ie.chromaticAberration.edgeThreshold ?? .5)),
21065
+ // Mouse interaction
21066
+ ie.mouseInteraction && (tokens["interactive-mouse-sensitivity"] = String(ie.mouseInteraction.sensitivity ?? 1),
21067
+ tokens["interactive-mouse-trail-effect"] = String(ie.mouseInteraction.trailEffect ?? !1)),
21068
+ // Animation speed
21069
+ ie.animationSpeed && (tokens["interactive-animation-speed-base"] = String(ie.animationSpeed.base ?? 1),
21070
+ tokens["interactive-animation-speed-multiplier"] = String(ie.animationSpeed.timeMultiplier ?? 1));
21071
+ }
21072
+ // Optimization (Phase 3)
21073
+ if (theme.custom.optimization) {
21074
+ const opt = theme.custom.optimization;
21075
+ // Responsive breakpoints
21076
+ opt.responsive && (opt.responsive.breakpoints && (tokens["optimization-breakpoint-mobile"] = opt.responsive.breakpoints.mobile ?? "0px",
21077
+ tokens["optimization-breakpoint-tablet"] = opt.responsive.breakpoints.tablet ?? "768px",
21078
+ tokens["optimization-breakpoint-desktop"] = opt.responsive.breakpoints.desktop ?? "1024px",
21079
+ tokens["optimization-breakpoint-wide"] = opt.responsive.breakpoints.wide ?? "1440px"),
21080
+ opt.responsive.deviceScaling && (tokens["optimization-device-scaling-mobile"] = String(opt.responsive.deviceScaling.mobile ?? .5),
21081
+ tokens["optimization-device-scaling-tablet"] = String(opt.responsive.deviceScaling.tablet ?? .75),
21082
+ tokens["optimization-device-scaling-desktop"] = String(opt.responsive.deviceScaling.desktop ?? 1))),
21083
+ // Performance settings
21084
+ opt.performance && (tokens["optimization-performance-fps-target"] = String(opt.performance.fpsTarget ?? 60),
21085
+ tokens["optimization-auto-scaling-enabled"] = String(opt.performance.autoScaling ?? !1)),
21086
+ // Auto-scaling settings
21087
+ opt.autoScaling && (tokens["optimization-auto-scaling-enabled"] = String(opt.autoScaling.enabled ?? !1),
21088
+ tokens["optimization-auto-scaling-low-end"] = String(opt.autoScaling.qualityThresholds?.lowEnd ?? .5),
21089
+ tokens["optimization-auto-scaling-mid-range"] = String(opt.autoScaling.qualityThresholds?.midRange ?? .75),
21090
+ tokens["optimization-auto-scaling-high-end"] = String(opt.autoScaling.qualityThresholds?.highEnd ?? 1));
21091
+ }
21092
+ // Visual Polish (Phase 4)
21093
+ if (theme.custom.visualPolish) {
21094
+ const vp = theme.custom.visualPolish;
21095
+ vp.borders && (tokens["visual-polish-border-iridescent-glow"] = String(vp.borders.iridescentGlow ?? !1),
21096
+ tokens["visual-polish-border-shimmer-effect"] = String(vp.borders.shimmerEffect ?? !1),
21097
+ tokens["visual-polish-border-beveled-edges"] = String(vp.borders.beveledEdges ?? !1),
21098
+ tokens["visual-polish-border-pulsing-glow"] = String(vp.borders.pulsingGlow ?? !1)),
21099
+ vp.contentAwareBlur && (tokens["visual-polish-content-aware-blur-enabled"] = String(vp.contentAwareBlur.enabled ?? !1),
21100
+ tokens["visual-polish-content-aware-depth-detection"] = String(vp.contentAwareBlur.depthDetection ?? !1),
21101
+ tokens["visual-polish-content-aware-edge-preservation"] = String(vp.contentAwareBlur.edgePreservation ?? !1),
21102
+ tokens["visual-polish-content-aware-variable-radius"] = String(vp.contentAwareBlur.variableRadius ?? !1)),
21103
+ vp.holographicEffects && (tokens["visual-polish-holographic-enabled"] = String(vp.holographicEffects.enabled ?? !1),
21104
+ tokens["visual-polish-holographic-rainbow-diffraction"] = String(vp.holographicEffects.rainbowDiffraction ?? !1),
21105
+ tokens["visual-polish-holographic-scanline-animation"] = String(vp.holographicEffects.scanlineAnimation ?? !1),
21106
+ tokens["visual-polish-holographic-grid-overlay"] = String(vp.holographicEffects.gridOverlay ?? !1),
21107
+ tokens["visual-polish-holographic-data-stream"] = String(vp.holographicEffects.dataStream ?? !1),
21108
+ tokens["visual-polish-holographic-pulse-rings"] = String(vp.holographicEffects.pulseRings ?? !1));
21109
+ }
20905
21110
  }
21111
+ // Create full tokens object with defaults
21112
+ return createTokens(tokens);
20906
21113
  }
20907
21114
 
20908
21115
  /**
20909
- * Log level
20910
- */ !function(LogLevel) {
20911
- LogLevel[LogLevel.ERROR = 0] = "ERROR", LogLevel[LogLevel.WARN = 1] = "WARN", LogLevel[LogLevel.INFO = 2] = "INFO",
20912
- LogLevel[LogLevel.DEBUG = 3] = "DEBUG";
20913
- }(LogLevel || (LogLevel = {}));
20914
-
20915
- /**
20916
- * Theme Logger
21116
+ * Converts an AtomixConfig to DesignTokens
20917
21117
  *
20918
- * Centralized logging for the theme system.
20919
- * Replaces console statements with structured logging.
20920
- */
20921
- class ThemeLogger {
20922
- constructor(config = {}) {
20923
- this.config = {
20924
- level: config.level ?? ("undefined" != typeof process && "production" === process.env?.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
20925
- enableConsole: config.enableConsole ?? !0,
20926
- onError: config.onError,
20927
- onWarn: config.onWarn,
20928
- onInfo: config.onInfo,
20929
- onDebug: config.onDebug
20930
- };
20931
- }
20932
- /**
20933
- * Log an error
20934
- */ error(message, error, context) {
20935
- if (this.config.level < LogLevel.ERROR) return;
20936
- const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
20937
- this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
20938
- error: errorObj,
20939
- context: {
20940
- ...context,
20941
- ...themeError.context
20942
- },
20943
- code: themeError.code
20944
- }), this.config.onError?.(themeError, context);
20945
- }
20946
- /**
20947
- * Log a warning
20948
- */ warn(message, context) {
20949
- this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
20950
- this.config.onWarn?.(message, context));
20951
- }
20952
- /**
20953
- * Log an info message
20954
- */ info(message, context) {
20955
- this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
20956
- this.config.onInfo?.(message, context));
20957
- }
20958
- /**
20959
- * Log a debug message
20960
- */ debug(message, context) {
20961
- this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
21118
+ * This function maps the configuration from the user-facing format
21119
+ * to the internal DesignTokens format used by the theme system.
21120
+ *
21121
+ * @param config - The configuration object to convert
21122
+ * @returns DesignTokens object ready for theme generation
21123
+ *
21124
+ * @example
21125
+ * ```typescript
21126
+ * import { configToTokens } from '@shohojdhara/atomix/theme';
21127
+ *
21128
+ * const config = {
21129
+ * prefix: 'myapp',
21130
+ * theme: { extend: { colors: { primary: { main: '#7AFFD7' } } } }
21131
+ * };
21132
+ * const tokens = configToTokens(config);
21133
+ * ```
21134
+ */ function configToTokens(config) {
21135
+ const prefix = config.prefix || "atomix", theme = config.theme || {};
21136
+ // Start with default tokens
21137
+ let tokens = {
21138
+ ...defaultTokens
21139
+ };
21140
+ // Apply theme extensions
21141
+ // Apply advanced features if available in config
21142
+ if (theme.extend &&
21143
+ // Apply extensions to tokens
21144
+ Object.entries(theme.extend).forEach((([category, values]) => {
21145
+ "object" == typeof values && null !== values && Object.entries(values).forEach((([key, value]) => {
21146
+ // Map theme categories to token names
21147
+ const tokenName = `${category}-${key}`;
21148
+ "string" == typeof value || "number" == typeof value ? tokens[tokenName] = String(value) : "object" == typeof value && null !== value &&
21149
+ // Handle nested objects like color scales
21150
+ Object.entries(value).forEach((([nestedKey, nestedValue]) => {
21151
+ "string" != typeof nestedValue && "number" != typeof nestedValue || (tokens[`${tokenName}-${nestedKey}`] = String(nestedValue));
21152
+ }));
21153
+ }));
21154
+ })),
21155
+ // Apply theme tokens if provided (completely replacing defaults)
21156
+ theme.tokens && (tokens = {
21157
+ ...tokens,
21158
+ ...theme.tokens
21159
+ }), config) {
21160
+ // Interactive Effects (Phase 2)
21161
+ if (config.interactiveEffects) {
21162
+ const ie = config.interactiveEffects;
21163
+ // Vortex effects
21164
+ ie.vortex && (tokens["interactive-vortex-enabled"] = String(ie.vortex.enabled ?? !1),
21165
+ tokens["interactive-vortex-strength"] = String(ie.vortex.strength ?? .5), tokens["interactive-vortex-radius"] = String(ie.vortex.radius ?? 100),
21166
+ tokens["interactive-vortex-decay"] = String(ie.vortex.decay ?? .8), tokens["interactive-vortex-curl-noise"] = String(ie.vortex.curlNoise ?? !1),
21167
+ tokens["interactive-vortex-velocity-tracking"] = String(ie.vortex.velocityTracking ?? !1)),
21168
+ // Chromatic aberration
21169
+ ie.chromaticAberration && (tokens["interactive-chromatic-enabled"] = String(ie.chromaticAberration.enabled ?? !1),
21170
+ tokens["interactive-chromatic-mode"] = ie.chromaticAberration.mode ?? "lateral",
21171
+ tokens["interactive-chromatic-red-shift"] = String(ie.chromaticAberration.redShift ?? .02),
21172
+ tokens["interactive-chromatic-green-shift"] = String(ie.chromaticAberration.greenShift ?? 0),
21173
+ tokens["interactive-chromatic-blue-shift"] = String(ie.chromaticAberration.blueShift ?? -.02),
21174
+ tokens["interactive-chromatic-edge-only"] = String(ie.chromaticAberration.edgeOnly ?? !1),
21175
+ tokens["interactive-chromatic-edge-threshold"] = String(ie.chromaticAberration.edgeThreshold ?? .5)),
21176
+ // Mouse interaction
21177
+ ie.mouseInteraction && (tokens["interactive-mouse-sensitivity"] = String(ie.mouseInteraction.sensitivity ?? 1),
21178
+ tokens["interactive-mouse-trail-effect"] = String(ie.mouseInteraction.trailEffect ?? !1),
21179
+ tokens["interactive-mouse-pressure-sensitivity"] = String(ie.mouseInteraction.pressureSensitivity ?? !1)),
21180
+ // Animation speed
21181
+ ie.animationSpeed && (tokens["interactive-animation-speed-base"] = String(ie.animationSpeed.base ?? 1),
21182
+ tokens["interactive-animation-speed-multiplier"] = String(ie.animationSpeed.timeMultiplier ?? 1));
21183
+ }
21184
+ // Optimization (Phase 3)
21185
+ if (config.optimization) {
21186
+ const opt = config.optimization;
21187
+ // Responsive breakpoints
21188
+ opt.responsive && (opt.responsive.breakpoints && (tokens["optimization-breakpoint-mobile"] = opt.responsive.breakpoints.mobile ?? "0px",
21189
+ tokens["optimization-breakpoint-tablet"] = opt.responsive.breakpoints.tablet ?? "768px",
21190
+ tokens["optimization-breakpoint-desktop"] = opt.responsive.breakpoints.desktop ?? "1024px",
21191
+ tokens["optimization-breakpoint-wide"] = opt.responsive.breakpoints.wide ?? "1440px"),
21192
+ opt.responsive.deviceScaling && (tokens["optimization-device-scaling-mobile"] = String(opt.responsive.deviceScaling.mobile ?? .5),
21193
+ tokens["optimization-device-scaling-tablet"] = String(opt.responsive.deviceScaling.tablet ?? .75),
21194
+ tokens["optimization-device-scaling-desktop"] = String(opt.responsive.deviceScaling.desktop ?? 1))),
21195
+ // Performance settings
21196
+ opt.performance && (tokens["optimization-performance-fps-target"] = String(opt.performance.fpsTarget ?? 60),
21197
+ tokens["optimization-auto-scaling-enabled"] = String(opt.performance.autoScaling ?? !1),
21198
+ tokens["optimization-monitor-dashboard-enabled"] = String(opt.performance.monitorDashboard ?? !1)),
21199
+ // Auto-scaling settings
21200
+ opt.autoScaling && (tokens["optimization-auto-scaling-enabled"] = String(opt.autoScaling.enabled ?? !1),
21201
+ tokens["optimization-auto-scaling-low-end"] = String(opt.autoScaling.qualityThresholds?.lowEnd ?? .5),
21202
+ tokens["optimization-auto-scaling-mid-range"] = String(opt.autoScaling.qualityThresholds?.midRange ?? .75),
21203
+ tokens["optimization-auto-scaling-high-end"] = String(opt.autoScaling.qualityThresholds?.highEnd ?? 1));
21204
+ }
21205
+ // Visual Polish (Phase 4)
21206
+ if (config.visualPolish) {
21207
+ const vp = config.visualPolish;
21208
+ vp.borders && (tokens["visual-polish-border-iridescent-glow"] = String(vp.borders.iridescentGlow ?? !1),
21209
+ tokens["visual-polish-border-shimmer-effect"] = String(vp.borders.shimmerEffect ?? !1),
21210
+ tokens["visual-polish-border-beveled-edges"] = String(vp.borders.beveledEdges ?? !1),
21211
+ tokens["visual-polish-border-pulsing-glow"] = String(vp.borders.pulsingGlow ?? !1)),
21212
+ vp.contentAwareBlur && (tokens["visual-polish-content-aware-blur-enabled"] = String(vp.contentAwareBlur.enabled ?? !1),
21213
+ tokens["visual-polish-content-aware-depth-detection"] = String(vp.contentAwareBlur.depthDetection ?? !1),
21214
+ tokens["visual-polish-content-aware-edge-preservation"] = String(vp.contentAwareBlur.edgePreservation ?? !1),
21215
+ tokens["visual-polish-content-aware-variable-radius"] = String(vp.contentAwareBlur.variableRadius ?? !1)),
21216
+ vp.holographicEffects && (tokens["visual-polish-holographic-enabled"] = String(vp.holographicEffects.enabled ?? !1),
21217
+ tokens["visual-polish-holographic-rainbow-diffraction"] = String(vp.holographicEffects.rainbowDiffraction ?? !1),
21218
+ tokens["visual-polish-holographic-scanline-animation"] = String(vp.holographicEffects.scanlineAnimation ?? !1),
21219
+ tokens["visual-polish-holographic-grid-overlay"] = String(vp.holographicEffects.gridOverlay ?? !1),
21220
+ tokens["visual-polish-holographic-data-stream"] = String(vp.holographicEffects.dataStream ?? !1),
21221
+ tokens["visual-polish-holographic-pulse-rings"] = String(vp.holographicEffects.pulseRings ?? !1));
21222
+ }
20962
21223
  }
21224
+ // Apply prefix to all tokens
21225
+ const prefixedTokens = {};
21226
+ return Object.entries(tokens).forEach((([key, value]) => {
21227
+ // If the token key already starts with the prefix, use as-is
21228
+ // Otherwise, add the prefix
21229
+ const prefixedKey = key.startsWith(prefix) ? key : `${prefix}-${key}`;
21230
+ prefixedTokens[prefixedKey] = value;
21231
+ })), prefixedTokens;
20963
21232
  }
20964
21233
 
20965
21234
  /**
20966
- * Default logger instance
20967
- */ let defaultLogger = null;
21235
+ * Convert hex color to RGB
21236
+ */ function hexToRgb$2(hex) {
21237
+ hex = hex.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, ((m, r, g, b) => r + r + g + g + b + b));
21238
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
21239
+ return result && result[1] && result[2] && result[3] ? `${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)}` : "0, 0, 0";
21240
+ }
20968
21241
 
20969
21242
  /**
20970
- * Get or create default logger
20971
- */ function getLogger() {
20972
- return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
21243
+ * Converts DesignTokens to CSS variables
21244
+ *
21245
+ * @param tokens - The tokens to convert
21246
+ * @returns A record of CSS variable names and values
21247
+ */ function designTokensToCSSVars(tokens) {
21248
+ const cssVars = {};
21249
+ return Object.entries(tokens).forEach((([key, value]) => {
21250
+ void 0 !== value && (cssVars[`--atomix-${key}`] = String(value));
21251
+ })), cssVars;
20973
21252
  }
20974
21253
 
20975
21254
  /**
20976
- * Core Theme Functions
20977
- *
20978
- * Simplified theme system using DesignTokens only.
20979
- * Config-first approach: loads from atomix.config.ts when no input is provided.
21255
+ * Load theme from config file (synchronous, Node.js only)
21256
+ * @param configPath - Path to config file (default: atomix.config.ts)
21257
+ * @returns DesignTokens from theme configuration
21258
+ * @throws Error if config loading is not available in browser environment
20980
21259
  */
20981
21260
  /**
20982
- * Create theme CSS from DesignTokens
21261
+ * Validate Atomix configuration structure
20983
21262
  *
20984
- * **Config-First Approach**: If no input is provided, loads from `atomix.config.ts`.
21263
+ * Performs basic validation to catch common configuration errors early.
21264
+ * Returns warnings for potential issues.
20985
21265
  *
20986
- * @param input - DesignTokens (partial) or undefined (loads from config)
20987
- * @param options - CSS generation options (prefix is automatically read from config if not provided)
20988
- * @returns CSS string with custom properties
20989
- * @throws Error if config loading fails when no input is provided
21266
+ * @param config - Configuration object to validate
21267
+ * @returns Array of validation warnings (empty if valid)
20990
21268
  *
20991
21269
  * @example
20992
21270
  * ```typescript
20993
- * // Loads from atomix.config.ts
20994
- * const css = createTheme();
20995
- *
20996
- * // Using DesignTokens
20997
- * const css = createTheme({
20998
- * 'primary': '#7c3aed',
20999
- * 'spacing-4': '1rem',
21000
- * });
21271
+ * import { loadAtomixConfig, validateConfig } from '@shohojdhara/atomix/config';
21001
21272
  *
21002
- * // With custom options
21003
- * const css = createTheme(undefined, { prefix: 'myapp', selector: ':root' });
21273
+ * const config = loadAtomixConfig();
21274
+ * const warnings = validateConfig(config);
21275
+ * warnings.forEach(w => console.warn(w));
21004
21276
  * ```
21005
- */ function createTheme(input, options) {
21006
- // Validate options if provided
21007
- if (options?.prefix) {
21008
- const prefixPattern = /^[a-z][a-z0-9-]*$/;
21009
- if (!prefixPattern.test(options.prefix)) throw new ThemeError(`Invalid CSS variable prefix: "${options.prefix}". Prefix must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens (e.g., "atomix", "my-app").`, ThemeErrorCode.THEME_VALIDATION_FAILED, {
21010
- prefix: options.prefix,
21011
- pattern: prefixPattern.toString()
21012
- });
21277
+ */
21278
+ function validateConfig$1(config) {
21279
+ const warnings = [];
21280
+ // Check prefix format
21281
+ // Check theme structure
21282
+ if (config.prefix && (/^[a-zA-Z][a-zA-Z0-9-]*$/.test(config.prefix) || warnings.push(`Invalid prefix "${config.prefix}". Prefix should start with a letter and contain only letters, numbers, and hyphens.\nExample: "myapp", "brand-ui", "enterprise"`),
21283
+ config.prefix.length < 2 && warnings.push(`Prefix "${config.prefix}" is too short. Use at least 2 characters for clarity.\nExample: "app" instead of "a"`)),
21284
+ config.theme && (
21285
+ // Warn if both extend and tokens are provided
21286
+ config.theme.extend && config.theme.tokens && warnings.push("Both theme.extend and theme.tokens are defined. theme.tokens will take precedence and completely replace the default token system.\nIf you want to extend defaults, remove theme.tokens and use only theme.extend."),
21287
+ config.theme.extend)) {
21288
+ const extend = config.theme.extend, validThemeKeys = [ "colors", "typography", "spacing", "borderRadius", "shadows", "zIndex", "transitions", "breakpoints" ];
21289
+ // Check for common typos in theme properties
21290
+ Object.keys(extend).forEach((key => {
21291
+ _includesInstanceProperty(validThemeKeys).call(validThemeKeys, key) || warnings.push(`Unknown theme property: "${key}"\nValid properties: ${validThemeKeys.join(", ")}\nDid you mean one of these? Check for typos.`);
21292
+ }));
21013
21293
  }
21014
- // Validate selector if provided
21015
- if (options?.selector && ("string" != typeof options.selector || 0 === options.selector.trim().length)) throw new ThemeError(`Invalid CSS selector: "${options.selector}". Selector must be a non-empty string (e.g., ":root", ".my-theme").`, ThemeErrorCode.THEME_VALIDATION_FAILED, {
21016
- selector: options.selector
21017
- });
21018
- // Determine tokens based on input
21019
- let tokens;
21020
- if (input) {
21021
- // Validate input tokens structure
21022
- if ("object" != typeof input || null === input || Array.isArray(input)) throw new ThemeError(`Invalid tokens input. Expected an object with DesignTokens, but received: ${typeof input}.`, ThemeErrorCode.THEME_VALIDATION_FAILED, {
21023
- inputType: typeof input
21024
- });
21025
- // Use DesignTokens directly
21026
- tokens = input;
21294
+ // Validate advanced features
21295
+ if (config.interactiveEffects) {
21296
+ const ie = config.interactiveEffects;
21297
+ // Validate vortex settings
21298
+ ie.vortex && (ie.vortex.strength && (ie.vortex.strength < 0 || ie.vortex.strength > 10) && warnings.push("Vortex strength should be between 0 and 10 for optimal performance"),
21299
+ ie.vortex.radius && ie.vortex.radius < 0 && warnings.push("Vortex radius should be a positive number"),
21300
+ ie.vortex.decay && (ie.vortex.decay <= 0 || ie.vortex.decay > 1) && warnings.push("Vortex decay should be between 0 and 1")),
21301
+ // Validate chromatic aberration settings
21302
+ ie.chromaticAberration && (ie.chromaticAberration.redShift && Math.abs(ie.chromaticAberration.redShift) > .1 && warnings.push("Chromatic red shift value seems unusually high (>0.1), verify this is intended"),
21303
+ ie.chromaticAberration.blueShift && Math.abs(ie.chromaticAberration.blueShift) > .1 && warnings.push("Chromatic blue shift value seems unusually high (>0.1), verify this is intended"),
21304
+ ie.chromaticAberration.edgeThreshold && (ie.chromaticAberration.edgeThreshold < 0 || ie.chromaticAberration.edgeThreshold > 1) && warnings.push("Chromatic edge threshold should be between 0 and 1")),
21305
+ // Validate mouse interaction settings
21306
+ ie.mouseInteraction && ie.mouseInteraction.sensitivity && ie.mouseInteraction.sensitivity < 0 && warnings.push("Mouse sensitivity should be a positive number"),
21307
+ // Validate animation speed settings
21308
+ ie.animationSpeed && (ie.animationSpeed.base && ie.animationSpeed.base <= 0 && warnings.push("Animation base speed should be greater than 0"),
21309
+ ie.animationSpeed.timeMultiplier && ie.animationSpeed.timeMultiplier <= 0 && warnings.push("Animation time multiplier should be greater than 0"));
21310
+ }
21311
+ // Validate optimization settings
21312
+ if (config.optimization) {
21313
+ const opt = config.optimization;
21314
+ // Validate responsive breakpoints
21315
+ if (opt.responsive && opt.responsive.breakpoints) {
21316
+ const breakpoints = opt.responsive.breakpoints;
21317
+ breakpoints.mobile && !isValidCSSLength(breakpoints.mobile) && warnings.push("Mobile breakpoint value is not a valid CSS length"),
21318
+ breakpoints.tablet && !isValidCSSLength(breakpoints.tablet) && warnings.push("Tablet breakpoint value is not a valid CSS length"),
21319
+ breakpoints.desktop && !isValidCSSLength(breakpoints.desktop) && warnings.push("Desktop breakpoint value is not a valid CSS length"),
21320
+ breakpoints.wide && !isValidCSSLength(breakpoints.wide) && warnings.push("Wide breakpoint value is not a valid CSS length");
21321
+ }
21322
+ // Validate device scaling
21323
+ if (opt.responsive && opt.responsive.deviceScaling) {
21324
+ const scaling = opt.responsive.deviceScaling;
21325
+ scaling.mobile && (scaling.mobile <= 0 || scaling.mobile > 1) && warnings.push("Mobile device scaling should be between 0 and 1"),
21326
+ scaling.tablet && (scaling.tablet <= 0 || scaling.tablet > 1) && warnings.push("Tablet device scaling should be between 0 and 1"),
21327
+ scaling.desktop && (scaling.desktop <= 0 || scaling.desktop > 1) && warnings.push("Desktop device scaling should be between 0 and 1");
21328
+ }
21329
+ // Validate performance settings
21330
+ // Validate auto-scaling thresholds
21331
+ if (opt.performance && opt.performance.fpsTarget && (opt.performance.fpsTarget <= 0 || opt.performance.fpsTarget > 240) && warnings.push("FPS target should be a reasonable value (typically 30-120)"),
21332
+ opt.autoScaling && opt.autoScaling.qualityThresholds) {
21333
+ const thresholds = opt.autoScaling.qualityThresholds;
21334
+ thresholds.lowEnd && (thresholds.lowEnd < 0 || thresholds.lowEnd > 1) && warnings.push("Auto-scaling low-end threshold should be between 0 and 1"),
21335
+ thresholds.midRange && (thresholds.midRange < 0 || thresholds.midRange > 1) && warnings.push("Auto-scaling mid-range threshold should be between 0 and 1"),
21336
+ thresholds.highEnd && (thresholds.highEnd < 0 || thresholds.highEnd > 1) && warnings.push("Auto-scaling high-end threshold should be between 0 and 1");
21337
+ }
21338
+ }
21339
+ // Validate visual polish settings
21340
+ if (config.visualPolish) {
21341
+ const vp = config.visualPolish;
21342
+ // Validate content aware blur settings
21343
+ vp.contentAwareBlur && (void 0 !== vp.contentAwareBlur.edgePreservation && "boolean" != typeof vp.contentAwareBlur.edgePreservation && warnings.push("Content-aware blur edge preservation should be a boolean value"),
21344
+ void 0 !== vp.contentAwareBlur.depthDetection && "boolean" != typeof vp.contentAwareBlur.depthDetection && warnings.push("Content-aware blur depth detection should be a boolean value")),
21345
+ // Validate holographic effects settings
21346
+ vp.holographicEffects && (void 0 !== vp.holographicEffects.enabled && "boolean" != typeof vp.holographicEffects.enabled && warnings.push("Holographic effects enabled should be a boolean value"),
21347
+ void 0 !== vp.holographicEffects.rainbowDiffraction && "boolean" != typeof vp.holographicEffects.rainbowDiffraction && warnings.push("Holographic rainbow diffraction should be a boolean value"));
21348
+ }
21349
+ // Validate AI settings
21350
+ var _context;
21351
+ return config.ai && (config.ai.provider && !_includesInstanceProperty(_context = [ "openai", "anthropic" ]).call(_context, config.ai.provider) && warnings.push(`Unknown AI provider: "${config.ai.provider}". Supported: openai, anthropic`),
21352
+ config.ai.temperature && (config.ai.temperature < 0 || config.ai.temperature > 1) && warnings.push("AI temperature should be between 0 and 1"),
21353
+ config.ai.maxTokens && config.ai.maxTokens < 100 && warnings.push("AI maxTokens should typically be 100 or more"),
21354
+ config.ai.rateLimit && (config.ai.rateLimit.requests <= 0 && warnings.push("AI rate limit requests should be greater than 0"),
21355
+ config.ai.rateLimit.windowMs <= 0 && warnings.push("AI rate limit window should be greater than 0"))),
21356
+ // Validate telemetry settings
21357
+ config.telemetry && config.telemetry.path && !config.telemetry.path.endsWith(".json") && warnings.push("Telemetry path should typically end with .json"),
21358
+ warnings;
21359
+ }
21360
+
21361
+ /**
21362
+ * Helper function to validate CSS length values
21363
+ */ function isValidCSSLength(value) {
21364
+ return /^(\d+(\.\d+)?)(px|em|rem|%|vw|vh|vmin|vmax|cm|mm|in|pt|pc|ex|ch)?$/.test(value);
21365
+ }
21366
+
21367
+ /**
21368
+ * Load Atomix configuration from project root
21369
+ *
21370
+ * Attempts to load atomix.config.ts, atomix.config.js, or atomix.config.json from the current working directory.
21371
+ * Falls back to default config if file doesn't exist.
21372
+ *
21373
+ * @param options - Loader options
21374
+ * @returns Loaded configuration or default
21375
+ *
21376
+ * @example
21377
+ * ```typescript
21378
+ * import { loadAtomixConfig } from '@shohojdhara/atomix/config';
21379
+ * import { createTheme } from '@shohojdhara/atomix/theme';
21380
+ *
21381
+ * const config = loadAtomixConfig();
21382
+ * const theme = createTheme(config.theme?.tokens || {});
21383
+ * ```
21384
+ */ function loadAtomixConfig(options = {}) {
21385
+ const {configPath: configPath, required: required = !1} = options, defaultConfig = {
21386
+ prefix: "atomix",
21387
+ theme: {
21388
+ extend: {}
21389
+ }
21390
+ };
21391
+ // Default config
21392
+ // In browser environments, config loading is not supported
21393
+ if ("undefined" != typeof window) {
21394
+ if (required) throw new Error('Config loading requires Node.js file system access.\n\nSolutions:\n1. Provide tokens explicitly to createTheme():\n const css = createTheme({ "--brand-primary": "#6366f1" });\n\n2. Use SSR framework (Next.js, Remix, Astro)\n\n3. Load config on server and pass to client\n\nSee examples/config-examples/browser-only.config.ts');
21395
+ return defaultConfig;
21396
+ }
21397
+ // If a specific config path is provided, try to load it directly
21398
+ if (configPath) return loadConfigAtPath(configPath, required, defaultConfig);
21399
+ // Otherwise, try standard locations in order of preference
21400
+ const possiblePaths = [ "atomix.config.ts", "atomix.config.js", "atomix.config.json" ];
21401
+ for (const path of possiblePaths) {
21402
+ const config = loadConfigAtPath(path, !1, defaultConfig);
21403
+ // If we found a valid config, return it
21404
+ if (JSON.stringify(config) !== JSON.stringify(defaultConfig)) return config;
21405
+ }
21406
+ // If no config file was found or all contained only defaults, return default config
21407
+ if (required) throw new Error('No Atomix configuration file found in project root.\n\nExpected one of:\n - atomix.config.ts (recommended)\n - atomix.config.js\n - atomix.config.json\n\nQuick Fix:\n1. Create a config file in your project root:\n touch atomix.config.ts\n\n2. Add basic configuration:\n import { defineConfig } from "@shohojdhara/atomix/config";\n export default defineConfig({ prefix: "myapp" });\n\n3. Or copy an example:\n cp node_modules/@shohojdhara/atomix/examples/config-examples/standard.config.ts ./atomix.config.ts');
21408
+ return defaultConfig;
21409
+ }
21410
+
21411
+ /**
21412
+ * Helper function to load config from a specific path
21413
+ */ function loadConfigAtPath(path, required, defaultConfig) {
21414
+ try {
21415
+ // Use dynamic import for ESM compatibility
21416
+ const configModule = require(path), config = configModule.default || configModule;
21417
+ // Validate it's an AtomixConfig
21418
+ if (config && "object" == typeof config) return config;
21419
+ throw new Error("Invalid config format");
21420
+ } catch (error) {
21421
+ if (required) throw new Error(`Failed to load config from ${path}: ${error.message}`);
21422
+ // Return default config if not required
21423
+ return defaultConfig;
21424
+ }
21425
+ }
21426
+
21427
+ /**
21428
+ * Resolve config path
21429
+ *
21430
+ * Finds atomix.config.ts in the project, checking common locations.
21431
+ * Returns null in browser environments where file system access is not available.
21432
+ *
21433
+ * This function is designed to help tools identify if a config exists without loading it.
21434
+ *
21435
+ * @param configPath - Optional custom path to check
21436
+ * @returns Absolute path to config file or null if not found
21437
+ */ function resolveConfigPath(configPath) {
21438
+ // In browser environments, config resolution is not possible
21439
+ if ("undefined" != typeof window) return null;
21440
+ // If a specific config path is provided, check if it exists
21441
+ if (configPath) {
21442
+ const absPath = join(process.cwd(), configPath);
21443
+ return existsSync(absPath) ? absPath : null;
21444
+ }
21445
+ // Otherwise, check standard locations
21446
+ const possiblePaths = [ join(process.cwd(), "atomix.config.ts"), join(process.cwd(), "atomix.config.js"), join(process.cwd(), "atomix.config.json") ];
21447
+ for (const path of possiblePaths) if (existsSync(path)) return path;
21448
+ return null;
21449
+ }
21450
+
21451
+ /**
21452
+ * Core Theme Functions
21453
+ *
21454
+ * Unified theme system that handles both DesignTokens and Theme objects.
21455
+ * Config-first approach: loads from atomix.config.ts when no input is provided.
21456
+ * Config-first approach: loads advanced features from config when available.
21457
+ */
21458
+ /**
21459
+ * Create theme CSS from tokens or Theme object
21460
+ *
21461
+ * **Config-First Approach**: If no input is provided, loads from `atomix.config.ts`.
21462
+ * Config file is required for automatic loading.
21463
+ *
21464
+ * @param input - DesignTokens (partial), Theme object, or undefined (loads from config)
21465
+ * @param options - CSS generation options (prefix is automatically read from config if not provided)
21466
+ * @returns CSS string with custom properties
21467
+ * @throws Error if config loading fails when no input is provided
21468
+ *
21469
+ * @example
21470
+ * ```typescript
21471
+ * // Loads from atomix.config.ts (config file required)
21472
+ * const css = createTheme();
21473
+ *
21474
+ * // Using DesignTokens
21475
+ * const css = createTheme({
21476
+ * 'primary': '#7c3aed',
21477
+ * 'spacing-4': '1rem',
21478
+ * });
21479
+ *
21480
+ * // Using Theme object
21481
+ * const theme = createThemeObject({ palette: { primary: { main: '#7c3aed' } } });
21482
+ * const css = createTheme(theme);
21483
+ *
21484
+ * // With custom options
21485
+ * const css = createTheme(undefined, { prefix: 'myapp', selector: ':root' });
21486
+ * ```
21487
+ */ function createTheme(input, options) {
21488
+ let tokens, configPrefix;
21489
+ // If no input provided, load from config (required)
21490
+ if (input)
21491
+ // Convert Theme object to DesignTokens
21492
+ tokens = !0 === input.__isJSTheme || input.palette && input.typography ? themeToDesignTokens(input) : input; else {
21493
+ const configTokens = function() {
21494
+ // Check if we're in a browser environment
21495
+ if ("undefined" != typeof window) throw new Error("loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.");
21496
+ // Use dynamic import to load the config loader
21497
+ // This allows bundlers to handle external dependencies properly
21498
+ let loadAtomixConfig;
21499
+ try {
21500
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
21501
+ const {loadAtomixConfig: loader} = require("../../config/loader");
21502
+ loadAtomixConfig = loader;
21503
+ } catch (error) {
21504
+ throw new Error("Config loader module not available");
21505
+ }
21506
+ const config = loadAtomixConfig({
21507
+ configPath: undefined,
21508
+ required: !0
21509
+ });
21510
+ if (!config?.theme) return createTokens({});
21511
+ if ((obj = config.theme) && "object" == typeof obj && (obj.palette || obj.typography || obj.spacing || obj.breakpoints || obj.colors)) return themeToDesignTokens(config.theme);
21512
+ // Handle the config.theme object which has extend/tokens/themes properties
21513
+ // Extract the actual tokens from the theme configuration
21514
+ // Helper type guard function
21515
+ var obj;
21516
+ const themeConfig = config.theme;
21517
+ let tokensToApply = {};
21518
+ return themeConfig.tokens ?
21519
+ // If tokens is provided, use it as the base
21520
+ tokensToApply = themeConfig.tokens : themeConfig.extend && (
21521
+ // If only extend is provided, use it as overrides
21522
+ tokensToApply = themeConfig.extend),
21523
+ // Apply advanced feature configurations as tokens
21524
+ config.interactiveEffects && (
21525
+ // Vortex effects
21526
+ config.interactiveEffects.vortex && (tokensToApply = {
21527
+ ...tokensToApply,
21528
+ "interactive-vortex-enabled": String(config.interactiveEffects.vortex.enabled ?? !1),
21529
+ "interactive-vortex-strength": String(config.interactiveEffects.vortex.strength ?? .5),
21530
+ "interactive-vortex-radius": String(config.interactiveEffects.vortex.radius ?? 100),
21531
+ "interactive-vortex-decay": String(config.interactiveEffects.vortex.decay ?? .8)
21532
+ }),
21533
+ // Chromatic aberration
21534
+ config.interactiveEffects.chromaticAberration && (tokensToApply = {
21535
+ ...tokensToApply,
21536
+ "interactive-chromatic-enabled": String(config.interactiveEffects.chromaticAberration.enabled ?? !1),
21537
+ "interactive-chromatic-mode": config.interactiveEffects.chromaticAberration.mode ?? "lateral",
21538
+ "interactive-chromatic-red-shift": String(config.interactiveEffects.chromaticAberration.redShift ?? .02),
21539
+ "interactive-chromatic-green-shift": String(config.interactiveEffects.chromaticAberration.greenShift ?? 0),
21540
+ "interactive-chromatic-blue-shift": String(config.interactiveEffects.chromaticAberration.blueShift ?? -.02),
21541
+ "interactive-chromatic-edge-only": String(config.interactiveEffects.chromaticAberration.edgeOnly ?? !1),
21542
+ "interactive-chromatic-edge-threshold": String(config.interactiveEffects.chromaticAberration.edgeThreshold ?? .5)
21543
+ }),
21544
+ // Mouse interaction
21545
+ config.interactiveEffects.mouseInteraction && (tokensToApply = {
21546
+ ...tokensToApply,
21547
+ "interactive-mouse-sensitivity": String(config.interactiveEffects.mouseInteraction.sensitivity ?? 1),
21548
+ "interactive-mouse-trail-effect": String(config.interactiveEffects.mouseInteraction.trailEffect ?? !1)
21549
+ }),
21550
+ // Animation speed
21551
+ config.interactiveEffects.animationSpeed && (tokensToApply = {
21552
+ ...tokensToApply,
21553
+ "interactive-animation-speed-base": String(config.interactiveEffects.animationSpeed.base ?? 1),
21554
+ "interactive-animation-speed-multiplier": String(config.interactiveEffects.animationSpeed.timeMultiplier ?? 1)
21555
+ })),
21556
+ // Apply optimization configurations as tokens
21557
+ config.optimization && (
21558
+ // Responsive breakpoints
21559
+ config.optimization.responsive && (config.optimization.responsive.breakpoints && (tokensToApply = {
21560
+ ...tokensToApply,
21561
+ "optimization-breakpoint-mobile": config.optimization.responsive.breakpoints.mobile ?? "0px",
21562
+ "optimization-breakpoint-tablet": config.optimization.responsive.breakpoints.tablet ?? "768px",
21563
+ "optimization-breakpoint-desktop": config.optimization.responsive.breakpoints.desktop ?? "1024px",
21564
+ "optimization-breakpoint-wide": config.optimization.responsive.breakpoints.wide ?? "1440px"
21565
+ }), config.optimization.responsive.deviceScaling && (tokensToApply = {
21566
+ ...tokensToApply,
21567
+ "optimization-device-scaling-mobile": String(config.optimization.responsive.deviceScaling.mobile ?? .5),
21568
+ "optimization-device-scaling-tablet": String(config.optimization.responsive.deviceScaling.tablet ?? .75),
21569
+ "optimization-device-scaling-desktop": String(config.optimization.responsive.deviceScaling.desktop ?? 1)
21570
+ })),
21571
+ // Performance settings
21572
+ config.optimization.performance && (tokensToApply = {
21573
+ ...tokensToApply,
21574
+ "optimization-performance-fps-target": String(config.optimization.performance.fpsTarget ?? 60),
21575
+ "optimization-auto-scaling-enabled": String(config.optimization.performance.autoScaling ?? !1)
21576
+ }),
21577
+ // Auto-scaling settings
21578
+ config.optimization.autoScaling && (tokensToApply = {
21579
+ ...tokensToApply,
21580
+ "optimization-auto-scaling-enabled": String(config.optimization.autoScaling.enabled ?? !1),
21581
+ "optimization-auto-scaling-low-end": String(config.optimization.autoScaling.qualityThresholds?.lowEnd ?? .5),
21582
+ "optimization-auto-scaling-mid-range": String(config.optimization.autoScaling.qualityThresholds?.midRange ?? .75),
21583
+ "optimization-auto-scaling-high-end": String(config.optimization.autoScaling.qualityThresholds?.highEnd ?? 1)
21584
+ })),
21585
+ // Apply visual polish configurations as tokens
21586
+ config.visualPolish && (config.visualPolish.borders && (tokensToApply = {
21587
+ ...tokensToApply,
21588
+ "visual-polish-border-iridescent-glow": String(config.visualPolish.borders.iridescentGlow ?? !1),
21589
+ "visual-polish-border-shimmer-effect": String(config.visualPolish.borders.shimmerEffect ?? !1),
21590
+ "visual-polish-border-beveled-edges": String(config.visualPolish.borders.beveledEdges ?? !1),
21591
+ "visual-polish-border-pulsing-glow": String(config.visualPolish.borders.pulsingGlow ?? !1)
21592
+ }), config.visualPolish.contentAwareBlur && (tokensToApply = {
21593
+ ...tokensToApply,
21594
+ "visual-polish-content-aware-blur-enabled": String(config.visualPolish.contentAwareBlur.enabled ?? !1),
21595
+ "visual-polish-content-aware-depth-detection": String(config.visualPolish.contentAwareBlur.depthDetection ?? !1),
21596
+ "visual-polish-content-aware-edge-preservation": String(config.visualPolish.contentAwareBlur.edgePreservation ?? !1),
21597
+ "visual-polish-content-aware-variable-radius": String(config.visualPolish.contentAwareBlur.variableRadius ?? !1)
21598
+ }), config.visualPolish.holographicEffects && (tokensToApply = {
21599
+ ...tokensToApply,
21600
+ "visual-polish-holographic-enabled": String(config.visualPolish.holographicEffects.enabled ?? !1),
21601
+ "visual-polish-holographic-rainbow-diffraction": String(config.visualPolish.holographicEffects.rainbowDiffraction ?? !1),
21602
+ "visual-polish-holographic-scanline-animation": String(config.visualPolish.holographicEffects.scanlineAnimation ?? !1),
21603
+ "visual-polish-holographic-grid-overlay": String(config.visualPolish.holographicEffects.gridOverlay ?? !1),
21604
+ "visual-polish-holographic-data-stream": String(config.visualPolish.holographicEffects.dataStream ?? !1),
21605
+ "visual-polish-holographic-pulse-rings": String(config.visualPolish.holographicEffects.pulseRings ?? !1)
21606
+ })), createTokens(tokensToApply);
21607
+ }();
21608
+ // Get prefix from config
21609
+ try {
21610
+ // Use the imported function directly instead of require to avoid bundling issues
21611
+ const config = loadAtomixConfig({
21612
+ configPath: "atomix.config.ts",
21613
+ required: !0
21614
+ });
21615
+ configPrefix = config?.prefix;
21616
+ } catch (error) {
21617
+ // Prefix loading failed, but tokens were loaded, so continue
21618
+ }
21619
+ tokens = configTokens;
21027
21620
  }
21028
21621
  // Merge with defaults and generate CSS
21029
- else
21030
- // Auto-loading config from file system is removed for browser compatibility.
21031
- // If no input is provided, we return an empty theme (using defaults only) or user must provide tokens.
21032
- // This allows createTheme to be isomorphic.
21033
- // Warn in development if no input provided
21034
- "production" !== process.env.NODE_ENV && "undefined" != typeof window && console.warn("Atomix: createTheme() called without tokens. Using default tokens only."),
21035
- tokens = {};
21036
- const allTokens = createTokens(tokens), prefix = options?.prefix ?? "atomix";
21037
- // Get prefix from options or use default
21622
+ const allTokens = createTokens(tokens), prefix = options?.prefix ?? configPrefix ?? "atomix";
21623
+ // Get prefix from options, config, or use default
21038
21624
  return generateCSSVariables$1(allTokens, {
21039
21625
  ...options,
21040
21626
  prefix: prefix
@@ -21248,12 +21834,145 @@ class ThemeLogger {
21248
21834
  */
21249
21835
  /**
21250
21836
  * Default storage key for theme persistence
21251
- */ "undefined" != typeof process && process.env;
21837
+ */
21838
+ /**
21839
+ * Theme System Error Handling
21840
+ *
21841
+ * Centralized error handling for the Atomix theme system.
21842
+ * Provides custom error classes and logging utilities.
21843
+ */
21844
+ /**
21845
+ * Theme error codes
21846
+ */
21847
+ var ThemeErrorCode, LogLevel;
21848
+
21849
+ "undefined" != typeof process && process.env, function(ThemeErrorCode) {
21850
+ /** Theme not found in registry */
21851
+ ThemeErrorCode.THEME_NOT_FOUND = "THEME_NOT_FOUND",
21852
+ /** Theme failed to load */
21853
+ ThemeErrorCode.THEME_LOAD_FAILED = "THEME_LOAD_FAILED",
21854
+ /** Theme validation failed */
21855
+ ThemeErrorCode.THEME_VALIDATION_FAILED = "THEME_VALIDATION_FAILED",
21856
+ /** Configuration loading failed */
21857
+ ThemeErrorCode.CONFIG_LOAD_FAILED = "CONFIG_LOAD_FAILED",
21858
+ /** Configuration validation failed */
21859
+ ThemeErrorCode.CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
21860
+ /** Circular dependency detected */
21861
+ ThemeErrorCode.CIRCULAR_DEPENDENCY = "CIRCULAR_DEPENDENCY",
21862
+ /** Missing dependency */
21863
+ ThemeErrorCode.MISSING_DEPENDENCY = "MISSING_DEPENDENCY",
21864
+ /** Storage operation failed */
21865
+ ThemeErrorCode.STORAGE_ERROR = "STORAGE_ERROR",
21866
+ /** Invalid theme name */
21867
+ ThemeErrorCode.INVALID_THEME_NAME = "INVALID_THEME_NAME",
21868
+ /** CSS injection failed */
21869
+ ThemeErrorCode.CSS_INJECTION_FAILED = "CSS_INJECTION_FAILED",
21870
+ /** Invalid color format */
21871
+ ThemeErrorCode.INVALID_COLOR_FORMAT = "INVALID_COLOR_FORMAT",
21872
+ /** Missing required token */
21873
+ ThemeErrorCode.MISSING_REQUIRED_TOKEN = "MISSING_REQUIRED_TOKEN",
21874
+ /** Accessibility contrast violation */
21875
+ ThemeErrorCode.CONTRAST_VIOLATION = "CONTRAST_VIOLATION",
21876
+ /** Invalid token type */
21877
+ ThemeErrorCode.INVALID_TOKEN_TYPE = "INVALID_TOKEN_TYPE",
21878
+ /** Unknown error */
21879
+ ThemeErrorCode.UNKNOWN_ERROR = "UNKNOWN_ERROR";
21880
+ }(ThemeErrorCode || (ThemeErrorCode = {}));
21252
21881
 
21253
21882
  /**
21254
- * Check if code is running in a browser environment
21883
+ * Custom error class for theme-related errors
21255
21884
  */
21256
- const isBrowser = () => "undefined" != typeof window && "undefined" != typeof document, isServer = () => !isBrowser(), sanitizePath = path => path.replace(/[<>"']/g, "").replace(/\.\./g, "").replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "") // Trim leading/trailing slashes
21885
+ class ThemeError extends Error {
21886
+ constructor(message, code = ThemeErrorCode.UNKNOWN_ERROR, context) {
21887
+ super(message), this.name = "ThemeError", this.code = code, this.context = context,
21888
+ this.timestamp = Date.now(),
21889
+ // Maintains proper stack trace for where our error was thrown (only available on V8)
21890
+ Error.captureStackTrace && Error.captureStackTrace(this, ThemeError);
21891
+ }
21892
+ /**
21893
+ * Convert error to JSON for logging
21894
+ */ toJSON() {
21895
+ return {
21896
+ name: this.name,
21897
+ message: this.message,
21898
+ code: this.code,
21899
+ context: this.context,
21900
+ timestamp: this.timestamp,
21901
+ stack: this.stack
21902
+ };
21903
+ }
21904
+ }
21905
+
21906
+ /**
21907
+ * Log level
21908
+ */ !function(LogLevel) {
21909
+ LogLevel[LogLevel.ERROR = 0] = "ERROR", LogLevel[LogLevel.WARN = 1] = "WARN", LogLevel[LogLevel.INFO = 2] = "INFO",
21910
+ LogLevel[LogLevel.DEBUG = 3] = "DEBUG";
21911
+ }(LogLevel || (LogLevel = {}));
21912
+
21913
+ /**
21914
+ * Theme Logger
21915
+ *
21916
+ * Centralized logging for the theme system.
21917
+ * Replaces console statements with structured logging.
21918
+ */
21919
+ class ThemeLogger {
21920
+ constructor(config = {}) {
21921
+ this.config = {
21922
+ level: config.level ?? ("undefined" != typeof process && "production" === process.env?.NODE_ENV ? LogLevel.WARN : LogLevel.INFO),
21923
+ enableConsole: config.enableConsole ?? !0,
21924
+ onError: config.onError,
21925
+ onWarn: config.onWarn,
21926
+ onInfo: config.onInfo,
21927
+ onDebug: config.onDebug
21928
+ };
21929
+ }
21930
+ /**
21931
+ * Log an error
21932
+ */ error(message, error, context) {
21933
+ if (this.config.level < LogLevel.ERROR) return;
21934
+ const errorObj = error instanceof Error ? error : new Error(message), themeError = error instanceof ThemeError ? error : new ThemeError(message, ThemeErrorCode.UNKNOWN_ERROR, context);
21935
+ this.config.enableConsole && console.error(`[ThemeError] ${message}`, {
21936
+ error: errorObj,
21937
+ context: {
21938
+ ...context,
21939
+ ...themeError.context
21940
+ },
21941
+ code: themeError.code
21942
+ }), this.config.onError?.(themeError, context);
21943
+ }
21944
+ /**
21945
+ * Log a warning
21946
+ */ warn(message, context) {
21947
+ this.config.level < LogLevel.WARN || (this.config.enableConsole && console.warn(`[ThemeWarning] ${message}`, context || {}),
21948
+ this.config.onWarn?.(message, context));
21949
+ }
21950
+ /**
21951
+ * Log an info message
21952
+ */ info(message, context) {
21953
+ this.config.level < LogLevel.INFO || (this.config.enableConsole && console.info(`[ThemeInfo] ${message}`, context || {}),
21954
+ this.config.onInfo?.(message, context));
21955
+ }
21956
+ /**
21957
+ * Log a debug message
21958
+ */ debug(message, context) {
21959
+ this.config.level < LogLevel.DEBUG || (this.config.enableConsole, this.config.onDebug?.(message, context));
21960
+ }
21961
+ }
21962
+
21963
+ /**
21964
+ * Default logger instance
21965
+ */ let defaultLogger = null;
21966
+
21967
+ /**
21968
+ * Get or create default logger
21969
+ */ function getLogger() {
21970
+ return defaultLogger || (defaultLogger = new ThemeLogger), defaultLogger;
21971
+ }
21972
+
21973
+ /**
21974
+ * Check if code is running in a browser environment
21975
+ */ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof document, isServer = () => !isBrowser(), sanitizePath = path => path.replace(/[<>"']/g, "").replace(/\.\./g, "").replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "") // Trim leading/trailing slashes
21257
21976
  , buildThemePath = (themeName, basePath = "/themes", useMinified = !1, cdnPath = null) => {
21258
21977
  // Validate theme name to prevent path injection
21259
21978
  if (!isValidThemeName(themeName)) throw new ThemeError(`Invalid theme name: "${themeName}". Theme names must be lowercase alphanumeric with hyphens (e.g., "my-theme").`, ThemeErrorCode.INVALID_THEME_NAME, {
@@ -21338,106 +22057,428 @@ const isBrowser = () => "undefined" != typeof window && "undefined" != typeof do
21338
22057
  /**
21339
22058
  * Check if code is running on the server (SSR)
21340
22059
  */
22060
+ // ============================================================================
22061
+ // Theme Mode Switching
22062
+ // ============================================================================
21341
22063
  /**
21342
- * Theme Utilities
22064
+ * Switch between light and dark themes
22065
+ *
22066
+ * Automatically toggles a class on the root element and persists the choice.
22067
+ *
22068
+ * @param mode - Theme mode ('light', 'dark', or 'system')
22069
+ * @param options - Configuration options
22070
+ *
22071
+ * @example
22072
+ * ```typescript
22073
+ * import { switchTheme } from '@shohojdhara/atomix/theme/utils';
22074
+ *
22075
+ * // Switch to dark mode
22076
+ * switchTheme('dark');
21343
22077
  *
21344
- * Helper utilities for working with themes, including color manipulation,
21345
- * spacing helpers, and theme value accessors.
22078
+ * // Toggle between light/dark
22079
+ * const current = getCurrentTheme();
22080
+ * switchTheme(current === 'dark' ? 'light' : 'dark');
22081
+ * ```
21346
22082
  */
22083
+ function switchTheme(mode, options = {}) {
22084
+ const {selector: selector = ":root", storageKey: storageKey = "atomix-theme", enableTransition: enableTransition = !0, transitionDuration: transitionDuration = 300} = options, resolvedMode = "system" === mode ? getSystemTheme() : mode, root = ":root" === selector ? document.documentElement : document.querySelector(selector);
22085
+ // Determine actual mode (resolve 'system')
22086
+ if (root) {
22087
+ // Add transition class if enabled
22088
+ if (enableTransition) {
22089
+ const htmlRoot = root;
22090
+ htmlRoot.style.transition = `all ${transitionDuration}ms ease-in-out`,
22091
+ // Remove transition after it completes
22092
+ setTimeout((() => {
22093
+ htmlRoot.style.transition = "";
22094
+ }), transitionDuration);
22095
+ }
22096
+ // Apply theme class
22097
+ root.classList.remove("atomix-theme-light", "atomix-theme-dark"), root.classList.add(`atomix-theme-${resolvedMode}`),
22098
+ // Set data attribute for CSS selectors
22099
+ root.setAttribute("data-theme", resolvedMode),
22100
+ // Persist choice
22101
+ persistTheme(resolvedMode, {
22102
+ storageKey: storageKey
22103
+ }),
22104
+ // Dispatch custom event for listeners
22105
+ window.dispatchEvent(new CustomEvent("atomix-theme-change", {
22106
+ detail: {
22107
+ mode: resolvedMode
22108
+ }
22109
+ }));
22110
+ }
22111
+ }
22112
+
22113
+ /**
22114
+ * Toggle between light and dark themes
22115
+ *
22116
+ * @param options - Configuration options
22117
+ * @returns The new theme mode
22118
+ *
22119
+ * @example
22120
+ * ```typescript
22121
+ * const newMode = toggleTheme();
22122
+ * console.log('Switched to:', newMode);
22123
+ * ```
22124
+ */ function toggleTheme(options = {}) {
22125
+ const next = "dark" === getCurrentTheme(options.storageKey) ? "light" : "dark";
22126
+ return switchTheme(next, options), next;
22127
+ }
22128
+
22129
+ /**
22130
+ * Get current theme mode
22131
+ *
22132
+ * @param storageKey - Storage key (default: 'atomix-theme')
22133
+ * @returns Current theme mode or 'light' if not set
22134
+ */ function getCurrentTheme(storageKey = "atomix-theme") {
22135
+ return "undefined" == typeof window ? "light" : localStorage.getItem(storageKey) || "light";
22136
+ }
22137
+
22138
+ /**
22139
+ * Get system theme preference
22140
+ *
22141
+ * @returns 'dark' if system prefers dark mode, 'light' otherwise
22142
+ */ function getSystemTheme() {
22143
+ return "undefined" == typeof window ? "light" : window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
22144
+ }
22145
+
22146
+ /**
22147
+ * Initialize theme based on saved preference or system preference
22148
+ *
22149
+ * Call this once at app startup.
22150
+ *
22151
+ * @param options - Configuration options
22152
+ * @returns The initialized theme mode
22153
+ *
22154
+ * @example
22155
+ * ```typescript
22156
+ * // In your app entry point
22157
+ * import { initializeTheme } from '@shohojdhara/atomix/theme/utils';
22158
+ *
22159
+ * const theme = initializeTheme();
22160
+ * console.log('Theme initialized:', theme);
22161
+ * ```
22162
+ */ function initializeTheme(options = {}) {
22163
+ const saved = getCurrentTheme(options.storageKey);
22164
+ // If no saved preference, use system preference
22165
+ if (!saved || "system" === saved) {
22166
+ const system = getSystemTheme();
22167
+ return switchTheme(system, options), system;
22168
+ }
22169
+ // Use saved preference
22170
+ return switchTheme(saved, options), saved;
22171
+ }
22172
+
22173
+ /**
22174
+ * Listen for system theme changes
22175
+ *
22176
+ * @param callback - Function to call when system theme changes
22177
+ * @returns Cleanup function to stop listening
22178
+ *
22179
+ * @example
22180
+ * ```typescript
22181
+ * const cleanup = listenToSystemTheme((mode) => {
22182
+ * console.log('System theme changed to:', mode);
22183
+ * switchTheme(mode);
22184
+ * });
22185
+ *
22186
+ * // Later, when component unmounts
22187
+ * cleanup();
22188
+ * ```
22189
+ */ function listenToSystemTheme(callback) {
22190
+ if ("undefined" == typeof window) return () => {};
22191
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"), handler = e => {
22192
+ callback(e.matches ? "dark" : "light");
22193
+ };
22194
+ // Modern browsers
22195
+ return mediaQuery.addEventListener ? (mediaQuery.addEventListener("change", handler),
22196
+ () => mediaQuery.removeEventListener("change", handler)) : (
22197
+ // Fallback for older browsers
22198
+ mediaQuery.addListener(handler), () => mediaQuery.removeListener(handler));
22199
+ }
22200
+
21347
22201
  // ============================================================================
21348
- // Color Manipulation Utilities
22202
+ // Theme Persistence
21349
22203
  // ============================================================================
21350
22204
  /**
21351
- * Convert hex color to RGB object
21352
- */
21353
- function hexToRgb$1(hex) {
21354
- const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
21355
- return result ? {
21356
- r: parseInt(result[1], 16),
21357
- g: parseInt(result[2], 16),
21358
- b: parseInt(result[3], 16)
21359
- } : null;
22205
+ * Save theme preference to storage
22206
+ *
22207
+ * @param mode - Theme mode to save
22208
+ * @param options - Persistence options
22209
+ */ function persistTheme(mode, options = {}) {
22210
+ if ("undefined" == typeof window) return;
22211
+ const {storageKey: storageKey = "atomix-theme", storageType: storageType = "localStorage"} = options;
22212
+ ("localStorage" === storageType ? localStorage : sessionStorage).setItem(storageKey, mode);
22213
+ }
22214
+
22215
+ /**
22216
+ * Clear saved theme preference
22217
+ *
22218
+ * @param options - Persistence options
22219
+ */ function clearThemePreference(options = {}) {
22220
+ if ("undefined" == typeof window) return;
22221
+ const {storageKey: storageKey = "atomix-theme", storageType: storageType = "localStorage"} = options;
22222
+ ("localStorage" === storageType ? localStorage : sessionStorage).removeItem(storageKey);
22223
+ }
22224
+
22225
+ // ============================================================================
22226
+ // Theme Tokens Manipulation
22227
+ // ============================================================================
22228
+ /**
22229
+ * Merge multiple token sets
22230
+ *
22231
+ * Deep merges token objects, with later tokens overriding earlier ones.
22232
+ *
22233
+ * @param tokens - Token objects to merge
22234
+ * @returns Merged tokens
22235
+ *
22236
+ * @example
22237
+ * ```typescript
22238
+ * const merged = mergeTokens(
22239
+ * baseTokens,
22240
+ * { colors: { primary: { main: '#custom' } } }
22241
+ * );
22242
+ * ```
22243
+ */ function mergeTokens(...tokens) {
22244
+ return _reduceInstanceProperty(tokens).call(tokens, ((acc, current) => deepMerge(acc, current)), {});
22245
+ }
22246
+
22247
+ /**
22248
+ * Override specific tokens
22249
+ *
22250
+ * Creates a new token object with specific overrides.
22251
+ *
22252
+ * @param base - Base tokens
22253
+ * @param overrides - Tokens to override
22254
+ * @returns New tokens with overrides applied
22255
+ *
22256
+ * @example
22257
+ * ```typescript
22258
+ * const customized = overrideTokens(defaultTokens, {
22259
+ * colors: {
22260
+ * primary: { main: '#ff0000' }
22261
+ * }
22262
+ * });
22263
+ * ```
22264
+ */ function overrideTokens(base, overrides) {
22265
+ return deepMerge({
22266
+ ...base
22267
+ }, overrides);
22268
+ }
22269
+
22270
+ /**
22271
+ * Pick specific token categories
22272
+ *
22273
+ * Extracts only the specified categories from tokens.
22274
+ *
22275
+ * @param tokens - Source tokens
22276
+ * @param categories - Categories to pick
22277
+ * @returns Tokens with only selected categories
22278
+ *
22279
+ * @example
22280
+ * ```typescript
22281
+ * const colorTokens = pickTokens(allTokens, ['colors']);
22282
+ * ```
22283
+ */ function pickTokens(tokens, categories) {
22284
+ const result = {};
22285
+ return categories.forEach((category => {
22286
+ tokens[category] && (result[category] = tokens[category]);
22287
+ })), result;
21360
22288
  }
21361
22289
 
21362
22290
  /**
21363
- * Convert RGB to hex color
22291
+ * Omit specific token categories
22292
+ *
22293
+ * Removes specified categories from tokens.
22294
+ *
22295
+ * @param tokens - Source tokens
22296
+ * @param categories - Categories to omit
22297
+ * @returns Tokens without omitted categories
22298
+ *
22299
+ * @example
22300
+ * ```typescript
22301
+ * const withoutColors = omitTokens(allTokens, ['colors']);
22302
+ * ```
22303
+ */ function omitTokens(tokens, categories) {
22304
+ const result = {
22305
+ ...tokens
22306
+ };
22307
+ return categories.forEach((category => {
22308
+ delete result[category];
22309
+ })), result;
22310
+ }
22311
+
22312
+ // ============================================================================
22313
+ // Color Utilities
22314
+ // ============================================================================
22315
+ /**
22316
+ * Convert hex color to RGB
22317
+ *
22318
+ * @param hex - Hex color (with or without #)
22319
+ * @returns RGB object { r, g, b }
22320
+ */ function hexToRgb$1(hex) {
22321
+ // Validate
22322
+ if (
22323
+ // Remove # if present
22324
+ // Handle shorthand hex
22325
+ 3 === (hex = hex.replace(/^#/, "")).length && (hex = hex.split("").map((c => c + c)).join("")),
22326
+ 6 !== hex.length) return null;
22327
+ const num = parseInt(hex, 16);
22328
+ return {
22329
+ r: num >> 16 & 255,
22330
+ g: num >> 8 & 255,
22331
+ b: 255 & num
22332
+ };
22333
+ }
22334
+
22335
+ /**
22336
+ * Convert RGB to hex
22337
+ *
22338
+ * @param r - Red (0-255)
22339
+ * @param g - Green (0-255)
22340
+ * @param b - Blue (0-255)
22341
+ * @returns Hex color with #
21364
22342
  */ function rgbToHex(r, g, b) {
21365
- const toHex = val => Math.round(Math.max(0, Math.min(255, val))).toString(16).padStart(2, "0");
21366
- return `#${toHex(r ?? 0)}${toHex(g ?? 0)}${toHex(b ?? 0)}`;
22343
+ return "#" + [ r, g, b ].map((x => {
22344
+ const hex = x.toString(16);
22345
+ return 1 === hex.length ? "0" + hex : hex;
22346
+ })).join("");
21367
22347
  }
21368
22348
 
21369
22349
  /**
21370
- * Calculate relative luminance of a color
21371
- * Used for determining contrast ratios
21372
- */ function getLuminance(color) {
21373
- const rgb = hexToRgb$1(color);
22350
+ * Calculate luminance of a color
22351
+ *
22352
+ * Used for determining contrast ratios.
22353
+ *
22354
+ * @param hex - Hex color
22355
+ * @returns Luminance value (0-1)
22356
+ */ function getLuminance(hex) {
22357
+ const rgb = hexToRgb$1(hex);
21374
22358
  if (!rgb) return 0;
21375
- const {r: r, g: g, b: b} = rgb, [rs, gs, bs] = [ r ?? 0, g ?? 0, b ?? 0 ].map((c => {
21376
- const val = c / 255;
21377
- return val <= .03928 ? val / 12.92 : Math.pow((val + .055) / 1.055, 2.4);
21378
- }));
21379
- return .2126 * (rs ?? 0) + .7152 * (gs ?? 0) + .0722 * (bs ?? 0);
22359
+ const [r, g, b] = [ rgb.r, rgb.g, rgb.b ].map((v => (v /= 255) <= .03928 ? v / 12.92 : Math.pow((v + .055) / 1.055, 2.4)));
22360
+ return .2126 * (r ?? 0) + .7152 * (g ?? 0) + .0722 * (b ?? 0);
22361
+ }
22362
+
22363
+ /**
22364
+ * Calculate contrast ratio between two colors
22365
+ *
22366
+ * @param hex1 - First hex color
22367
+ * @param hex2 - Second hex color
22368
+ * @returns Contrast ratio (1-21)
22369
+ */ function getContrastRatio(hex1, hex2) {
22370
+ const lum1 = getLuminance(hex1), lum2 = getLuminance(hex2);
22371
+ return (Math.max(lum1, lum2) + .05) / (Math.min(lum1, lum2) + .05);
21380
22372
  }
21381
22373
 
21382
22374
  /**
21383
- * Calculate contrast ratio between two colors
21384
- */ function getContrastRatio(foreground, background) {
21385
- const lumA = getLuminance(foreground), lumB = getLuminance(background);
21386
- return (Math.max(lumA, lumB) + .05) / (Math.min(lumA, lumB) + .05);
22375
+ * Check if text color passes WCAG AA standard
22376
+ *
22377
+ * @param textColor - Text color hex
22378
+ * @param backgroundColor - Background color hex
22379
+ * @param size - Font size ('small' or 'large')
22380
+ * @returns true if passes WCAG AA
22381
+ */ function isAccessible(textColor, backgroundColor, size = "small") {
22382
+ return getContrastRatio(textColor, backgroundColor) >= ("large" === size ? 3 : 4.5);
21387
22383
  }
21388
22384
 
21389
22385
  /**
21390
- * Get appropriate contrast text color (black or white) for a background color
21391
- */ function getContrastText(background, threshold = 3) {
21392
- const contrastWithWhite = getContrastRatio("#FFFFFF", background), contrastWithBlack = getContrastRatio("#000000", background);
21393
- return contrastWithWhite >= threshold ? "#FFFFFF" : contrastWithBlack >= threshold ? "#000000" : contrastWithWhite > contrastWithBlack ? "#FFFFFF" : "#000000";
22386
+ * Get appropriate text color (black or white) for a background
22387
+ *
22388
+ * @param backgroundColor - Background hex color
22389
+ * @param threshold - Contrast threshold (default: 3)
22390
+ * @returns '#000000' or '#FFFFFF'
22391
+ */ function getContrastText(backgroundColor, threshold = 3) {
22392
+ return getContrastRatio(backgroundColor, "#FFFFFF") >= threshold ? "#FFFFFF" : "#000000";
21394
22393
  }
21395
22394
 
21396
22395
  /**
21397
- * Lighten a color by a given amount
22396
+ * Lighten a color
21398
22397
  *
21399
- * @param color - Hex color string
21400
- * @param amount - Amount to lighten (0-1), default 0.2
22398
+ * @param hex - Base hex color
22399
+ * @param amount - Amount to lighten (0-1)
21401
22400
  * @returns Lightened hex color
21402
- */ function lighten(color, amount = .2) {
21403
- const rgb = hexToRgb$1(color);
21404
- if (!rgb) return color;
21405
- const {r: r, g: g, b: b} = rgb, lightenValue = val => Math.min(255, Math.round(val + (255 - val) * amount));
21406
- return rgbToHex(lightenValue(r), lightenValue(g), lightenValue(b));
22401
+ */ function lighten(hex, amount = 0) {
22402
+ const rgb = hexToRgb$1(hex);
22403
+ if (!rgb) return hex;
22404
+ // Use amount directly as factor (0-1)
22405
+ const factor = Math.max(0, Math.min(1, amount)), r = Math.round(rgb.r + (255 - rgb.r) * factor), g = Math.round(rgb.g + (255 - rgb.g) * factor), b = Math.round(rgb.b + (255 - rgb.b) * factor);
22406
+ return rgbToHex(Math.min(255, r), Math.min(255, g), Math.min(255, b));
21407
22407
  }
21408
22408
 
21409
22409
  /**
21410
- * Darken a color by a given amount
22410
+ * Darken a color
21411
22411
  *
21412
- * @param color - Hex color string
21413
- * @param amount - Amount to darken (0-1), default 0.2
22412
+ * @param hex - Base hex color
22413
+ * @param amount - Amount to darken (0-1)
21414
22414
  * @returns Darkened hex color
21415
- */ function darken(color, amount = .2) {
21416
- const rgb = hexToRgb$1(color);
21417
- if (!rgb) return color;
21418
- const {r: r, g: g, b: b} = rgb, darkenValue = val => Math.max(0, Math.round(val * (1 - amount)));
21419
- return rgbToHex(darkenValue(r), darkenValue(g), darkenValue(b));
22415
+ */ function darken(hex, amount = 0) {
22416
+ const rgb = hexToRgb$1(hex);
22417
+ if (!rgb) return hex;
22418
+ // Use amount directly as factor (0-1)
22419
+ const factor = Math.max(0, Math.min(1, amount)), r = Math.round(rgb.r * (1 - factor)), g = Math.round(rgb.g * (1 - factor)), b = Math.round(rgb.b * (1 - factor));
22420
+ return rgbToHex(Math.max(0, r), Math.max(0, g), Math.max(0, b));
21420
22421
  }
21421
22422
 
21422
22423
  /**
21423
- * Add alpha (opacity) to a color
22424
+ * Add alpha to a color
21424
22425
  *
21425
- * @param color - Hex color string
22426
+ * @param hex - Hex color
21426
22427
  * @param opacity - Opacity value (0-1)
21427
22428
  * @returns RGBA color string
21428
- */ function alpha(color, opacity) {
21429
- const rgb = hexToRgb$1(color);
21430
- if (!rgb) return color;
21431
- const {r: r, g: g, b: b} = rgb;
21432
- return `rgba(${r}, ${g}, ${b}, ${Math.max(0, Math.min(1, opacity))})`;
22429
+ */ function alpha(hex, opacity) {
22430
+ const rgb = hexToRgb$1(hex);
22431
+ if (!rgb) return hex;
22432
+ const validOpacity = Math.max(0, Math.min(1, opacity));
22433
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${validOpacity})`;
21433
22434
  }
21434
22435
 
21435
22436
  /**
21436
22437
  * Emphasize a color (lighten if dark, darken if light)
21437
22438
  *
21438
- * @param color - Hex color string
21439
- * @param coefficient - Amount to emphasize (0-1), default 0.15
22439
+ * @param hex - Hex color
22440
+ * @param amount - Amount to emphasize (0-1)
21440
22441
  * @returns Emphasized hex color
22442
+ */ function emphasize(hex, amount = .15) {
22443
+ return getLuminance(hex) > .5 ? darken(hex, amount) : lighten(hex, amount);
22444
+ }
22445
+
22446
+ /**
22447
+ * Create a spacing utility
22448
+ *
22449
+ * @param spacingInput - Spacing configuration
22450
+ * @returns Spacing function
22451
+ */ function createSpacing(spacingInput = 4) {
22452
+ return (...values) => 0 === values.length ? "0px" : "function" == typeof spacingInput ? spacingInput(...values) : values.map((value => {
22453
+ if ("number" == typeof spacingInput) return value * spacingInput + "px";
22454
+ if (Array.isArray(spacingInput)) {
22455
+ const scaled = spacingInput[value];
22456
+ return "number" == typeof scaled ? `${scaled}px` : `${value}px`;
22457
+ }
22458
+ return `${value}px`;
22459
+ })).join(" ");
22460
+ }
22461
+
22462
+ /**
22463
+ * CSS Variable Generator
22464
+ *
22465
+ * Generates CSS custom properties from theme objects and injects them into the DOM.
22466
+ *
22467
+ * **Token Naming Alignment:**
22468
+ * This generator produces CSS variables that match the SCSS token naming pattern exactly:
22469
+ * - Colors: --atomix-primary, --atomix-primary-1 through --atomix-primary-10
22470
+ * - Spacing: --atomix-spacing-1, --atomix-spacing-4, etc.
22471
+ * - Typography: --atomix-font-size-base, --atomix-font-weight-normal, etc.
22472
+ * - Shadows: --atomix-box-shadow, --atomix-box-shadow-sm, etc.
22473
+ *
22474
+ * All tokens follow the flat structure pattern used in SCSS (not nested like --atomix-palette-primary-main).
22475
+ * This ensures compatibility between SCSS themes and JavaScript themes.
22476
+ *
22477
+ * @see src/styles/03-generic/_generic.root.scss for SCSS token definitions
22478
+ */
22479
+ /**
22480
+ * Convert a nested object to flat CSS variable declarations
22481
+ * Uses iterative approach for better performance with large objects
21441
22482
  */
21442
22483
  /**
21443
22484
  * Generate a color scale from a base color (1-10 steps)
@@ -21505,18 +22546,7 @@ function generateCSSVariables(theme, options = {}) {
21505
22546
  color.dark && (vars[`${prefix}-${key}-hover`] = color.dark),
21506
22547
  // Generate semantic color variants (matches SCSS patterns)
21507
22548
  // Text emphasis: emphasized version of the color for text (--atomix-primary-text-emphasis)
21508
- vars[`${prefix}-${key}-text-emphasis`] = function(color, coefficient = .15) {
21509
- return getLuminance(color) > .5 ? darken(color, coefficient) : lighten(color, coefficient);
21510
- }
21511
- // ============================================================================
21512
- // Spacing Utilities
21513
- // ============================================================================
21514
- /**
21515
- * Create a spacing function from various input types
21516
- *
21517
- * @param spacingInput - Spacing configuration (number, array, or function), default 4
21518
- * @returns Spacing function
21519
- */ (color.main, .15),
22549
+ vars[`${prefix}-${key}-text-emphasis`] = emphasize(color.main, .15),
21520
22550
  // Background subtle: very light version for backgrounds (--atomix-primary-bg-subtle)
21521
22551
  vars[`${prefix}-${key}-bg-subtle`] = alpha(color.main, .1),
21522
22552
  // Border subtle: light version for borders (--atomix-primary-border-subtle)
@@ -21861,29 +22891,7 @@ function generateCSSVariables(theme, options = {}) {
21861
22891
  return vars[`${prefix}-focus-ring-width`] = "3px", vars[`${prefix}-focus-ring-offset`] = "2px",
21862
22892
  vars[`${prefix}-focus-ring-opacity`] = "0.25", vars;
21863
22893
  }(theme.palette, prefix)), theme.custom && Object.keys(theme.custom).length > 0) {
21864
- const customVars =
21865
- /**
21866
- * CSS Variable Generator
21867
- *
21868
- * Generates CSS custom properties from theme objects and injects them into the DOM.
21869
- *
21870
- * **Token Naming Alignment:**
21871
- * This generator produces CSS variables that match the SCSS token naming pattern exactly:
21872
- * - Colors: --atomix-primary, --atomix-primary-1 through --atomix-primary-10
21873
- * - Spacing: --atomix-spacing-1, --atomix-spacing-4, etc.
21874
- * - Typography: --atomix-font-size-base, --atomix-font-weight-normal, etc.
21875
- * - Shadows: --atomix-box-shadow, --atomix-box-shadow-sm, etc.
21876
- *
21877
- * All tokens follow the flat structure pattern used in SCSS (not nested like --atomix-palette-primary-main).
21878
- * This ensures compatibility between SCSS themes and JavaScript themes.
21879
- *
21880
- * @see src/styles/03-generic/_generic.root.scss for SCSS token definitions
21881
- */
21882
- /**
21883
- * Convert a nested object to flat CSS variable declarations
21884
- * Uses iterative approach for better performance with large objects
21885
- */
21886
- function(obj, prefix = "", result = {}) {
22894
+ const customVars = function(obj, prefix = "", result = {}) {
21887
22895
  // Use iterative approach with stack to avoid deep recursion
21888
22896
  const stack = [ {
21889
22897
  obj: obj,
@@ -22337,19 +23345,29 @@ const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme:
22337
23345
  // Check storage first
22338
23346
  if (enablePersistence && storageAdapter.isAvailable()) {
22339
23347
  const stored = storageAdapter.getItem(storageKey);
22340
- if (stored) return stored;
23348
+ if (stored) {
23349
+ // If it looks like a JSON object, parse it
23350
+ if (stored.trim().startsWith("{")) try {
23351
+ return JSON.parse(stored);
23352
+ } catch (e) {
23353
+ return logger.error("Failed to parse stored theme tokens", e), stored;
23354
+ }
23355
+ return stored;
23356
+ }
22341
23357
  }
22342
23358
  // If defaultTheme is provided, use it
22343
23359
  return null != defaultTheme ? defaultTheme : "default";
22344
23360
  // Default fallback
22345
- }), [ defaultTheme, enablePersistence, storageKey ]), [currentTheme, setCurrentTheme] = useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : "tokens-theme")), [activeTokens, setActiveTokens] = useState((() => {
22346
- // If defaultTheme is DesignTokens, validate and store them
22347
- if (defaultTheme && "string" != typeof defaultTheme) {
23361
+ }), [ defaultTheme, enablePersistence, storageKey, storageAdapter ]), [currentTheme, setCurrentTheme] = useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : "tokens-theme")), [activeTokens, setActiveTokens] = useState((() => {
23362
+ // 1. Check if initialDefaultTheme (from storage) is an object
23363
+ if (initialDefaultTheme && "string" != typeof initialDefaultTheme) {
23364
+ const {tokens: tokens, validation: validation} = validateAndMergeTokens(initialDefaultTheme);
23365
+ if (validation.valid) return tokens;
23366
+ }
23367
+ // 2. Check if defaultTheme prop is an object
23368
+ if (defaultTheme && "string" != typeof defaultTheme) {
22348
23369
  const {tokens: tokens, validation: validation} = validateAndMergeTokens(defaultTheme);
22349
- return validation.valid ? tokens : (logger.warn("Invalid default theme tokens, using defaults", {
22350
- errors: validation.errors,
22351
- warnings: validation.warnings
22352
- }), createTokens({}));
23370
+ if (validation.valid) return tokens;
22353
23371
  }
22354
23372
  return null;
22355
23373
  })), [isLoading, setIsLoading] = useState(!1), [error, setError] = useState(null), loadedThemesRef = useRef(new Set), themePromisesRef = useRef({}), abortControllerRef = useRef(null);
@@ -22361,10 +23379,14 @@ const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme:
22361
23379
  useEffect((() => {
22362
23380
  isServer() || applyThemeAttributes(String(currentTheme), dataAttribute);
22363
23381
  }), [ currentTheme, dataAttribute ]),
22364
- // Handle theme persistence
23382
+ // Handle persistence
22365
23383
  useEffect((() => {
22366
- enablePersistence && storageAdapter.isAvailable() && storageAdapter.setItem(storageKey, String(currentTheme));
22367
- }), [ currentTheme, storageKey, enablePersistence, storageAdapter ]),
23384
+ enablePersistence && storageAdapter.isAvailable() && ("tokens-theme" === currentTheme ?
23385
+ // Only persist if we have actual tokens to store
23386
+ activeTokens && storageAdapter.setItem(storageKey, JSON.stringify(activeTokens)) :
23387
+ // Persist named theme string
23388
+ storageAdapter.setItem(storageKey, String(currentTheme)));
23389
+ }), [ currentTheme, activeTokens, enablePersistence, storageKey, storageAdapter ]),
22368
23390
  // Cleanup: Remove completed promises and abort controllers on unmount
22369
23391
  useEffect((() => () => {
22370
23392
  // Cancel any in-flight theme loads
@@ -22503,20 +23525,21 @@ const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme:
22503
23525
  setIsLoading(!1);
22504
23526
  }
22505
23527
  }
22506
- }), [ themes, isThemeLoaded, handleError, basePath, useMinified, cdnPath ]), themeManager = useMemo((() => ({})), []), availableThemes = useMemo((() => Object.entries(themes).map((([name, metadata]) => ({
23528
+ }), [ themes, isThemeLoaded, handleError, basePath, useMinified, cdnPath ]), updateTheme = useCallback((async (sectionOrTokens, values) => setTheme("string" == typeof sectionOrTokens && values ? values : sectionOrTokens)), [ setTheme ]), themeManager = useMemo((() => ({})), []), availableThemes = useMemo((() => Object.entries(themes).map((([name, metadata]) => ({
22507
23529
  ...metadata,
22508
23530
  name: name
22509
23531
  })))), [ themes ]), contextValue = useMemo((() => ({
22510
23532
  theme: currentTheme,
22511
23533
  activeTokens: activeTokens,
22512
23534
  setTheme: setTheme,
23535
+ updateTheme: updateTheme,
22513
23536
  availableThemes: availableThemes,
22514
23537
  isLoading: isLoading,
22515
23538
  error: error,
22516
23539
  isThemeLoaded: isThemeLoaded,
22517
23540
  preloadTheme: preloadTheme,
22518
23541
  themeManager: themeManager
22519
- })), [ currentTheme, activeTokens, setTheme, availableThemes,
23542
+ })), [ currentTheme, activeTokens, setTheme, updateTheme, availableThemes,
22520
23543
  // Use memoized value
22521
23544
  isLoading, error, isThemeLoaded, preloadTheme, themeManager ]);
22522
23545
  // Check if theme is loaded
@@ -22570,6 +23593,7 @@ function useTheme() {
22570
23593
  theme: context.theme,
22571
23594
  activeTokens: context.activeTokens,
22572
23595
  setTheme: context.setTheme,
23596
+ updateTheme: context.updateTheme,
22573
23597
  availableThemes: context.availableThemes,
22574
23598
  isLoading: context.isLoading,
22575
23599
  error: context.error,
@@ -22805,6 +23829,389 @@ function useThemeTokens() {
22805
23829
  }
22806
23830
  }
22807
23831
 
23832
+ /**
23833
+ * useThemeSwitcher Hook
23834
+ *
23835
+ * React hook for managing theme switching with persistence and system preference detection.
23836
+ * Provides an easy-to-use API for dark/light mode toggling.
23837
+ *
23838
+ * @example
23839
+ * ```tsx
23840
+ * import { useThemeSwitcher } from '@shohojdhara/atomix/theme';
23841
+ *
23842
+ * function ThemeToggle() {
23843
+ * const { mode, toggle, setMode, isDark } = useThemeSwitcher();
23844
+ *
23845
+ * return (
23846
+ * <button onClick={toggle}>
23847
+ * {isDark ? '☀️ Light' : '🌙 Dark'}
23848
+ * </button>
23849
+ * );
23850
+ * }
23851
+ * ```
23852
+ */
23853
+ /**
23854
+ * Hook for managing theme switching
23855
+ *
23856
+ * @param options - Configuration options
23857
+ * @returns Theme switcher controls
23858
+ */ function useThemeSwitcher(options = {}) {
23859
+ const {initialMode: initialMode = "system", syncWithSystem: syncWithSystem = !1, storageKey: storageKey = "atomix-theme", enableTransition: enableTransition = !0, transitionDuration: transitionDuration = 300} = options, [mode, setModeState] = useState((() => {
23860
+ if ("undefined" == typeof window) return initialMode;
23861
+ // Check for saved preference first
23862
+ const saved = getCurrentTheme(storageKey);
23863
+ return saved && "system" !== saved ? saved : "system" === initialMode ? getSystemTheme() : initialMode;
23864
+ // Fall back to initial mode or system
23865
+ }));
23866
+ // State for current mode
23867
+ // Initialize theme on mount
23868
+ return useEffect((() => {
23869
+ "undefined" != typeof window && (
23870
+ // Initialize with proper theme application
23871
+ initializeTheme({
23872
+ storageKey: storageKey,
23873
+ enableTransition: enableTransition,
23874
+ transitionDuration: transitionDuration
23875
+ }),
23876
+ // Update state to match initialized theme
23877
+ setModeState(getCurrentTheme(storageKey)));
23878
+ }), [ storageKey, enableTransition, transitionDuration ]),
23879
+ // Listen for system theme changes if enabled
23880
+ useEffect((() => {
23881
+ if (syncWithSystem) return listenToSystemTheme((newMode => {
23882
+ setModeState(newMode), switchTheme(newMode, {
23883
+ storageKey: storageKey,
23884
+ enableTransition: enableTransition,
23885
+ transitionDuration: transitionDuration
23886
+ });
23887
+ }));
23888
+ }), [ syncWithSystem, storageKey, enableTransition, transitionDuration ]), {
23889
+ mode: mode,
23890
+ isDark: "dark" === mode,
23891
+ isLight: "light" === mode,
23892
+ toggle: useCallback((() => {
23893
+ const newMode = toggleTheme({
23894
+ storageKey: storageKey,
23895
+ enableTransition: enableTransition,
23896
+ transitionDuration: transitionDuration
23897
+ });
23898
+ return setModeState(newMode), newMode;
23899
+ }), [ storageKey, enableTransition, transitionDuration ]),
23900
+ setMode: useCallback((newMode => {
23901
+ switchTheme(newMode, {
23902
+ storageKey: storageKey,
23903
+ enableTransition: enableTransition,
23904
+ transitionDuration: transitionDuration
23905
+ }), setModeState(newMode);
23906
+ }), [ storageKey, enableTransition, transitionDuration ]),
23907
+ resetToSystem: useCallback((() => {
23908
+ const systemMode = getSystemTheme();
23909
+ switchTheme(systemMode, {
23910
+ storageKey: storageKey,
23911
+ enableTransition: enableTransition,
23912
+ transitionDuration: transitionDuration
23913
+ }), setModeState(systemMode);
23914
+ }), [ storageKey, enableTransition, transitionDuration ]),
23915
+ clearPreference: useCallback((() => {
23916
+ "undefined" != typeof window && localStorage.removeItem(storageKey);
23917
+ }), [ storageKey ])
23918
+ };
23919
+ }
23920
+
23921
+ /**
23922
+ * ThemeToggle component with multiple variants
23923
+ */ const ThemeToggle = ({className: className = "", showLabel: showLabel = !1, lightLabel: lightLabel = "Light", darkLabel: darkLabel = "Dark", iconSize: iconSize = 20, variant: variant = "icon", render: render, ariaLabel: ariaLabel = "Toggle theme", ...hookOptions}) => {
23924
+ const {mode: mode, isDark: isDark, toggle: toggle} = useThemeSwitcher(hookOptions);
23925
+ // Custom render
23926
+ return render ? jsx(Fragment, {
23927
+ children: render({
23928
+ isDark: isDark,
23929
+ toggle: toggle,
23930
+ mode: mode
23931
+ })
23932
+ }) :
23933
+ // Icon-only variant (default)
23934
+ "icon" === variant ? jsx("button", {
23935
+ onClick: toggle,
23936
+ className: `theme-toggle theme-toggle-icon ${className}`,
23937
+ "aria-label": ariaLabel,
23938
+ title: isDark ? darkLabel : lightLabel,
23939
+ style: {
23940
+ background: "none",
23941
+ border: "none",
23942
+ cursor: "pointer",
23943
+ padding: "8px",
23944
+ borderRadius: "50%",
23945
+ display: "flex",
23946
+ alignItems: "center",
23947
+ justifyContent: "center",
23948
+ transition: "all 0.3s ease-in-out"
23949
+ },
23950
+ children: isDark ? jsxs("svg", {
23951
+ width: iconSize,
23952
+ height: iconSize,
23953
+ viewBox: "0 0 24 24",
23954
+ fill: "none",
23955
+ stroke: "currentColor",
23956
+ strokeWidth: "2",
23957
+ strokeLinecap: "round",
23958
+ strokeLinejoin: "round",
23959
+ children: [ jsx("circle", {
23960
+ cx: "12",
23961
+ cy: "12",
23962
+ r: "5"
23963
+ }), jsx("line", {
23964
+ x1: "12",
23965
+ y1: "1",
23966
+ x2: "12",
23967
+ y2: "3"
23968
+ }), jsx("line", {
23969
+ x1: "12",
23970
+ y1: "21",
23971
+ x2: "12",
23972
+ y2: "23"
23973
+ }), jsx("line", {
23974
+ x1: "4.22",
23975
+ y1: "4.22",
23976
+ x2: "5.64",
23977
+ y2: "5.64"
23978
+ }), jsx("line", {
23979
+ x1: "18.36",
23980
+ y1: "18.36",
23981
+ x2: "19.78",
23982
+ y2: "19.78"
23983
+ }), jsx("line", {
23984
+ x1: "1",
23985
+ y1: "12",
23986
+ x2: "3",
23987
+ y2: "12"
23988
+ }), jsx("line", {
23989
+ x1: "21",
23990
+ y1: "12",
23991
+ x2: "23",
23992
+ y2: "12"
23993
+ }), jsx("line", {
23994
+ x1: "4.22",
23995
+ y1: "19.78",
23996
+ x2: "5.64",
23997
+ y2: "18.36"
23998
+ }), jsx("line", {
23999
+ x1: "18.36",
24000
+ y1: "5.64",
24001
+ x2: "19.78",
24002
+ y2: "4.22"
24003
+ }) ]
24004
+ }) : jsx("svg", {
24005
+ width: iconSize,
24006
+ height: iconSize,
24007
+ viewBox: "0 0 24 24",
24008
+ fill: "none",
24009
+ stroke: "currentColor",
24010
+ strokeWidth: "2",
24011
+ strokeLinecap: "round",
24012
+ strokeLinejoin: "round",
24013
+ children: jsx("path", {
24014
+ d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
24015
+ })
24016
+ })
24017
+ }) :
24018
+ // Button variant with text
24019
+ "button" === variant ? jsxs("button", {
24020
+ onClick: toggle,
24021
+ className: `theme-toggle theme-toggle-button ${className}`,
24022
+ "aria-label": ariaLabel,
24023
+ style: {
24024
+ display: "flex",
24025
+ alignItems: "center",
24026
+ gap: "8px",
24027
+ padding: "8px 16px",
24028
+ borderRadius: "8px",
24029
+ border: "1px solid currentColor",
24030
+ background: "transparent",
24031
+ color: "inherit",
24032
+ cursor: "pointer",
24033
+ fontSize: "14px",
24034
+ fontWeight: "500",
24035
+ transition: "all 0.3s ease-in-out"
24036
+ },
24037
+ children: [ isDark ? jsxs("svg", {
24038
+ width: iconSize,
24039
+ height: iconSize,
24040
+ viewBox: "0 0 24 24",
24041
+ fill: "none",
24042
+ stroke: "currentColor",
24043
+ strokeWidth: "2",
24044
+ strokeLinecap: "round",
24045
+ strokeLinejoin: "round",
24046
+ children: [ jsx("circle", {
24047
+ cx: "12",
24048
+ cy: "12",
24049
+ r: "5"
24050
+ }), jsx("line", {
24051
+ x1: "12",
24052
+ y1: "1",
24053
+ x2: "12",
24054
+ y2: "3"
24055
+ }), jsx("line", {
24056
+ x1: "12",
24057
+ y1: "21",
24058
+ x2: "12",
24059
+ y2: "23"
24060
+ }), jsx("line", {
24061
+ x1: "4.22",
24062
+ y1: "4.22",
24063
+ x2: "5.64",
24064
+ y2: "5.64"
24065
+ }), jsx("line", {
24066
+ x1: "18.36",
24067
+ y1: "18.36",
24068
+ x2: "19.78",
24069
+ y2: "19.78"
24070
+ }), jsx("line", {
24071
+ x1: "1",
24072
+ y1: "12",
24073
+ x2: "3",
24074
+ y2: "12"
24075
+ }), jsx("line", {
24076
+ x1: "21",
24077
+ y1: "12",
24078
+ x2: "23",
24079
+ y2: "12"
24080
+ }), jsx("line", {
24081
+ x1: "4.22",
24082
+ y1: "19.78",
24083
+ x2: "5.64",
24084
+ y2: "18.36"
24085
+ }), jsx("line", {
24086
+ x1: "18.36",
24087
+ y1: "5.64",
24088
+ x2: "19.78",
24089
+ y2: "4.22"
24090
+ }) ]
24091
+ }) : jsx("svg", {
24092
+ width: iconSize,
24093
+ height: iconSize,
24094
+ viewBox: "0 0 24 24",
24095
+ fill: "none",
24096
+ stroke: "currentColor",
24097
+ strokeWidth: "2",
24098
+ strokeLinecap: "round",
24099
+ strokeLinejoin: "round",
24100
+ children: jsx("path", {
24101
+ d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
24102
+ })
24103
+ }), showLabel && jsx("span", {
24104
+ children: isDark ? darkLabel : lightLabel
24105
+ }) ]
24106
+ }) :
24107
+ // Switch/toggle variant
24108
+ "switch" === variant ? jsx("div", {
24109
+ className: `theme-toggle theme-toggle-switch ${className}`,
24110
+ role: "button",
24111
+ tabIndex: 0,
24112
+ onClick: toggle,
24113
+ onKeyDown: e => "Enter" === e.key && toggle(),
24114
+ "aria-label": ariaLabel,
24115
+ style: {
24116
+ position: "relative",
24117
+ width: "56px",
24118
+ height: "28px",
24119
+ borderRadius: "14px",
24120
+ background: isDark ? "#4b5563" : "#d1d5db",
24121
+ cursor: "pointer",
24122
+ transition: "background 0.3s ease-in-out",
24123
+ display: "flex",
24124
+ alignItems: "center",
24125
+ padding: "2px"
24126
+ },
24127
+ children: jsx("div", {
24128
+ style: {
24129
+ position: "absolute",
24130
+ left: isDark ? "auto" : "2px",
24131
+ right: isDark ? "2px" : "auto",
24132
+ width: "24px",
24133
+ height: "24px",
24134
+ borderRadius: "50%",
24135
+ background: "white",
24136
+ boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)",
24137
+ transition: "all 0.3s ease-in-out",
24138
+ display: "flex",
24139
+ alignItems: "center",
24140
+ justifyContent: "center"
24141
+ },
24142
+ children: isDark ? jsx("svg", {
24143
+ width: "14",
24144
+ height: "14",
24145
+ viewBox: "0 0 24 24",
24146
+ fill: "none",
24147
+ stroke: "#4b5563",
24148
+ strokeWidth: "2",
24149
+ strokeLinecap: "round",
24150
+ strokeLinejoin: "round",
24151
+ children: jsx("path", {
24152
+ d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
24153
+ })
24154
+ }) : jsxs("svg", {
24155
+ width: "14",
24156
+ height: "14",
24157
+ viewBox: "0 0 24 24",
24158
+ fill: "none",
24159
+ stroke: "#f59e0b",
24160
+ strokeWidth: "2",
24161
+ strokeLinecap: "round",
24162
+ strokeLinejoin: "round",
24163
+ children: [ jsx("circle", {
24164
+ cx: "12",
24165
+ cy: "12",
24166
+ r: "5"
24167
+ }), jsx("line", {
24168
+ x1: "12",
24169
+ y1: "1",
24170
+ x2: "12",
24171
+ y2: "3"
24172
+ }), jsx("line", {
24173
+ x1: "12",
24174
+ y1: "21",
24175
+ x2: "12",
24176
+ y2: "23"
24177
+ }), jsx("line", {
24178
+ x1: "4.22",
24179
+ y1: "4.22",
24180
+ x2: "5.64",
24181
+ y2: "5.64"
24182
+ }), jsx("line", {
24183
+ x1: "18.36",
24184
+ y1: "18.36",
24185
+ x2: "19.78",
24186
+ y2: "19.78"
24187
+ }), jsx("line", {
24188
+ x1: "1",
24189
+ y1: "12",
24190
+ x2: "3",
24191
+ y2: "12"
24192
+ }), jsx("line", {
24193
+ x1: "21",
24194
+ y1: "12",
24195
+ x2: "23",
24196
+ y2: "12"
24197
+ }), jsx("line", {
24198
+ x1: "4.22",
24199
+ y1: "19.78",
24200
+ x2: "5.64",
24201
+ y2: "18.36"
24202
+ }), jsx("line", {
24203
+ x1: "18.36",
24204
+ y1: "5.64",
24205
+ x2: "19.78",
24206
+ y2: "4.22"
24207
+ }) ]
24208
+ })
24209
+ })
24210
+ }) : null;
24211
+ };
24212
+
24213
+ ThemeToggle.displayName = "ThemeToggle";
24214
+
22808
24215
  /**
22809
24216
  * Theme Applicator
22810
24217
  *
@@ -22817,7 +24224,8 @@ function useThemeTokens() {
22817
24224
  * Theme applicator class for runtime theme application
22818
24225
  *
22819
24226
  * Uses the unified theme system for efficient CSS variable generation and injection.
22820
- */ class ThemeApplicator {
24227
+ */
24228
+ class ThemeApplicator {
22821
24229
  constructor(root = document.documentElement) {
22822
24230
  this.styleId = "atomix-theme-applicator", this.root = root;
22823
24231
  }
@@ -23643,7 +25051,7 @@ class ThemeValidator {
23643
25051
  *
23644
25052
  * Provides detailed inspection and debugging information for themes
23645
25053
  */ const ThemeInspector = ({theme: theme, showValidation: showValidation = !0, showCSSVariables: showCSSVariables = !0, showStructure: showStructure = !0, className: className, style: style}) => {
23646
- const [activeTab, setActiveTab] = useState("overview"), [expandedSections, setExpandedSections] = useState(new Set([ "palette" ])), [searchQuery, setSearchQuery] = useState(""), [debouncedSearchQuery, setDebouncedSearchQuery] = useState(""), [copiedPath, setCopiedPath] = useState(null), searchTimeoutRef = useRef();
25054
+ const [activeTab, setActiveTab] = useState("overview"), [expandedSections, setExpandedSections] = useState(new Set([ "palette" ])), [searchQuery, setSearchQuery] = useState(""), [debouncedSearchQuery, setDebouncedSearchQuery] = useState(""), [copiedPath, setCopiedPath] = useState(null), searchTimeoutRef = useRef(void 0);
23647
25055
  // Debounce search query
23648
25056
  useEffect((() => (searchTimeoutRef.current && clearTimeout(searchTimeoutRef.current),
23649
25057
  searchTimeoutRef.current = setTimeout((() => {
@@ -24049,7 +25457,7 @@ class ThemeValidator {
24049
25457
  }) ]
24050
25458
  });
24051
25459
  }, ThemeComparator = ({themeA: themeA, themeB: themeB, showOnlyDifferences: showOnlyDifferences = !1, className: className, style: style}) => {
24052
- const [searchQuery, setSearchQuery] = useState(""), [debouncedSearchQuery, setDebouncedSearchQuery] = useState(""), [filterType, setFilterType] = useState("all"), [filterCategory, setFilterCategory] = useState("all"), searchTimeoutRef = useRef();
25460
+ const [searchQuery, setSearchQuery] = useState(""), [debouncedSearchQuery, setDebouncedSearchQuery] = useState(""), [filterType, setFilterType] = useState("all"), [filterCategory, setFilterCategory] = useState("all"), searchTimeoutRef = useRef(void 0);
24053
25461
  // Debounce search query
24054
25462
  useEffect((() => (searchTimeoutRef.current && clearTimeout(searchTimeoutRef.current),
24055
25463
  searchTimeoutRef.current = setTimeout((() => {
@@ -24556,13 +25964,13 @@ class ThemeValidator {
24556
25964
  function createPaletteColor(color) {
24557
25965
  return "string" == typeof color ? {
24558
25966
  main: color,
24559
- light: lighten(color),
24560
- dark: darken(color),
25967
+ light: lighten(color, .15),
25968
+ dark: darken(color, .15),
24561
25969
  contrastText: getContrastText(color)
24562
25970
  } : {
24563
25971
  main: color.main || "#000000",
24564
- light: color.light || lighten(color.main || "#000000"),
24565
- dark: color.dark || darken(color.main || "#000000"),
25972
+ light: color.light || lighten(color.main || "#000000", .15),
25973
+ dark: color.dark || darken(color.main || "#000000", .15),
24566
25974
  contrastText: color.contrastText || getContrastText(color.main || "#000000")
24567
25975
  };
24568
25976
  }
@@ -24597,23 +26005,19 @@ function createThemeObject(...options) {
24597
26005
  },
24598
26006
  background: {
24599
26007
  default: mergedOptions.palette?.background?.default || DEFAULT_PALETTE.background.default,
26008
+ paper: mergedOptions.palette?.background?.paper || DEFAULT_PALETTE.background.paper,
24600
26009
  subtle: mergedOptions.palette?.background?.subtle || DEFAULT_PALETTE.background.subtle
24601
26010
  },
24602
26011
  text: {
24603
26012
  primary: mergedOptions.palette?.text?.primary || DEFAULT_PALETTE.text.primary,
24604
26013
  secondary: mergedOptions.palette?.text?.secondary || DEFAULT_PALETTE.text.secondary,
24605
26014
  disabled: mergedOptions.palette?.text?.disabled || DEFAULT_PALETTE.text.disabled
24606
- }
26015
+ },
26016
+ // Spread other palette properties
26017
+ ...mergedOptions.palette
24607
26018
  }, typography = deepMerge({
24608
26019
  ...DEFAULT_TYPOGRAPHY
24609
- }, mergedOptions.typography || {}), spacing = function(spacingInput = 4) {
24610
- // If it's already a function, return it
24611
- return "function" == typeof spacingInput ? spacingInput :
24612
- // If it's a number, create a function that multiplies by that number
24613
- "number" == typeof spacingInput ? (...values) => 0 === values.length ? "0px" : values.map((value => value * spacingInput + "px")).join(" ") :
24614
- // If it's an array, use it as a scale
24615
- Array.isArray(spacingInput) ? (...values) => 0 === values.length ? "0px" : values.map((value => `${spacingInput[value] || value}px`)).join(" ") : (...values) => 0 === values.length ? "0px" : values.map((value => 4 * value + "px")).join(" ");
24616
- }(mergedOptions.spacing), breakpoints = function(breakpointsInput) {
26020
+ }, mergedOptions.typography || {}), spacing = createSpacing(mergedOptions.spacing), breakpoints = function(breakpointsInput) {
24617
26021
  const values = {
24618
26022
  xs: 0,
24619
26023
  sm: 576,
@@ -24845,7 +26249,7 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
24845
26249
  } catch (err) {
24846
26250
  setError(err instanceof Error ? err.message : "Invalid JSON");
24847
26251
  }
24848
- }), [ updateTheme ]), jsonUpdateTimeoutRef = useRef();
26252
+ }), [ updateTheme ]), jsonUpdateTimeoutRef = useRef(void 0);
24849
26253
  // Debounced JSON update to history
24850
26254
  useEffect((() => {
24851
26255
  if (!error) {
@@ -25434,48 +26838,360 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
25434
26838
  };
25435
26839
 
25436
26840
  /**
25437
- * Design Tokens Customizer Component
25438
- */
25439
- /**
25440
- * Theme Adapter
25441
- *
25442
- * Converts between Theme objects and DesignTokens.
25443
- */
25444
- /**
25445
- * Convert DesignTokens to Theme-compatible CSS variables
26841
+ * Design Tokens Customizer Component
26842
+ */
26843
+ /**
26844
+ * Theme Helper Functions
26845
+ *
26846
+ * Utility functions for working with DesignTokens
26847
+ */
26848
+ /**
26849
+ * Check if a value is DesignTokens
26850
+ *
26851
+ * Type guard to check if an object is DesignTokens format.
26852
+ *
26853
+ * @param value - Value to check
26854
+ * @returns True if value is DesignTokens
26855
+ */
26856
+ function isDesignTokens(value) {
26857
+ if (!value || "object" != typeof value) return !1;
26858
+ // DesignTokens is a flat object with string keys, no nested structures
26859
+ const obj = value;
26860
+ // Check for absence of Theme-specific properties
26861
+ if ("palette" in obj || "typography" in obj || "__isJSTheme" in obj) return !1;
26862
+ // Check if it has DesignTokens-like structure (flat string keys)
26863
+ const keys = Object.keys(obj);
26864
+ return 0 !== keys.length && keys.some((key => /^[a-z]+(-[a-z0-9]+)*$/.test(key) && "string" == typeof obj[key]));
26865
+ // Check if keys look like DesignTokens (kebab-case, no nesting)
26866
+ }
26867
+
26868
+ /**
26869
+ * Performance monitor class
26870
+ */ class PerformanceMonitor {
26871
+ /**
26872
+ * Create a new performance monitor
26873
+ *
26874
+ * @param config Configuration options
26875
+ */
26876
+ constructor(config) {
26877
+ this.frameCount = 0, this.lastSampleTime = 0, this.lastFpsUpdate = 0, this.frameTimes = [],
26878
+ this.animationFrameId = null, this.isActive = !1, this.startTime = 0, this.config = {
26879
+ fpsTarget: config?.fpsTarget ?? 60,
26880
+ sampleInterval: config?.sampleInterval ?? 500,
26881
+ onUpdate: config?.onUpdate ?? (() => {}),
26882
+ onDegraded: config?.onDegraded ?? (() => {}),
26883
+ enableMemoryMonitoring: config?.enableMemoryMonitoring ?? ("undefined" != typeof window && window.performance && window.performance.memory)
26884
+ };
26885
+ }
26886
+ /**
26887
+ * Start monitoring performance
26888
+ */ start() {
26889
+ this.isActive || (this.isActive = !0, this.frameCount = 0, this.lastSampleTime = performance.now(),
26890
+ this.lastFpsUpdate = this.lastSampleTime, this.frameTimes = [], this.startTime = this.lastSampleTime,
26891
+ this.animationFrameId = requestAnimationFrame(this.onFrame.bind(this)));
26892
+ }
26893
+ /**
26894
+ * Stop monitoring performance
26895
+ */ stop() {
26896
+ this.animationFrameId && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null),
26897
+ this.isActive = !1;
26898
+ }
26899
+ /**
26900
+ * Get current performance metrics
26901
+ */ getMetrics() {
26902
+ var _context;
26903
+ const now = performance.now(), elapsed = now - this.lastFpsUpdate, fps = elapsed > 0 ? Math.round(this.frameCount / elapsed * 1e3) : 0, avgFrameTime = this.frameTimes.length > 0 ? _reduceInstanceProperty(_context = this.frameTimes).call(_context, ((a, b) => a + b), 0) / this.frameTimes.length : 0, peakFrameTime = this.frameTimes.length > 0 ? Math.max(...this.frameTimes) : 0;
26904
+ // Get memory stats if available
26905
+ let memory;
26906
+ if (this.config.enableMemoryMonitoring) {
26907
+ const perf = window.performance;
26908
+ perf && perf.memory && (memory = {
26909
+ usedJSHeapSize: perf.memory.usedJSHeapSize,
26910
+ totalJSHeapSize: perf.memory.totalJSHeapSize,
26911
+ jsHeapSizeLimit: perf.memory.jsHeapSizeLimit
26912
+ });
26913
+ }
26914
+ return {
26915
+ fps: fps,
26916
+ frameTime: avgFrameTime,
26917
+ peakFrameTime: peakFrameTime,
26918
+ memory: memory,
26919
+ timestamp: now,
26920
+ isDegraded: fps < .7 * this.config.fpsTarget
26921
+ };
26922
+ }
26923
+ /**
26924
+ * Get the current FPS
26925
+ */ getFps() {
26926
+ return this.getMetrics().fps;
26927
+ }
26928
+ /**
26929
+ * Check if performance is degraded
26930
+ */ isPerformanceDegraded() {
26931
+ return this.getMetrics().isDegraded;
26932
+ }
26933
+ /**
26934
+ * Private method called on each animation frame
26935
+ */ onFrame(timestamp) {
26936
+ if (!this.isActive) return;
26937
+ // Calculate frame time
26938
+ const frameTime = timestamp - this.lastSampleTime;
26939
+ // Check if we need to update metrics
26940
+ if (this.frameTimes.push(frameTime),
26941
+ // Keep only the last 60 frame times for averaging
26942
+ this.frameTimes.length > 60 && this.frameTimes.shift(), this.frameCount++, this.lastSampleTime = timestamp,
26943
+ timestamp - this.lastFpsUpdate >= this.config.sampleInterval) {
26944
+ const metrics = this.getMetrics();
26945
+ // Call update callback
26946
+ this.config.onUpdate(metrics),
26947
+ // Check for degradation
26948
+ metrics.isDegraded && this.config.onDegraded(metrics),
26949
+ // Reset counters
26950
+ this.frameCount = 0, this.lastFpsUpdate = timestamp;
26951
+ }
26952
+ this.animationFrameId = requestAnimationFrame(this.onFrame.bind(this));
26953
+ }
26954
+ /**
26955
+ * Run a performance test for a specific function
26956
+ *
26957
+ * @param fn Function to test
26958
+ * @param iterations Number of iterations (default: 100)
26959
+ * @returns Average execution time in ms
26960
+ */ async testFunctionPerformance(fn, iterations = 100) {
26961
+ const times = [];
26962
+ for (let i = 0; i < iterations; i++) {
26963
+ const start = performance.now();
26964
+ fn();
26965
+ const end = performance.now();
26966
+ times.push(end - start);
26967
+ }
26968
+ return _reduceInstanceProperty(times).call(times, ((a, b) => a + b), 0) / times.length;
26969
+ }
26970
+ }
26971
+
26972
+ /**
26973
+ * Create a performance monitor instance
26974
+ *
26975
+ * @param config Configuration options
26976
+ * @returns PerformanceMonitor instance
26977
+ *
26978
+ * @example
26979
+ * ```typescript
26980
+ * import { createPerformanceMonitor } from '@shohojdhara/atomix/theme';
26981
+ *
26982
+ * const monitor = createPerformanceMonitor({
26983
+ * fpsTarget: 60,
26984
+ * onUpdate: (metrics) => console.log('FPS:', metrics.fps),
26985
+ * onDegraded: (metrics) => console.warn('Performance degraded!', metrics),
26986
+ * });
26987
+ *
26988
+ * monitor.start();
26989
+ *
26990
+ * // Later...
26991
+ * monitor.stop();
26992
+ * ```
26993
+ */ function createPerformanceMonitor(config) {
26994
+ return new PerformanceMonitor(config);
26995
+ }
26996
+
26997
+ /**
26998
+ * Hook for React components to monitor performance
26999
+ *
27000
+ * @param config Configuration options
27001
+ * @returns Performance metrics and monitor controls
27002
+ *
27003
+ * @example
27004
+ * ```typescript
27005
+ * import { usePerformanceMonitor } from '@shohojdhara/atomix/theme';
27006
+ *
27007
+ * function MyComponent() {
27008
+ * const { metrics, start, stop } = usePerformanceMonitor({ fpsTarget: 60 });
27009
+ *
27010
+ * useEffect(() => {
27011
+ * start();
27012
+ * return () => stop();
27013
+ * }, []);
27014
+ *
27015
+ * return <div>FPS: {metrics.fps}</div>;
27016
+ * }
27017
+ * ```
27018
+ */ function usePerformanceMonitor(config) {
27019
+ const [monitor] = React.useState((() => createPerformanceMonitor(config))), [metrics, setMetrics] = React.useState((() => "undefined" != typeof window ? monitor.getMetrics() : {
27020
+ fps: 0,
27021
+ frameTime: 0,
27022
+ peakFrameTime: 0,
27023
+ timestamp: 0,
27024
+ isDegraded: !1
27025
+ })), start = React.useCallback((() => {
27026
+ "undefined" != typeof window && monitor.start();
27027
+ }), [ monitor ]), stop = React.useCallback((() => {
27028
+ "undefined" != typeof window && monitor.stop();
27029
+ }), [ monitor ]);
27030
+ return React.useEffect((() => {
27031
+ if ("undefined" == typeof window) return;
27032
+ // Update metrics when monitor callbacks fire
27033
+ const originalOnUpdate = config?.onUpdate;
27034
+ return monitor.config.onUpdate = newMetrics => {
27035
+ setMetrics(newMetrics), originalOnUpdate?.(newMetrics);
27036
+ }, () => {
27037
+ monitor.stop();
27038
+ };
27039
+ }), [ monitor, config?.onUpdate ]), {
27040
+ metrics: metrics,
27041
+ start: start,
27042
+ stop: stop
27043
+ };
27044
+ }
27045
+
27046
+ /**
27047
+ * Responsive Utility for Atomix Theme System
27048
+ *
27049
+ * Provides responsive breakpoint detection and device-aware parameter scaling
27050
+ * based on configuration from the advanced optimization features.
27051
+ */
27052
+ /**
27053
+ * Responsive utility class
27054
+ */ class ResponsiveUtil {
27055
+ constructor(config) {
27056
+ this.currentDevice = "desktop", // Default
27057
+ this.resizeHandler = null, this.observer = null, this.config = config, this.currentDevice = this.getCurrentDeviceType(),
27058
+ // Set up resize listener
27059
+ this.setupResizeListener();
27060
+ }
27061
+ /**
27062
+ * Get the current device type based on viewport width
27063
+ */ getCurrentDeviceType() {
27064
+ if ("undefined" == typeof window) return "desktop";
27065
+ // SSR fallback
27066
+ const width = window.innerWidth;
27067
+ // Parse breakpoint values to numbers
27068
+ this.parsePxValue(this.config.breakpoints.mobile);
27069
+ const tabletWidth = this.parsePxValue(this.config.breakpoints.tablet), desktopWidth = this.parsePxValue(this.config.breakpoints.desktop), wideWidth = this.parsePxValue(this.config.breakpoints.wide);
27070
+ return width < tabletWidth ? "mobile" : width < desktopWidth ? "tablet" : width < wideWidth ? "desktop" : "wide";
27071
+ }
27072
+ /**
27073
+ * Get the scaling factor for the current device
27074
+ */ getCurrentScalingFactor() {
27075
+ // 'wide' devices use the same scaling as 'desktop'
27076
+ const scalingKey = "wide" === this.currentDevice ? "desktop" : this.currentDevice;
27077
+ return this.config.deviceScaling[scalingKey] || 1;
27078
+ }
27079
+ /**
27080
+ * Scale a value based on the current device's scaling factor
27081
+ */ scaleValue(value) {
27082
+ return value * this.getCurrentScalingFactor();
27083
+ }
27084
+ /**
27085
+ * Check if the current device matches a specific type
27086
+ */ isDevice(device) {
27087
+ return this.currentDevice === device;
27088
+ }
27089
+ /**
27090
+ * Check if the current device is mobile or smaller
27091
+ */ isMobileOrSmaller() {
27092
+ return "mobile" === this.currentDevice;
27093
+ }
27094
+ /**
27095
+ * Check if the current device is tablet or smaller
27096
+ */ isTabletOrSmaller() {
27097
+ return "mobile" === this.currentDevice || "tablet" === this.currentDevice;
27098
+ }
27099
+ /**
27100
+ * Check if the current device is desktop or larger
27101
+ */ isDesktopOrLarger() {
27102
+ return "desktop" === this.currentDevice || "wide" === this.currentDevice;
27103
+ }
27104
+ /**
27105
+ * Update the responsive configuration
27106
+ */ updateConfig(config) {
27107
+ this.config = config, this.currentDevice = this.getCurrentDeviceType();
27108
+ }
27109
+ /**
27110
+ * Destroy the responsive utility and clean up listeners
27111
+ */ destroy() {
27112
+ this.resizeHandler && (window.removeEventListener("resize", this.resizeHandler),
27113
+ this.resizeHandler = null), this.observer && (this.observer.disconnect(), this.observer = null);
27114
+ }
27115
+ /**
27116
+ * Parse a CSS value to pixels
27117
+ */ parsePxValue(value) {
27118
+ return value.endsWith("px") ? parseFloat(value.slice(0, -2)) :
27119
+ // For other units, we'll use a rough conversion assuming 16px base
27120
+ value.endsWith("rem") ? 16 * parseFloat(value.slice(0, -3)) : value.endsWith("em") ? 16 * parseFloat(value.slice(0, -2)) : parseFloat(value) || 0;
27121
+ }
27122
+ /**
27123
+ * Set up the resize listener
27124
+ */ setupResizeListener() {
27125
+ if ("undefined" == typeof window) return;
27126
+ // Throttled resize handler
27127
+ let resizeTimeout = null;
27128
+ const handleResize = () => {
27129
+ resizeTimeout && window.clearTimeout(resizeTimeout), resizeTimeout = window.setTimeout((() => {
27130
+ const newDeviceType = this.getCurrentDeviceType();
27131
+ newDeviceType !== this.currentDevice && (this.currentDevice = newDeviceType);
27132
+ }), 150);
27133
+ } // Throttle to 150ms
27134
+ ;
27135
+ this.resizeHandler = handleResize, window.addEventListener("resize", handleResize),
27136
+ // Also observe the document body for size changes
27137
+ "undefined" != typeof ResizeObserver && (this.observer = new ResizeObserver(handleResize),
27138
+ this.observer.observe(document.body));
27139
+ }
27140
+ }
27141
+
27142
+ /**
27143
+ * Create a responsive utility instance
25446
27144
  *
25447
- * @param tokens - DesignTokens object
25448
- * @returns CSS variables object compatible with Theme.cssVars
25449
- */
25450
- function designTokensToCSSVars(tokens) {
25451
- const cssVars = {};
25452
- return Object.entries(tokens).forEach((([key, value]) => {
25453
- void 0 !== value && (cssVars[`--atomix-${key}`] = String(value));
25454
- })), cssVars;
27145
+ * @param config Responsive configuration
27146
+ * @returns ResponsiveUtil instance
27147
+ */ function createResponsiveUtil(config) {
27148
+ return new ResponsiveUtil(config);
25455
27149
  }
25456
27150
 
25457
27151
  /**
25458
- * Theme Helper Functions
25459
- *
25460
- * Utility functions for working with DesignTokens
25461
- */
25462
- /**
25463
- * Check if a value is DesignTokens
25464
- *
25465
- * Type guard to check if an object is DesignTokens format.
27152
+ * Hook for React components to use responsive features
25466
27153
  *
25467
- * @param value - Value to check
25468
- * @returns True if value is DesignTokens
25469
- */ function isDesignTokens(value) {
25470
- if (!value || "object" != typeof value) return !1;
25471
- // DesignTokens is a flat object with string keys, no nested structures
25472
- const obj = value;
25473
- // Check for absence of Theme-specific properties
25474
- if ("palette" in obj || "typography" in obj || "__isJSTheme" in obj) return !1;
25475
- // Check if it has DesignTokens-like structure (flat string keys)
25476
- const keys = Object.keys(obj);
25477
- return 0 !== keys.length && keys.some((key => /^[a-z]+(-[a-z0-9]+)*$/.test(key) && "string" == typeof obj[key]));
25478
- // Check if keys look like DesignTokens (kebab-case, no nesting)
27154
+ * @param config Responsive configuration
27155
+ * @returns Current device type and utility functions
27156
+ */ function useResponsive(config) {
27157
+ const [util] = React.useState((() => createResponsiveUtil(config))), [deviceType, setDeviceType] = React.useState((() => "undefined" != typeof window ? util.getCurrentDeviceType() : "desktop"));
27158
+ return React.useEffect((() => {
27159
+ if ("undefined" == typeof window) return;
27160
+ const handleResize = () => {
27161
+ const newDeviceType = util.getCurrentDeviceType();
27162
+ newDeviceType !== deviceType && setDeviceType(newDeviceType);
27163
+ };
27164
+ // Update device type on mount
27165
+ return setDeviceType(util.getCurrentDeviceType()),
27166
+ // Listen for resize events
27167
+ window.addEventListener("resize", handleResize), () => {
27168
+ window.removeEventListener("resize", handleResize), util.destroy();
27169
+ };
27170
+ }), [ util, deviceType ]), "undefined" == typeof window ? {
27171
+ deviceType: "desktop",
27172
+ isMobile: !1,
27173
+ isTablet: !1,
27174
+ isDesktop: !0,
27175
+ isWide: !1,
27176
+ scaleValue: value => value,
27177
+ getCurrentDeviceType: () => "desktop",
27178
+ getCurrentScalingFactor: () => 1,
27179
+ isMobileOrSmaller: () => !1,
27180
+ isTabletOrSmaller: () => !0,
27181
+ isDesktopOrLarger: () => !0
27182
+ } : {
27183
+ deviceType: deviceType,
27184
+ isMobile: "mobile" === deviceType,
27185
+ isTablet: "tablet" === deviceType,
27186
+ isDesktop: "desktop" === deviceType,
27187
+ isWide: "wide" === deviceType,
27188
+ scaleValue: value => util.scaleValue(value),
27189
+ getCurrentDeviceType: () => util.getCurrentDeviceType(),
27190
+ getCurrentScalingFactor: () => util.getCurrentScalingFactor(),
27191
+ isMobileOrSmaller: () => util.isMobileOrSmaller(),
27192
+ isTabletOrSmaller: () => util.isTabletOrSmaller(),
27193
+ isDesktopOrLarger: () => util.isDesktopOrLarger()
27194
+ };
25479
27195
  }
25480
27196
 
25481
27197
  /**
@@ -25663,6 +27379,32 @@ class RTLManager {
25663
27379
  }
25664
27380
  }
25665
27381
 
27382
+ /**
27383
+ * Create RTL manager instance
27384
+ */ function createRTLManager(config) {
27385
+ return new RTLManager(config);
27386
+ }
27387
+
27388
+ /**
27389
+ * Check if locale is RTL
27390
+ */ function isRTLLocale(locale) {
27391
+ return RTL_LOCALES.has(locale.toLowerCase());
27392
+ }
27393
+
27394
+ /**
27395
+ * Get direction from locale
27396
+ */ function getDirectionFromLocale(locale) {
27397
+ return isRTLLocale(locale) ? "rtl" : "ltr";
27398
+ }
27399
+
27400
+ /**
27401
+ * RTL-aware CSS helper
27402
+ *
27403
+ * Returns appropriate CSS based on direction
27404
+ */ function rtlCSS(ltrCSS, rtlCSS, direction = "ltr") {
27405
+ return "rtl" === direction ? rtlCSS : ltrCSS;
27406
+ }
27407
+
25666
27408
  /**
25667
27409
  * Theme System Exports
25668
27410
  *
@@ -25685,8 +27427,6 @@ class RTLManager {
25685
27427
  // ============================================================================
25686
27428
  // Core Theme Functions
25687
27429
  // ============================================================================
25688
- // Create theme CSS from DesignTokens
25689
- // File saving utilities removed to prevent bundling Node.js modules in browser
25690
27430
  /**
25691
27431
  * Inject theme CSS into DOM
25692
27432
  */ function injectTheme(css, id = "atomix-theme") {
@@ -25699,7 +27439,114 @@ class RTLManager {
25699
27439
  removeCSS(id);
25700
27440
  }
25701
27441
 
25702
- const themeImport = Object.freeze( Object.defineProperty({
27442
+ /**
27443
+ * Main theme module interface
27444
+ */ const index = {
27445
+ // Core
27446
+ createTheme: createTheme,
27447
+ injectTheme: injectTheme,
27448
+ removeTheme: removeTheme,
27449
+ // Context and Provider
27450
+ ThemeProvider: ThemeProvider,
27451
+ useTheme: useTheme,
27452
+ useThemeTokens: useThemeTokens,
27453
+ ThemeContext: ThemeContext,
27454
+ ThemeErrorBoundary: ThemeErrorBoundary,
27455
+ // Adapters
27456
+ configToTokens: configToTokens,
27457
+ designTokensToCSSVars: designTokensToCSSVars,
27458
+ // Theme Utils
27459
+ switchTheme: switchTheme,
27460
+ toggleTheme: toggleTheme,
27461
+ getCurrentTheme: getCurrentTheme,
27462
+ getSystemTheme: getSystemTheme,
27463
+ initializeTheme: initializeTheme,
27464
+ listenToSystemTheme: listenToSystemTheme,
27465
+ persistTheme: persistTheme,
27466
+ clearThemePreference: clearThemePreference,
27467
+ // Token Manipulation
27468
+ mergeTokens: mergeTokens,
27469
+ overrideTokens: overrideTokens,
27470
+ pickTokens: pickTokens,
27471
+ omitTokens: omitTokens,
27472
+ // Color Utilities
27473
+ hexToRgb: hexToRgb$1,
27474
+ rgbToHex: rgbToHex,
27475
+ getLuminance: getLuminance,
27476
+ getContrastRatio: getContrastRatio,
27477
+ isAccessible: isAccessible,
27478
+ getContrastText: getContrastText,
27479
+ lighten: lighten,
27480
+ darken: darken,
27481
+ alpha: alpha,
27482
+ emphasize: emphasize,
27483
+ createSpacing: createSpacing,
27484
+ // Performance utilities
27485
+ createPerformanceMonitor: createPerformanceMonitor,
27486
+ usePerformanceMonitor: usePerformanceMonitor,
27487
+ // Responsive utilities
27488
+ createResponsiveUtil: createResponsiveUtil,
27489
+ useResponsive: useResponsive,
27490
+ // Components
27491
+ ThemeToggle: ThemeToggle,
27492
+ ThemeApplicator: ThemeApplicator,
27493
+ applyTheme: applyTheme,
27494
+ getThemeApplicator: getThemeApplicator,
27495
+ // Registry
27496
+ createThemeRegistry: createThemeRegistry,
27497
+ registerTheme: registerTheme,
27498
+ unregisterTheme: unregisterTheme,
27499
+ hasTheme: hasTheme,
27500
+ getTheme: getTheme,
27501
+ getAllThemes: getAllThemes,
27502
+ getThemeIds: getThemeIds,
27503
+ clearThemes: clearThemes,
27504
+ getThemeCount: getThemeCount,
27505
+ // Composition
27506
+ deepMerge: deepMerge,
27507
+ mergeTheme: mergeTheme,
27508
+ extendTheme: extendTheme,
27509
+ // Tokens
27510
+ createTokens: createTokens,
27511
+ defaultTokens: defaultTokens,
27512
+ // Generators
27513
+ generateCSSVariables: generateCSSVariables$1,
27514
+ generateCSSVariablesForSelector: generateCSSVariablesForSelector,
27515
+ // Naming
27516
+ generateClassName: generateClassName,
27517
+ generateCSSVariableName: generateCSSVariableName,
27518
+ normalizeThemeTokens: normalizeThemeTokens,
27519
+ camelToKebab: camelToKebab,
27520
+ themePropertyToCSSVar: themePropertyToCSSVar,
27521
+ // Component Theming
27522
+ getComponentThemeValue: getComponentThemeValue,
27523
+ generateComponentCSSVars: generateComponentCSSVars,
27524
+ applyComponentTheme: applyComponentTheme,
27525
+ useComponentTheme: useComponentTheme,
27526
+ // Hooks
27527
+ useThemeSwitcher: useThemeSwitcher,
27528
+ // Helpers
27529
+ isDesignTokens: isDesignTokens,
27530
+ // CSS Variable Mapper
27531
+ mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
27532
+ applyCSSVariables: applyCSSVariables,
27533
+ removeCSSVariables: removeCSSVariables,
27534
+ getCSSVariable: getCSSVariable,
27535
+ cssVarsToStyle: cssVarsToStyle,
27536
+ mergeCSSVars: mergeCSSVars,
27537
+ isValidCSSVariableName: isValidCSSVariableName,
27538
+ extractComponentName: extractComponentName,
27539
+ // Injection Utils
27540
+ injectCSS: injectCSS$1,
27541
+ removeCSS: removeCSS,
27542
+ isCSSInjected: isCSSInjected,
27543
+ // I18n
27544
+ RTLManager: RTLManager,
27545
+ createRTLManager: createRTLManager,
27546
+ isRTLLocale: isRTLLocale,
27547
+ getDirectionFromLocale: getDirectionFromLocale,
27548
+ rtlCSS: rtlCSS
27549
+ }, themeImport = Object.freeze( Object.defineProperty({
25703
27550
  __proto__: null,
25704
27551
  DesignTokensCustomizer: DesignTokensCustomizer,
25705
27552
  RTLManager: RTLManager,
@@ -25711,19 +27558,30 @@ const themeImport = Object.freeze( Object.defineProperty({
25711
27558
  ThemeLiveEditor: ThemeLiveEditor,
25712
27559
  ThemePreview: ThemePreview,
25713
27560
  ThemeProvider: ThemeProvider,
27561
+ ThemeToggle: ThemeToggle,
25714
27562
  ThemeValidator: ThemeValidator,
27563
+ alpha: alpha,
25715
27564
  applyCSSVariables: applyCSSVariables,
25716
27565
  applyComponentTheme: applyComponentTheme,
25717
27566
  applyTheme: applyTheme,
25718
27567
  camelToKebab: camelToKebab,
27568
+ clearThemePreference: clearThemePreference,
25719
27569
  clearThemes: clearThemes,
27570
+ configToTokens: configToTokens,
27571
+ createPerformanceMonitor: createPerformanceMonitor,
27572
+ createRTLManager: createRTLManager,
27573
+ createResponsiveUtil: createResponsiveUtil,
27574
+ createSpacing: createSpacing,
25720
27575
  createTheme: createTheme,
25721
27576
  createThemeRegistry: createThemeRegistry,
25722
27577
  createTokens: createTokens,
25723
27578
  cssVarsToStyle: cssVarsToStyle,
27579
+ darken: darken,
25724
27580
  deepMerge: deepMerge,
27581
+ default: index,
25725
27582
  defaultTokens: defaultTokens,
25726
27583
  designTokensToCSSVars: designTokensToCSSVars,
27584
+ emphasize: emphasize,
25727
27585
  extendTheme: extendTheme,
25728
27586
  extractComponentName: extractComponentName,
25729
27587
  generateCSSVariableName: generateCSSVariableName,
@@ -25734,29 +27592,53 @@ const themeImport = Object.freeze( Object.defineProperty({
25734
27592
  getAllThemes: getAllThemes,
25735
27593
  getCSSVariable: getCSSVariable,
25736
27594
  getComponentThemeValue: getComponentThemeValue,
27595
+ getContrastRatio: getContrastRatio,
27596
+ getContrastText: getContrastText,
27597
+ getCurrentTheme: getCurrentTheme,
27598
+ getDirectionFromLocale: getDirectionFromLocale,
27599
+ getLuminance: getLuminance,
27600
+ getSystemTheme: getSystemTheme,
25737
27601
  getTheme: getTheme,
25738
27602
  getThemeApplicator: getThemeApplicator,
25739
27603
  getThemeCount: getThemeCount,
25740
27604
  getThemeIds: getThemeIds,
25741
27605
  hasTheme: hasTheme,
27606
+ hexToRgb: hexToRgb$1,
27607
+ initializeTheme: initializeTheme,
25742
27608
  injectCSS: injectCSS$1,
25743
27609
  injectTheme: injectTheme,
27610
+ isAccessible: isAccessible,
25744
27611
  isCSSInjected: isCSSInjected,
25745
27612
  isDesignTokens: isDesignTokens,
27613
+ isRTLLocale: isRTLLocale,
25746
27614
  isValidCSSVariableName: isValidCSSVariableName,
27615
+ lighten: lighten,
27616
+ listenToSystemTheme: listenToSystemTheme,
25747
27617
  mapSCSSTokensToCSSVars: mapSCSSTokensToCSSVars,
25748
27618
  mergeCSSVars: mergeCSSVars,
25749
27619
  mergeTheme: mergeTheme,
27620
+ mergeTokens: mergeTokens,
25750
27621
  normalizeThemeTokens: normalizeThemeTokens,
27622
+ omitTokens: omitTokens,
27623
+ overrideTokens: overrideTokens,
27624
+ persistTheme: persistTheme,
27625
+ pickTokens: pickTokens,
25751
27626
  registerTheme: registerTheme,
25752
27627
  removeCSS: removeCSS,
25753
27628
  removeCSSVariables: removeCSSVariables,
25754
27629
  removeTheme: removeTheme,
27630
+ rgbToHex: rgbToHex,
27631
+ rtlCSS: rtlCSS,
27632
+ switchTheme: switchTheme,
25755
27633
  themePropertyToCSSVar: themePropertyToCSSVar,
27634
+ toggleTheme: toggleTheme,
25756
27635
  unregisterTheme: unregisterTheme,
25757
27636
  useComponentTheme: useComponentTheme,
25758
27637
  useHistory: useHistory,
27638
+ usePerformanceMonitor: usePerformanceMonitor,
27639
+ useResponsive: useResponsive,
25759
27640
  useTheme: useTheme,
27641
+ useThemeSwitcher: useThemeSwitcher,
25760
27642
  useThemeTokens: useThemeTokens
25761
27643
  }, Symbol.toStringTag, {
25762
27644
  value: "Module"
@@ -26018,15 +27900,6 @@ const themeImport = Object.freeze( Object.defineProperty({
26018
27900
  Radio: RADIO_CSS_VARS
26019
27901
  };
26020
27902
 
26021
- /**
26022
- * CSS Variables Constants
26023
- *
26024
- * Comprehensive CSS custom property definitions for all components.
26025
- * These provide type-safe access to component styling variables.
26026
- */
26027
- /**
26028
- * Button CSS Variables
26029
- */
26030
27903
  /**
26031
27904
  * Get CSS variables for a component
26032
27905
  */
@@ -26052,97 +27925,6 @@ function getComponentCSSVars(component) {
26052
27925
  } : base : override;
26053
27926
  }
26054
27927
 
26055
- /**
26056
- * Render a slot with the given props
26057
- *
26058
- * Priority order:
26059
- * 1. render function
26060
- * 2. component
26061
- * 3. children
26062
- * 4. fallback
26063
- *
26064
- * @example
26065
- * renderSlot(
26066
- * { render: (props) => <CustomButton {...props} /> },
26067
- * { onClick: handleClick, children: 'Click me' }
26068
- * )
26069
- */ function renderSlot(slot, props, fallback) {
26070
- // No slot provided, use fallback
26071
- if (!slot) return fallback;
26072
- // Slot is a plain React node
26073
- if ( React.isValidElement(slot) || "string" == typeof slot || "number" == typeof slot) return slot;
26074
- // Slot is an object with rendering options
26075
- if ("object" == typeof slot && null !== slot) {
26076
- const slotObj = slot;
26077
- // Priority 1: render function
26078
- if (slotObj.render && "function" == typeof slotObj.render) return slotObj.render(props);
26079
- // Priority 2: component
26080
- if (slotObj.component) {
26081
- const Component = slotObj.component;
26082
- return jsx(Component, {
26083
- ...props
26084
- });
26085
- }
26086
- // Priority 3: children
26087
- if (void 0 !== slotObj.children) return slotObj.children;
26088
- }
26089
- // Fallback
26090
- return fallback;
26091
- }
26092
-
26093
- /**
26094
- * Check if a value is a slot configuration
26095
- */ function isSlot(value) {
26096
- return "object" == typeof value && null !== value && ("render" in value || "component" in value || "children" in value);
26097
- }
26098
-
26099
- /**
26100
- * Merge multiple slot configurations
26101
- * Later slots override earlier ones
26102
- */ function mergeSlots(...slots) {
26103
- const filtered = slots.filter((s => void 0 !== s));
26104
- if (0 !== filtered.length) return 1 === filtered.length ? filtered[0] : _reduceInstanceProperty(filtered).call(filtered, ((acc, slot) => ({
26105
- ...acc,
26106
- ...slot
26107
- })));
26108
- }
26109
-
26110
- /**
26111
- * Create a slot wrapper component
26112
- *
26113
- * @example
26114
- * const ButtonSlot = createSlotComponent<ButtonSlotProps>('button')
26115
- *
26116
- * <ButtonSlot slot={customSlot} {...props}>
26117
- * Default content
26118
- * </ButtonSlot>
26119
- */ function createSlotComponent(defaultElement = "div") {
26120
- return function({slot: slot, children: children, ...props}) {
26121
- const slotProps = props;
26122
- return slot ? jsx(Fragment, {
26123
- children: renderSlot(slot, slotProps, children)
26124
- }) : jsx(defaultElement, "string" == typeof defaultElement ? {
26125
- ...props,
26126
- children: children
26127
- } : {
26128
- ...slotProps,
26129
- children: children
26130
- });
26131
- };
26132
- }
26133
-
26134
- /**
26135
- * Utility to create typed slot props
26136
- */ function createSlotProps(props) {
26137
- return props;
26138
- }
26139
-
26140
- /**
26141
- * Hook to manage slot rendering
26142
- */ function useSlot(slot, props, fallback) {
26143
- return React.useMemo((() => renderSlot(slot, props, fallback)), [ slot, props, fallback ]);
26144
- }
26145
-
26146
27928
  /**
26147
27929
  * Hook to merge theme overrides with component props
26148
27930
  *
@@ -26210,59 +27992,174 @@ function getComponentCSSVars(component) {
26210
27992
  }
26211
27993
 
26212
27994
  /**
26213
- * Atomix Configuration System
27995
+ * Configuration Types
27996
+ *
27997
+ * Type definitions for the Atomix configuration system.
27998
+ */
27999
+ /**
28000
+ * Helper function to define Atomix configuration with type safety
28001
+ */ function defineConfig(config) {
28002
+ return config;
28003
+ }
28004
+
28005
+ /**
28006
+ * Configuration Validator
26214
28007
  *
26215
- * Tailwind-like configuration for customizing the Atomix Design System.
28008
+ * Provides detailed validation and feedback for Atomix configurations,
28009
+ * especially for advanced features (Phases 2, 3, and 4).
28010
+ */
28011
+ /**
28012
+ * Validate an Atomix configuration with detailed feedback
26216
28013
  *
26217
- * External developers can create `atomix.config.ts` in their project root
26218
- * to customize design tokens, similar to Tailwind's tailwind.config.js
28014
+ * @param config - The configuration to validate
28015
+ * @param options - Validation options
28016
+ * @returns Detailed validation result
26219
28017
  *
26220
28018
  * @example
26221
28019
  * ```typescript
26222
- * // atomix.config.ts (in your project)
26223
- * import { defineConfig } from '@shohojdhara/atomix/config';
28020
+ * import { validateConfiguration } from '@shohojdhara/atomix/config';
26224
28021
  *
26225
- * export default defineConfig({
26226
- * theme: {
26227
- * extend: {
26228
- * colors: {
26229
- * primary: { main: '#7AFFD7' },
26230
- * },
26231
- * },
26232
- * },
26233
- * });
28022
+ * const config = { /* your config *\/ };
28023
+ * const result = validateConfiguration(config);
28024
+ *
28025
+ * if (!result.isValid) {
28026
+ * console.warn('Warnings:', result.warnings);
28027
+ * console.info('Suggestions:', result.suggestions);
28028
+ * }
26234
28029
  * ```
28030
+ */ function validateConfiguration(config, options) {
28031
+ const {performanceAnalysis: performanceAnalysis = !0, compatibilityReport: compatibilityReport = !0} = options || {}, warnings = [], suggestions = [];
28032
+ let performanceImpact = "low";
28033
+ // Use the existing validation
28034
+ const baseWarnings = validateConfig$1(config);
28035
+ warnings.push(...baseWarnings),
28036
+ // Analyze advanced features for performance impact
28037
+ performanceAnalysis && (performanceImpact =
28038
+ /**
28039
+ * Analyze the performance impact of a configuration
26235
28040
  */
28041
+ function(config) {
28042
+ let impactScore = 0;
28043
+ // Analyze interactive effects
28044
+ if (config.interactiveEffects) {
28045
+ const ie = config.interactiveEffects;
28046
+ ie.vortex?.enabled && (impactScore += 2), ie.chromaticAberration?.enabled && (impactScore += 1),
28047
+ ie.mouseInteraction?.trailEffect && (impactScore += 1), ie.mouseInteraction?.pressureSensitivity && (impactScore += 1);
28048
+ }
28049
+ // Analyze visual polish effects
28050
+ if (config.visualPolish) {
28051
+ const vp = config.visualPolish;
28052
+ vp.borders?.iridescentGlow && (impactScore += 1), vp.borders?.shimmerEffect && (impactScore += 1),
28053
+ vp.contentAwareBlur?.enabled && (impactScore += 2), vp.holographicEffects?.enabled && (impactScore += 2),
28054
+ vp.holographicEffects?.scanlineAnimation && (impactScore += 1), vp.holographicEffects?.dataStream && (impactScore += 1),
28055
+ vp.holographicEffects?.pulseRings && (impactScore += 1);
28056
+ }
28057
+ // Analyze optimization settings
28058
+ return config.optimization?.autoScaling?.enabled && (impactScore -= 1),
28059
+ impactScore >= 6 ? "high" : impactScore >= 3 ? "medium" : "low";
28060
+ }
28061
+ /**
28062
+ * Generate suggestions based on the configuration
28063
+ */ (config)),
28064
+ // Generate suggestions based on configuration
28065
+ function(config, suggestions) {
28066
+ // Suggest enabling performance optimizations if heavy effects are used
28067
+ (config.interactiveEffects || config.visualPolish?.holographicEffects?.enabled) && (config.optimization?.autoScaling?.enabled || suggestions.push("Consider enabling auto-scaling in optimization settings to adjust effects based on device performance: optimization.autoScaling.enabled = true"),
28068
+ config.optimization?.performance?.fpsTarget || suggestions.push("Set a target FPS in optimization.performance.fpsTarget to ensure smooth performance when using interactive effects")),
28069
+ // Suggest responsive breakpoints if optimization is partially configured
28070
+ config.optimization && !config.optimization.responsive && suggestions.push("Consider adding responsive breakpoints in optimization.responsive.breakpoints to adapt advanced effects based on device type"),
28071
+ // Suggest disabling heavy effects on lower-end devices
28072
+ config.visualPolish?.holographicEffects?.enabled && suggestions.push("For better performance on lower-end devices, consider conditionally disabling holographic effects based on device capabilities"),
28073
+ // Suggest using content-aware blur with performance considerations
28074
+ config.visualPolish?.contentAwareBlur?.enabled && suggestions.push("Content-aware blur can be expensive; consider setting a maximum blur radius or using simpler blur techniques for mobile devices"),
28075
+ // Suggest using chromatic aberration适度
28076
+ config.interactiveEffects?.chromaticAberration?.enabled && (config.interactiveEffects.chromaticAberration.redShift && Math.abs(config.interactiveEffects.chromaticAberration.redShift) > .05 && suggestions.push("High chromatic aberration red shift values (>0.05) may cause discomfort for some users; consider reducing to improve accessibility"),
28077
+ config.interactiveEffects.chromaticAberration.blueShift && Math.abs(config.interactiveEffects.chromaticAberration.blueShift) > .05 && suggestions.push("High chromatic aberration blue shift values (>0.05) may cause discomfort for some users; consider reducing to improve accessibility"));
28078
+ }
28079
+ /**
28080
+ * Generate a compatibility report for the configuration
28081
+ */ (config, suggestions);
28082
+ // Determine overall validity
28083
+ const isValid = 0 === warnings.length, compatibility = compatibilityReport ? function(config) {
28084
+ return {
28085
+ browsers: !(config.visualPolish?.holographicEffects?.enabled || config.visualPolish?.contentAwareBlur?.enabled || config.interactiveEffects?.vortex?.enabled || config.interactiveEffects?.chromaticAberration?.enabled),
28086
+ // May have issues on older browsers
28087
+ ssr: !0,
28088
+ // Works fine with SSR
28089
+ frameworks: [ "react", "vue", "angular", "svelte", "vanillajs" ]
28090
+ };
28091
+ }
28092
+ /**
28093
+ * Print a detailed configuration report to the console
28094
+ *
28095
+ * @param config - The configuration to analyze
28096
+ * @param title - Optional title for the report
28097
+ *
28098
+ * @example
28099
+ * ```typescript
28100
+ * import { printConfigReport } from '@shohojdhara/atomix/config';
28101
+ *
28102
+ * const config = { /* your config *\/ };
28103
+ * printConfigReport(config, 'My Application Config');
28104
+ * ```
28105
+ */ (config) : {
28106
+ browsers: !0,
28107
+ ssr: !0,
28108
+ frameworks: [ "react", "vue", "angular", "svelte", "vanillajs" ]
28109
+ };
28110
+ // Generate compatibility report
28111
+ return {
28112
+ isValid: isValid,
28113
+ warnings: warnings,
28114
+ suggestions: suggestions,
28115
+ performanceImpact: performanceImpact,
28116
+ compatibility: compatibility
28117
+ };
28118
+ }
28119
+
28120
+ function printConfigReport(config, title) {
28121
+ const result = validateConfiguration(config);
28122
+ result.warnings.length > 0 && result.warnings.forEach((warning => {})), result.suggestions.length > 0 && result.suggestions.forEach((suggestion => {}));
28123
+ const featuresDetected = [];
28124
+ config.interactiveEffects && featuresDetected.push("Interactive Effects"), config.optimization && featuresDetected.push("Optimization"),
28125
+ config.visualPolish && featuresDetected.push("Visual Polish"), config.ai && featuresDetected.push("AI Integration"),
28126
+ config.tokenEngine && featuresDetected.push("Token Engine"), config.generator && featuresDetected.push("Component Generator"),
28127
+ featuresDetected.length > 0 && featuresDetected.forEach((feature => {}));
28128
+ }
28129
+
26236
28130
  /**
26237
- * Helper function to define Atomix configuration with type safety
28131
+ * Public API for loading and managing Atomix configuration
26238
28132
  *
26239
- * @param config - Atomix configuration object
26240
- * @returns The configuration object
28133
+ * This module provides the public-facing API for configuration loading
28134
+ * in external projects.
26241
28135
  */
26242
28136
  /**
26243
- * Helper function to define Atomix configuration with type safety
28137
+ * Load Atomix configuration from an external project.
26244
28138
  *
26245
- * Similar to Tailwind's defineConfig, provides autocomplete and type checking.
26246
- *
26247
- * @param config - Atomix configuration object
26248
- * @returns The configuration object
28139
+ * @param options - Loading options
28140
+ * @returns The loaded configuration
26249
28141
  *
26250
28142
  * @example
26251
28143
  * ```typescript
26252
- * import { defineConfig } from '@shohojdhara/atomix/config';
28144
+ * import { loadConfig } from '@shohojdhara/atomix/config';
26253
28145
  *
26254
- * export default defineConfig({
26255
- * theme: {
26256
- * extend: {
26257
- * colors: {
26258
- * primary: { main: '#7AFFD7' },
26259
- * },
26260
- * },
26261
- * },
26262
- * });
28146
+ * const config = loadConfig();
28147
+ * console.log(config.prefix); // 'atomix' or user's custom prefix
26263
28148
  * ```
26264
- */ function defineConfig(config) {
26265
- return config;
28149
+ */ function loadConfig(options) {
28150
+ return loadAtomixConfig({
28151
+ configPath: options?.configPath,
28152
+ required: options?.required ?? !1
28153
+ });
28154
+ }
28155
+
28156
+ /**
28157
+ * Validate Atomix configuration structure.
28158
+ *
28159
+ * @param config - Configuration object to validate
28160
+ * @returns Array of validation warnings (empty if valid)
28161
+ */ function validateConfig(config) {
28162
+ return validateConfig$1(config);
26266
28163
  }
26267
28164
 
26268
28165
  // Import and re-export as namespaces with proper typing
@@ -26411,5 +28308,5 @@ const atomix = {
26411
28308
  types: types
26412
28309
  };
26413
28310
 
26414
- export { ACCORDION, ATOMIX_GLASS, AVATAR, AVATAR_GROUP, Accordion, AreaChart, AtomixGlass, AtomixLogo, Avatar, AvatarGroup, BADGE, BADGE_CSS_VARS, BALANCED_PRESET, BLOCK, BREADCRUMB, BUTTON, BUTTON_CSS_VARS, BUTTON_GROUP, Badge, BarChart, Block, Breadcrumb, BubbleChart, Button, ButtonGroup, CALLOUT, CARD, CARD_CSS_VARS, CHART, CHECKBOX_CSS_VARS, CLASS_PREFIX, CODE_SNIPPET, COMPONENT_CSS_VARS, COUNTDOWN, Callout, CandlestickChart, Card, Chart, ChartRenderer, Checkbox, ColorModeToggle, Container, Countdown, DATA_TABLE_CLASSES, DATA_TABLE_SELECTORS, DATEPICKER, DEFAULT_ATOMIX_FONTS, DEFAULT_BREAKPOINTS, DROPDOWN, DROPDOWN_CSS_VARS, DataTable, DatePicker, DesignTokensCustomizer, DeviceDetector, DonutChart, Dropdown, EDGE_PANEL, EdgePanel, ElevationCard, FOOTER, FORM, FORM_GROUP, Footer, FooterLink, FooterSection, FooterSocialLink, Form, FormGroup, FunnelChart, GaugeChart, Grid, GridCol, HERO, HeatmapChart, Hero, INPUT, INPUT_CSS_VARS, Icon, Input, LIST, LIST_GROUP, LineChart, List, ListGroup, MESSAGES, MOBILE_OPTIMIZED_BREAKPOINTS, MODAL, MODAL_CSS_VARS, MasonryGrid, MasonryGridItem, MegaMenu, MegaMenuColumn, MegaMenuLink, Menu, MenuDivider, MenuItem, Messages, Modal, MultiAxisChart, NAV, NAVBAR, Nav, NavDropdown, NavItem, Navbar, PAGINATION_DEFAULTS, PERFORMANCE_PRESET, PHOTOVIEWER, POPOVER, PROGRESS, PROGRESS_CSS_VARS, Pagination, PerformanceOverlay, PhotoViewer, PieChart, Popover, ProductReview, Progress, QUALITY_PRESET, RADIO, RADIO_CSS_VARS, RATING, RIVER, RTLManager, RadarChart, Radio, Rating, River, Row, SECTION_INTRO, SELECT, SIDE_MENU, SIZES, SLIDER, SPINNER, STEPS, ScatterChart, SectionIntro, Select, SideMenu, SideMenuItem, SideMenuList, Slider, Spinner, Steps, TAB, TABS_CSS_VARS, TESTIMONIAL, TEXTAREA, THEME_COLORS, THEME_NAMING, TODO, TOGGLE, TOOLTIP, TOOLTIP_CSS_VARS, TYPEDBUTTON, Tabs, Testimonial, Textarea, ThemeApplicator, ThemeComparator, ThemeContext, ThemeErrorBoundary, ThemeInspector, ThemeLiveEditor, ThemePreview, ThemeProvider, ThemeValidator, Todo, Toggle, Tooltip, TreemapChart, UPLOAD, Upload, VIDEO_PLAYER, VideoPlayer, WaterfallChart, applyCSSVariables, applyCSSVarsToStyle, applyComponentTheme, applyPartStyles, applyTheme, camelToKebab, clearThemes, composables, constants, createBreakpoints$1 as createBreakpoints, createCSSVarStyle, createDarkVariant, createDebugAttrs, createFontPreloadLink, createPartProps, createSlotComponent, createSlotProps, createTheme, createThemeRegistry, createTokens, cssVarsToStyle, deepMerge, atomix as default, defaultTokens, defineConfig, designTokensToCSSVars, exportTheme, extendTheme, extractComponentName, extractYouTubeId, generateCSSVariableName, generateCSSVariables$1 as generateCSSVariables, generateCSSVariablesForSelector, generateClassName, generateComponentCSSVars, generateFontPreloadTags, generateUUID, getAllThemes, getCSSVariable, getComponentCSSVars, getComponentThemeValue, getDefaultBreakpoints, getDevicePreset, getMobileOptimizedParams, getPartStyles, getQualityMultipliers, getTheme, getThemeApplicator, getThemeCount, getThemeIds, getThemeMetadata, hasCustomization, hasTheme, importTheme, injectCSS$1 as injectCSS, injectTheme, isCSSInjected, isDesignTokens, isSlot, isValidCSSVariableName, isYouTubeUrl, mapSCSSTokensToCSSVars, mergeCSSVars, mergeClassNames, mergeComponentProps, mergePartStyles, mergeSlots, mergeTheme, normalizeThemeTokens, preloadFonts, quickTheme, registerTheme, removeCSS, removeCSSVariables, removeTheme, renderSlot, sliderConstants, supportsDarkMode, theme, themePropertyToCSSVar, themeToCSS, types, unregisterTheme, useAccordion, useAtomixGlass, useBadge, useBarChart, useBlock, useChartData, useChartInteraction, useChartScale, useComponentCustomization, useComponentDefaultProps, useComponentTheme, useEdgePanel, useForm, useFormGroup, useHero, useHistory, useInput, useLineChart, useMergedProps, useNav, useNavDropdown, useNavItem, useNavbar, usePerformanceMonitor, usePieChart, useRadio, useResponsiveGlass, useRiver, useSelect, useSideMenu, useSideMenuItem, useSlot, useSpinner, useTextarea, useTheme, useThemeTokens, useTodo, utils, validateTheme };
28311
+ export { ACCORDION, ATOMIX_GLASS, AVATAR, AVATAR_GROUP, Accordion, AreaChart, AtomixGlass, AtomixLogo, Avatar, AvatarGroup, BADGE, BADGE_CSS_VARS, BALANCED_PRESET, BLOCK, BREADCRUMB, BUTTON, BUTTON_CSS_VARS, BUTTON_GROUP, Badge, BarChart, Block, Breadcrumb, BubbleChart, Button, ButtonGroup, CALLOUT, CARD, CARD_CSS_VARS, CHART, CHECKBOX_CSS_VARS, CLASS_PREFIX, CODE_SNIPPET, COMPONENT_CSS_VARS, COUNTDOWN, Callout, CandlestickChart, Card, Chart, ChartRenderer, Checkbox, ColorModeToggle, Container, Countdown, DATA_TABLE_CLASSES, DATA_TABLE_SELECTORS, DATEPICKER, DEFAULT_ATOMIX_FONTS, DEFAULT_BREAKPOINTS, DROPDOWN, DROPDOWN_CSS_VARS, DataTable, DatePicker, DesignTokensCustomizer, DeviceDetector, DonutChart, Dropdown, EDGE_PANEL, EdgePanel, ElevationCard, FOOTER, FORM, FORM_GROUP, Footer, FooterLink, FooterSection, FooterSocialLink, Form, FormGroup, FunnelChart, GaugeChart, Grid, GridCol, HERO, HeatmapChart, Hero, INPUT, INPUT_CSS_VARS, Icon, Input, LIST, LIST_GROUP, LineChart, List, ListGroup, MESSAGES, MOBILE_OPTIMIZED_BREAKPOINTS, MODAL, MODAL_CSS_VARS, MasonryGrid, MasonryGridItem, MegaMenu, MegaMenuColumn, MegaMenuLink, Menu, MenuDivider, MenuItem, Messages, Modal, MultiAxisChart, NAV, NAVBAR, Nav, NavDropdown, NavItem, Navbar, PAGINATION_DEFAULTS, PERFORMANCE_PRESET, PHOTOVIEWER, POPOVER, PROGRESS, PROGRESS_CSS_VARS, Pagination, PerformanceOverlay, PhotoViewer, PieChart, Popover, ProductReview, Progress, QUALITY_PRESET, RADIO, RADIO_CSS_VARS, RATING, RIVER, RTLManager, RadarChart, Radio, Rating, River, Row, SECTION_INTRO, SELECT, SIDE_MENU, SIZES, SLIDER, SPINNER, STEPS, ScatterChart, SectionIntro, Select, SideMenu, SideMenuItem, SideMenuList, Slider, Spinner, Steps, TAB, TABS_CSS_VARS, TESTIMONIAL, TEXTAREA, THEME_COLORS, THEME_NAMING, TODO, TOGGLE, TOOLTIP, TOOLTIP_CSS_VARS, TYPEDBUTTON, Tabs, Testimonial, Textarea, ThemeApplicator, ThemeComparator, ThemeContext, ThemeErrorBoundary, ThemeInspector, ThemeLiveEditor, ThemePreview, ThemeProvider, ThemeToggle, ThemeValidator, Todo, Toggle, Tooltip, TreemapChart, UPLOAD, Upload, VIDEO_PLAYER, VideoPlayer, WaterfallChart, alpha, applyCSSVariables, applyCSSVarsToStyle, applyComponentTheme, applyPartStyles, applyTheme, camelToKebab, clearThemePreference, clearThemes, composables, configToTokens, constants, createBreakpoints$1 as createBreakpoints, createCSSVarStyle, createDarkVariant, createDebugAttrs, createFontPreloadLink, createPartProps, createPerformanceMonitor, createRTLManager, createResponsiveUtil, createSlotComponent, createSlotProps, createSpacing, createTheme, createThemeRegistry, createTokens, cssVarsToStyle, darken, deepMerge, atomix as default, defaultTokens, defineConfig, designTokensToCSSVars, emphasize, exportTheme, extendTheme, extractComponentName, extractYouTubeId, generateCSSVariableName, generateCSSVariables$1 as generateCSSVariables, generateCSSVariablesForSelector, generateClassName, generateComponentCSSVars, generateFontPreloadTags, generateUUID, getAllThemes, getCSSVariable, getComponentCSSVars, getComponentThemeValue, getContrastRatio, getContrastText, getCurrentTheme, getDefaultBreakpoints, getDevicePreset, getDirectionFromLocale, getLuminance, getMobileOptimizedParams, getPartStyles, getQualityMultipliers, getSystemTheme, getTheme, getThemeApplicator, getThemeCount, getThemeIds, getThemeMetadata, hasCustomization, hasTheme, hexToRgb$1 as hexToRgb, importTheme, initializeTheme, injectCSS$1 as injectCSS, injectTheme, isAccessible, isCSSInjected, isDesignTokens, isRTLLocale, isSlot, isValidCSSVariableName, isYouTubeUrl, lighten, listenToSystemTheme, loadAtomixConfig, loadConfig, mapSCSSTokensToCSSVars, mergeCSSVars, mergeClassNames, mergeComponentProps, mergePartStyles, mergeSlots, mergeTheme, mergeTokens, normalizeThemeTokens, omitTokens, overrideTokens, persistTheme, pickTokens, preloadFonts, printConfigReport, quickTheme, registerTheme, removeCSS, removeCSSVariables, removeTheme, renderSlot, resolveConfigPath, rgbToHex, rtlCSS, sliderConstants, supportsDarkMode, switchTheme, theme, themePropertyToCSSVar, themeToCSS, toggleTheme, types, unregisterTheme, useAccordion, useAtomixGlass, useBadge, useBarChart, useBlock, useChartData, useChartInteraction, useChartScale, useComponentCustomization, useComponentDefaultProps, useComponentTheme, useEdgePanel, useForm, useFormGroup, useHero, useHistory, useInput, useLineChart, useMergedProps, useNav, useNavDropdown, useNavItem, useNavbar, usePieChart, useRadio, useResponsive, useResponsiveGlass, useRiver, useSelect, useSideMenu, useSideMenuItem, useSlot, useSpinner, useTextarea, useTheme, useThemeSwitcher, useThemeTokens, useTodo, utils, validateConfig, validateConfiguration, validateTheme };
26415
28312
  //# sourceMappingURL=index.esm.js.map