@shohojdhara/atomix 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/atomix.config.ts +12 -0
  2. package/build-tools/webpack-loader.js +5 -4
  3. package/dist/atomix.css +230 -83
  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 +24 -23
  9. package/dist/charts.js +271 -369
  10. package/dist/charts.js.map +1 -1
  11. package/dist/config.d.ts +624 -0
  12. package/dist/config.js +59 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/core.d.ts +3 -2
  15. package/dist/core.js +342 -382
  16. package/dist/core.js.map +1 -1
  17. package/dist/forms.d.ts +4 -6
  18. package/dist/forms.js +233 -334
  19. package/dist/forms.js.map +1 -1
  20. package/dist/heavy.d.ts +11 -2
  21. package/dist/heavy.js +406 -445
  22. package/dist/heavy.js.map +1 -1
  23. package/dist/index.d.ts +109 -65
  24. package/dist/index.esm.js +654 -748
  25. package/dist/index.esm.js.map +1 -1
  26. package/dist/index.js +621 -717
  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.js +4 -4
  33. package/dist/theme.js.map +1 -1
  34. package/package.json +24 -9
  35. package/scripts/atomix-cli.js +15 -1
  36. package/scripts/cli/__tests__/complexity-utils.test.js +24 -0
  37. package/scripts/cli/__tests__/detector.test.js +50 -0
  38. package/scripts/cli/__tests__/template-engine.test.js +23 -0
  39. package/scripts/cli/__tests__/test-setup.js +1 -133
  40. package/scripts/cli/commands/doctor.js +15 -3
  41. package/scripts/cli/commands/generate.js +113 -51
  42. package/scripts/cli/internal/ai-engine.js +30 -10
  43. package/scripts/cli/internal/complexity-utils.js +60 -0
  44. package/scripts/cli/internal/component-validator.js +49 -16
  45. package/scripts/cli/internal/generator.js +89 -36
  46. package/scripts/cli/internal/hook-generator.js +5 -2
  47. package/scripts/cli/internal/itcss-generator.js +16 -12
  48. package/scripts/cli/templates/next-templates.js +81 -30
  49. package/scripts/cli/templates/storybook-templates.js +12 -2
  50. package/scripts/cli/utils/detector.js +45 -7
  51. package/scripts/cli/utils/diagnostics.js +78 -0
  52. package/scripts/cli/utils/telemetry.js +13 -0
  53. package/src/components/Accordion/Accordion.stories.tsx +4 -0
  54. package/src/components/AtomixGlass/AtomixGlass.tsx +188 -128
  55. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +63 -91
  56. package/src/components/AtomixGlass/PerformanceDashboard.tsx +153 -201
  57. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +9 -6
  58. package/src/components/AtomixGlass/glass-utils.ts +51 -1
  59. package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +52 -46
  60. package/src/components/AtomixGlass/stories/Examples.stories.tsx +573 -236
  61. package/src/components/AtomixGlass/stories/Playground.stories.tsx +88 -41
  62. package/src/components/AtomixGlass/stories/argTypes.ts +19 -19
  63. package/src/components/AtomixGlass/stories/shared-components.tsx +7 -12
  64. package/src/components/AtomixGlass/stories/types.ts +3 -3
  65. package/src/components/Button/Button.tsx +114 -57
  66. package/src/components/Callout/Callout.tsx +4 -4
  67. package/src/components/Chart/ChartRenderer.tsx +1 -1
  68. package/src/components/Chart/DonutChart.tsx +11 -8
  69. package/src/components/EdgePanel/EdgePanel.tsx +119 -115
  70. package/src/components/Form/Select.tsx +4 -4
  71. package/src/components/List/List.tsx +4 -4
  72. package/src/components/Navigation/SideMenu/SideMenu.tsx +6 -6
  73. package/src/components/PhotoViewer/PhotoViewerImage.tsx +1 -1
  74. package/src/components/ProductReview/ProductReview.tsx +4 -2
  75. package/src/components/Rating/Rating.tsx +4 -2
  76. package/src/components/SectionIntro/SectionIntro.tsx +4 -2
  77. package/src/components/Steps/Steps.tsx +1 -1
  78. package/src/components/Tabs/Tabs.tsx +5 -5
  79. package/src/components/Testimonial/Testimonial.tsx +4 -2
  80. package/src/components/VideoPlayer/VideoPlayer.tsx +4 -2
  81. package/src/layouts/CssGrid/CssGrid.stories.tsx +464 -0
  82. package/src/layouts/CssGrid/CssGrid.tsx +215 -0
  83. package/src/layouts/CssGrid/index.ts +8 -0
  84. package/src/layouts/CssGrid/scripts/CssGrid.js +284 -0
  85. package/src/layouts/CssGrid/scripts/index.js +43 -0
  86. package/src/layouts/Grid/scripts/Container.js +139 -0
  87. package/src/layouts/Grid/scripts/Grid.js +184 -0
  88. package/src/layouts/Grid/scripts/GridCol.js +273 -0
  89. package/src/layouts/Grid/scripts/Row.js +154 -0
  90. package/src/layouts/Grid/scripts/index.js +48 -0
  91. package/src/layouts/MasonryGrid/MasonryGrid.tsx +71 -59
  92. package/src/lib/composables/atomix-glass/useGlassSize.ts +1 -1
  93. package/src/lib/composables/useAccordion.ts +5 -5
  94. package/src/lib/composables/useAtomixGlass.ts +111 -74
  95. package/src/lib/composables/useAtomixGlassStyles.ts +0 -2
  96. package/src/lib/composables/useBarChart.ts +2 -2
  97. package/src/lib/composables/useChart.ts +3 -2
  98. package/src/lib/composables/useChartToolbar.ts +48 -66
  99. package/src/lib/composables/useDataTable.ts +1 -1
  100. package/src/lib/composables/useDatePicker.ts +2 -2
  101. package/src/lib/composables/useEdgePanel.ts +45 -54
  102. package/src/lib/composables/useHeroBackgroundSlider.ts +5 -5
  103. package/src/lib/composables/usePhotoViewer.ts +2 -3
  104. package/src/lib/composables/usePieChart.ts +1 -1
  105. package/src/lib/composables/usePopover.ts +151 -139
  106. package/src/lib/composables/useSideMenu.ts +28 -41
  107. package/src/lib/composables/useSlider.ts +2 -6
  108. package/src/lib/composables/useTooltip.ts +2 -2
  109. package/src/lib/config/index.ts +39 -0
  110. package/src/lib/constants/components.ts +1 -0
  111. package/src/lib/theme/devtools/Comparator.tsx +1 -1
  112. package/src/lib/theme/devtools/Inspector.tsx +1 -1
  113. package/src/lib/theme/devtools/LiveEditor.tsx +1 -1
  114. package/src/lib/theme/runtime/ThemeProvider.tsx +1 -1
  115. package/src/lib/types/components.ts +1 -0
  116. package/src/styles/01-settings/_index.scss +1 -0
  117. package/src/styles/01-settings/_settings.atomix-glass.scss +174 -0
  118. package/src/styles/01-settings/_settings.masonry-grid.scss +42 -6
  119. package/src/styles/02-tools/_tools.glass.scss +6 -0
  120. package/src/styles/05-objects/_objects.masonry-grid.scss +162 -24
  121. package/src/styles/06-components/_components.atomix-glass.scss +160 -99
  122. package/scripts/cli/__tests__/README.md +0 -81
  123. package/scripts/cli/__tests__/basic.test.js +0 -116
  124. package/scripts/cli/__tests__/clean.test.js +0 -278
  125. package/scripts/cli/__tests__/component-generator.test.js +0 -332
  126. package/scripts/cli/__tests__/component-validator.test.js +0 -433
  127. package/scripts/cli/__tests__/generator.test.js +0 -613
  128. package/scripts/cli/__tests__/glass-motion.test.js +0 -256
  129. package/scripts/cli/__tests__/integration.test.js +0 -938
  130. package/scripts/cli/__tests__/migrate.test.js +0 -74
  131. package/scripts/cli/__tests__/security.test.js +0 -206
  132. package/scripts/cli/__tests__/theme-bridge.test.js +0 -507
  133. package/scripts/cli/__tests__/token-manager.test.js +0 -251
  134. package/scripts/cli/__tests__/token-provider.test.js +0 -361
  135. package/scripts/cli/__tests__/utils.test.js +0 -165
  136. package/src/components/AtomixGlass/stories/AnimationTests.stories.tsx +0 -95
  137. package/src/components/AtomixGlass/stories/CardExamples.stories.tsx +0 -212
  138. package/src/components/AtomixGlass/stories/Customization.stories.tsx +0 -131
  139. package/src/components/AtomixGlass/stories/DashboardExamples.stories.tsx +0 -348
  140. package/src/components/AtomixGlass/stories/EcommerceExamples.stories.tsx +0 -410
  141. package/src/components/AtomixGlass/stories/FormExamples.stories.tsx +0 -436
  142. package/src/components/AtomixGlass/stories/HeroExamples.stories.tsx +0 -264
  143. package/src/components/AtomixGlass/stories/InteractivePlayground.stories.tsx +0 -247
  144. package/src/components/AtomixGlass/stories/MobileUIExamples.stories.tsx +0 -418
  145. package/src/components/AtomixGlass/stories/ModalExamples.stories.tsx +0 -402
  146. package/src/components/AtomixGlass/stories/Modes.stories.tsx +0 -1082
  147. package/src/components/AtomixGlass/stories/Overview.stories.tsx +0 -497
  148. package/src/components/AtomixGlass/stories/Performance.stories.tsx +0 -103
  149. package/src/components/AtomixGlass/stories/PresetGallery.stories.tsx +0 -335
  150. package/src/components/AtomixGlass/stories/Shaders.stories.tsx +0 -395
  151. package/src/components/AtomixGlass/stories/WidgetExamples.stories.tsx +0 -441
  152. package/src/components/TypedButton/TypedButton.stories.tsx +0 -59
  153. package/src/components/TypedButton/TypedButton.tsx +0 -39
  154. package/src/components/TypedButton/index.ts +0 -2
  155. package/src/lib/composables/useBreadcrumb.ts +0 -81
  156. package/src/lib/composables/useChartInteractions.ts +0 -123
  157. package/src/lib/composables/useChartPerformance.ts +0 -347
  158. package/src/lib/composables/useDropdown.ts +0 -338
  159. package/src/lib/composables/useModal.ts +0 -110
  160. package/src/lib/composables/useTypedButton.ts +0 -66
  161. package/src/lib/hooks/usePerformanceMonitor.ts +0 -148
  162. package/src/lib/utils/displacement-generator.ts +0 -92
  163. package/src/lib/utils/memoryMonitor.ts +0 -191
  164. package/src/styles/01-settings/_settings.testtypecheck.scss +0 -53
  165. package/src/styles/01-settings/_settings.typedbutton.scss +0 -53
  166. package/src/styles/06-components/_components.testbutton.scss +0 -212
  167. package/src/styles/06-components/_components.testtypecheck.scss +0 -212
  168. package/src/styles/06-components/_components.typedbutton.scss +0 -212
package/dist/index.js CHANGED
@@ -1718,6 +1718,7 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
1718
1718
  FILTER_OVERLAY_CLASS: "c-atomix-glass__filter-overlay",
1719
1719
  FILTER_SHADOW_CLASS: "c-atomix-glass__filter-shadow",
1720
1720
  CONTENT_CLASS: "c-atomix-glass__content",
1721
+ BORDER_BACKDROP_CLASS: "c-atomix-glass__border-backdrop",
1721
1722
  BORDER_1_CLASS: "c-atomix-glass__border-1",
1722
1723
  BORDER_2_CLASS: "c-atomix-glass__border-2",
1723
1724
  HOVER_1_CLASS: "c-atomix-glass__hover-1",
@@ -1987,19 +1988,19 @@ function useAccordion(initialProps) {
1987
1988
  disabled: !1,
1988
1989
  iconPosition: "right",
1989
1990
  ...initialProps
1990
- }, isControlled = "boolean" == typeof defaultProps.isOpen, [internalOpen, setInternalOpen] = React.useState(defaultProps.defaultOpen || !1), isOpen = isControlled ? defaultProps.isOpen : internalOpen, [panelHeight, setPanelHeight] = React.useState(isOpen ? "auto" : "0px"), panelRef = React.useRef(null), contentRef = React.useRef(null), updatePanelHeight = () => {
1991
+ }, isControlled = "boolean" == typeof defaultProps.isOpen, [internalOpen, setInternalOpen] = React.useState(defaultProps.defaultOpen || !1), isOpen = isControlled ? defaultProps.isOpen : internalOpen, [panelHeight, setPanelHeight] = React.useState(isOpen ? "auto" : "0px"), panelRef = React.useRef(null), contentRef = React.useRef(null), updatePanelHeight = React.useCallback((() => {
1991
1992
  if (contentRef.current && panelRef.current) {
1992
1993
  const height = isOpen ? `${contentRef.current.clientHeight}px` : "0px";
1993
1994
  panelRef.current.style.setProperty(ACCORDION.CSS_VARS.PANEL_HEIGHT, height), setPanelHeight(height);
1994
1995
  }
1995
- };
1996
+ }), [ isOpen ]);
1996
1997
  // Controlled/uncontrolled open state
1997
1998
  /**
1998
1999
  * Effect to update panel height when open state changes
1999
2000
  */
2000
2001
  return React.useEffect((() => {
2001
2002
  updatePanelHeight();
2002
- }), [ isOpen ]),
2003
+ }), [ isOpen, updatePanelHeight ]),
2003
2004
  /**
2004
2005
  * Effect to handle window resize and update panel height
2005
2006
  */
@@ -2008,7 +2009,7 @@ function useAccordion(initialProps) {
2008
2009
  isOpen && updatePanelHeight();
2009
2010
  };
2010
2011
  return window.addEventListener("resize", handleResize), () => window.removeEventListener("resize", handleResize);
2011
- }), [ isOpen ]), {
2012
+ }), [ isOpen, updatePanelHeight ]), {
2012
2013
  state: {
2013
2014
  isOpen: isOpen,
2014
2015
  panelHeight: panelHeight
@@ -2120,7 +2121,7 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateDistance = (pos1, pos2)
2120
2121
  default:
2121
2122
  return console.warn("AtomixGlass: Invalid displacement mode"), displacementMap;
2122
2123
  }
2123
- }, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsxRuntime.jsx("svg", {
2124
+ }, sharedShaderCache = new Map, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsxRuntime.jsx("svg", {
2124
2125
  style: {
2125
2126
  position: "absolute",
2126
2127
  width: "100%",
@@ -2261,24 +2262,17 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateDistance = (pos1, pos2)
2261
2262
  */ GlassFilterComponent.displayName = "GlassFilter";
2262
2263
 
2263
2264
  // Memoize component to prevent unnecessary re-renders
2264
- const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) => prevProps.id === nextProps.id && prevProps.displacementScale === nextProps.displacementScale && prevProps.aberrationIntensity === nextProps.aberrationIntensity && prevProps.mode === nextProps.mode && prevProps.shaderMapUrl === nextProps.shaderMapUrl && prevProps.blurAmount === nextProps.blurAmount));
2265
-
2266
- // Module-level counter for deterministic ID generation
2267
- let idCounter = 0;
2268
-
2269
- // Module-level shared shader cache with LRU eviction
2270
- const sharedShaderCache = new Map, AtomixGlassContainer = React.forwardRef((({children: children, className: className = "", style: style, displacementScale: displacementScale = 25, blurAmount: blurAmount = .0625, saturation: saturation = 180, aberrationIntensity: aberrationIntensity = 2, mouseOffset: mouseOffset = {
2265
+ const GlassFilter = React.memo(GlassFilterComponent, ((prevProps, nextProps) => prevProps.id === nextProps.id && prevProps.displacementScale === nextProps.displacementScale && prevProps.aberrationIntensity === nextProps.aberrationIntensity && prevProps.mode === nextProps.mode && prevProps.shaderMapUrl === nextProps.shaderMapUrl && prevProps.blurAmount === nextProps.blurAmount)), AtomixGlassContainer = React.forwardRef((({children: children, className: className = "", style: style, displacementScale: displacementScale = 25, blurAmount: blurAmount = .0625, saturation: saturation = 180, aberrationIntensity: aberrationIntensity = 2, mouseOffset: mouseOffset = {
2271
2266
  x: 0,
2272
2267
  y: 0
2273
2268
  }, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0, padding: padding = "0 0", glassSize: glassSize = {
2274
2269
  width: 0,
2275
2270
  height: 0
2276
- }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1,
2271
+ }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, isFixedOrSticky: isFixedOrSticky = !1,
2277
2272
  // Phase 1: Animation System props
2278
2273
  shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", contentRef: contentRef}, ref) => {
2279
- // Generate a stable, deterministic ID for SSR compatibility
2280
- // Use a module-level counter that's consistent across server and client
2281
- const filterId = React.useMemo((() => "atomix-glass-filter-" + ++idCounter), []), [shaderMapUrl, setShaderMapUrl] = React.useState(""), shaderGeneratorRef = React.useRef(null), shaderUtilsRef = React.useRef(null), shaderDebounceTimeoutRef = React.useRef(null), shaderUpdateTimeoutRef = React.useRef(null), animationFrameRef = React.useRef(null);
2274
+ // React 18 useId — stable, unique, and SSR-safe (no module-level counter)
2275
+ const rawId = React.useId(), filterId = React.useMemo((() => `atomix-glass-filter-${rawId.replace(/:/g, "")}`), [ rawId ]), [shaderMapUrl, setShaderMapUrl] = React.useState(""), shaderGeneratorRef = React.useRef(null), shaderUtilsRef = React.useRef(null), shaderDebounceTimeoutRef = React.useRef(null), shaderUpdateTimeoutRef = React.useRef(null), animationFrameRef = React.useRef(null);
2282
2276
  // Lazy load shader utilities only when shader mode is needed
2283
2277
  React.useEffect((() => {
2284
2278
  "shader" === mode ?
@@ -2303,9 +2297,7 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
2303
2297
  // Create cache key from size and variant
2304
2298
  const cacheKey = `${glassSize.width}x${glassSize.height}-${shaderVariant}`, cachedUrl = (key => {
2305
2299
  const entry = sharedShaderCache.get(key);
2306
- return entry ? (
2307
- // Update access timestamp for LRU
2308
- entry.timestamp = Date.now(), entry.url) : null;
2300
+ return entry ? (entry.timestamp = Date.now(), entry.url) : null;
2309
2301
  })(cacheKey);
2310
2302
  // Check shared cache first
2311
2303
  if (cachedUrl) return void setShaderMapUrl(cachedUrl);
@@ -2316,29 +2308,24 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
2316
2308
  if (shaderUtilsRef.current) try {
2317
2309
  const {ShaderDisplacementGenerator: ShaderDisplacementGenerator, fragmentShaders: fragmentShaders} = shaderUtilsRef.current;
2318
2310
  shaderGeneratorRef.current?.destroy();
2319
- const selectedShader = fragmentShaders[shaderVariant] || fragmentShaders.liquidGlass;
2311
+ const selectedShader = fragmentShaders[shaderVariant] ?? fragmentShaders.liquidGlass;
2320
2312
  shaderGeneratorRef.current = new ShaderDisplacementGenerator({
2321
2313
  width: glassSize.width,
2322
2314
  height: glassSize.height,
2323
2315
  fragment: selectedShader
2324
2316
  }), shaderUpdateTimeoutRef.current = setTimeout((() => {
2325
- const url = shaderGeneratorRef.current?.updateShader() || "";
2317
+ const url = shaderGeneratorRef.current?.updateShader() ?? "";
2326
2318
  url && ((key, url) => {
2327
- // Evict oldest entries if at capacity
2328
2319
  if (sharedShaderCache.size >= 15) {
2329
2320
  const entries = Array.from(sharedShaderCache.entries());
2330
- // Sort by timestamp (oldest first)
2331
- entries.sort(((a, b) => a[1].timestamp - b[1].timestamp));
2332
- // Remove oldest entry
2333
- const oldestEntry = entries[0];
2334
- oldestEntry && sharedShaderCache.delete(oldestEntry[0]);
2321
+ entries.sort(((a, b) => a[1].timestamp - b[1].timestamp));
2322
+ const oldest = entries[0];
2323
+ oldest && sharedShaderCache.delete(oldest[0]);
2335
2324
  }
2336
2325
  sharedShaderCache.set(key, {
2337
2326
  url: url,
2338
2327
  timestamp: Date.now()
2339
- }),
2340
- // Development mode: log cache size
2341
- "undefined" != typeof process && "production" === process.env?.NODE_ENV || sharedShaderCache.size;
2328
+ }), "undefined" != typeof process && "production" === process.env?.NODE_ENV || sharedShaderCache.size;
2342
2329
  })(cacheKey, url), setShaderMapUrl(url);
2343
2330
  }), 100);
2344
2331
  } catch (error) {
@@ -2407,7 +2394,6 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
2407
2394
  console.warn("AtomixGlassContainer: Error getting element bounds", error), setRectCache(null);
2408
2395
  }
2409
2396
  }), [ ref, glassSize ]);
2410
- // Pre-calculate static multipliers outside useMemo
2411
2397
  const liquidBlur = React.useMemo((() => {
2412
2398
  const defaultBlur = {
2413
2399
  baseBlur: blurAmount,
@@ -2476,7 +2462,6 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
2476
2462
  }), [ borderRadius, backdropStyle, mouseOffset, overLight, effectiveWithoutEffects, overLightConfig ]);
2477
2463
  return jsxRuntime.jsx("div", {
2478
2464
  ref: el => {
2479
- // Apply force no-transition
2480
2465
  // Handle forwarded ref
2481
2466
  "function" == typeof ref ? ref(el) : ref && (ref.current = el);
2482
2467
  },
@@ -2518,6 +2503,7 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
2518
2503
  });
2519
2504
  }));
2520
2505
 
2506
+ // ─── Blur multiplier constants (module-level, never change at runtime) ────────
2521
2507
  AtomixGlassContainer.displayName = "AtomixGlassContainer";
2522
2508
 
2523
2509
  // Singleton instance
@@ -2718,8 +2704,6 @@ class {
2718
2704
  backdropFilterString = !withLiquidBlur || effectiveReducedMotion || effectiveWithoutEffects || area > 18e4 ? `blur(${clampBlur(Math.max(liquidBlur.baseBlur, .8 * liquidBlur.edgeBlur, 1.1 * liquidBlur.centerBlur, .9 * liquidBlur.flowBlur))}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig.contrast}) brightness(${overLightConfig.brightness})` : `blur(${clampBlur(.4 * liquidBlur.baseBlur + .25 * liquidBlur.edgeBlur + .15 * liquidBlur.centerBlur + .2 * liquidBlur.flowBlur)}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig.contrast}) brightness(${overLightConfig.brightness})`;
2719
2705
  // Container variables
2720
2706
  const style = containerElement.style;
2721
- style.setProperty("--atomix-glass-container-width", isFixedOrSticky ? `${glassSize.width}` : "100%"),
2722
- style.setProperty("--atomix-glass-container-height", isFixedOrSticky ? `${glassSize.height}` : "100%"),
2723
2707
  style.setProperty("--atomix-glass-container-padding", padding), style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
2724
2708
  style.setProperty("--atomix-glass-container-backdrop", backdropFilterString),
2725
2709
  // Shadows
@@ -3180,47 +3164,55 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
3180
3164
  return "undefined" == typeof process || process.env, finalConfig;
3181
3165
  }
3182
3166
  return "undefined" == typeof process || process.env, baseConfig;
3183
- }), [ overLight, getEffectiveOverLight, isHovered, isActive, validateConfigValue, debugOverLight ]), transformStyle = React.useMemo((() => effectiveWithoutEffects || isActive && Boolean(onClick) ? "scale(0.98)" : "scale(1)"), [ effectiveWithoutEffects, isActive, onClick ]), updateRectRef = React.useRef(null), handleGlobalMousePosition = React.useCallback((globalPos => {
3184
- if (externalGlobalMousePosition && externalMouseOffset) return;
3185
- if (effectiveWithoutEffects) return;
3186
- const container = mouseContainer?.current || glassRef.current;
3187
- if (!container) return;
3188
- // Use cached rect if available, otherwise get new one
3189
- let rect = cachedRectRef.current;
3190
- if (rect && 0 !== rect.width && 0 !== rect.height || (rect = container.getBoundingClientRect(),
3191
- cachedRectRef.current = rect), 0 === rect.width || 0 === rect.height) return;
3192
- const center = calculateElementCenter(rect);
3193
- // Write raw target — the lerp loop will smoothly pursue it
3194
- targetMouseOffsetRef.current = {
3195
- x: (globalPos.x - center.x) / rect.width * 100,
3196
- y: (globalPos.y - center.y) / rect.height * 100
3197
- }, targetGlobalMousePositionRef.current = globalPos;
3198
- }), [ mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects ]), startLerpLoop = React.useCallback((() => {
3167
+ }), [ overLight, getEffectiveOverLight, isHovered, isActive, validateConfigValue, debugOverLight ]), transformStyle = React.useMemo((() => effectiveWithoutEffects || isActive && Boolean(onClick) ? "scale(0.98)" : "scale(1)"), [ effectiveWithoutEffects, isActive, onClick ]), updateRectRef = React.useRef(null), stopLerpLoop = React.useCallback((() => {
3168
+ lerpActiveRef.current = !1, null !== lerpRafRef.current && (cancelAnimationFrame(lerpRafRef.current),
3169
+ lerpRafRef.current = null);
3170
+ }), []), startLerpLoop = React.useCallback((() => {
3199
3171
  if (lerpActiveRef.current) return;
3200
3172
  lerpActiveRef.current = !0;
3201
3173
  const LERP_T = CONSTANTS.LERP_FACTOR, tick = () => {
3202
3174
  if (!lerpActiveRef.current) return;
3203
- // Add ref validity check to prevent memory leaks
3204
- if (!glassRef.current || !wrapperRef?.current) return void (lerpActiveRef.current = !1);
3175
+ if (!glassRef.current) return void (lerpActiveRef.current = !1);
3205
3176
  const cur = internalMouseOffsetRef.current, tgt = targetMouseOffsetRef.current, dx = tgt.x - cur.x, dy = tgt.y - cur.y;
3206
3177
  // If we're close enough, snap and park
3207
- if (Math.abs(dx) < .05 && Math.abs(dy) < .05) internalMouseOffsetRef.current = {
3178
+ if (Math.abs(dx) < .01 && Math.abs(dy) < .01) return internalMouseOffsetRef.current = {
3208
3179
  ...tgt
3209
3180
  }, internalGlobalMousePositionRef.current = {
3210
3181
  ...targetGlobalMousePositionRef.current
3211
- }; else {
3212
- internalMouseOffsetRef.current = {
3213
- x: lerp$1(cur.x, tgt.x, LERP_T),
3214
- y: lerp$1(cur.y, tgt.y, LERP_T)
3215
- };
3216
- const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
3217
- internalGlobalMousePositionRef.current = {
3218
- x: lerp$1(curG.x, tgtG.x, LERP_T),
3219
- y: lerp$1(curG.y, tgtG.y, LERP_T)
3220
- };
3221
- }
3222
- // Imperative style update with the smoothed values
3223
- updateAtomixGlassStyles(wrapperRef.current, glassRef.current, {
3182
+ },
3183
+ // Final update and stop
3184
+ updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
3185
+ mouseOffset: internalMouseOffsetRef.current,
3186
+ globalMousePosition: internalGlobalMousePositionRef.current,
3187
+ glassSize: glassSize,
3188
+ isHovered: isHovered,
3189
+ isActive: isActive,
3190
+ isOverLight: overLightConfig.isOverLight,
3191
+ baseOverLightConfig: overLightConfig,
3192
+ effectiveBorderRadius: effectiveBorderRadius,
3193
+ effectiveWithoutEffects: effectiveWithoutEffects,
3194
+ effectiveReducedMotion: effectiveReducedMotion,
3195
+ elasticity: elasticity,
3196
+ directionalScale: isActive && Boolean(onClick) ? "scale(0.96)" : "scale(1)",
3197
+ onClick: onClick,
3198
+ withLiquidBlur: withLiquidBlur,
3199
+ blurAmount: blurAmount,
3200
+ saturation: saturation,
3201
+ padding: padding,
3202
+ isFixedOrSticky: isFixedOrSticky
3203
+ }), void stopLerpLoop();
3204
+ // Smooth step
3205
+ internalMouseOffsetRef.current = {
3206
+ x: lerp$1(cur.x, tgt.x, LERP_T),
3207
+ y: lerp$1(cur.y, tgt.y, LERP_T)
3208
+ };
3209
+ const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
3210
+ internalGlobalMousePositionRef.current = {
3211
+ x: lerp$1(curG.x, tgtG.x, LERP_T),
3212
+ y: lerp$1(curG.y, tgtG.y, LERP_T)
3213
+ },
3214
+ // Imperative style update
3215
+ updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
3224
3216
  mouseOffset: internalMouseOffsetRef.current,
3225
3217
  globalMousePosition: internalGlobalMousePositionRef.current,
3226
3218
  glassSize: glassSize,
@@ -3243,10 +3235,24 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
3243
3235
  };
3244
3236
  // 0.08 – lower = more viscous
3245
3237
  lerpRafRef.current = requestAnimationFrame(tick);
3246
- }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding, isFixedOrSticky ]), stopLerpLoop = React.useCallback((() => {
3247
- lerpActiveRef.current = !1, null !== lerpRafRef.current && (cancelAnimationFrame(lerpRafRef.current),
3248
- lerpRafRef.current = null);
3249
- }), []);
3238
+ }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding, isFixedOrSticky, stopLerpLoop ]), handleGlobalMousePosition = React.useCallback((globalPos => {
3239
+ if (externalGlobalMousePosition && externalMouseOffset) return;
3240
+ if (effectiveWithoutEffects) return;
3241
+ const container = mouseContainer?.current || glassRef.current;
3242
+ if (!container) return;
3243
+ // Use cached rect if available, otherwise get new one
3244
+ let rect = cachedRectRef.current;
3245
+ if (rect && 0 !== rect.width && 0 !== rect.height || (rect = container.getBoundingClientRect(),
3246
+ cachedRectRef.current = rect), 0 === rect.width || 0 === rect.height) return;
3247
+ const center = calculateElementCenter(rect);
3248
+ // Write raw target — the lerp loop will smoothly pursue it
3249
+ targetMouseOffsetRef.current = {
3250
+ x: (globalPos.x - center.x) / rect.width * 100,
3251
+ y: (globalPos.y - center.y) / rect.height * 100
3252
+ }, targetGlobalMousePositionRef.current = globalPos,
3253
+ // Ensure the lerp loop is running to smoothly chase the new target
3254
+ lerpActiveRef.current || startLerpLoop();
3255
+ }), [ mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects, startLerpLoop ]);
3250
3256
  /**
3251
3257
  * Validate and clamp a numeric config value
3252
3258
  */
@@ -3255,7 +3261,7 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
3255
3261
  if (externalGlobalMousePosition && externalMouseOffset) return;
3256
3262
  if (effectiveWithoutEffects) return;
3257
3263
  const unsubscribe = globalMouseTracker.subscribe(handleGlobalMousePosition);
3258
- // Start the lerp loop — it will smoothly chase the target
3264
+ // Initial start
3259
3265
  startLerpLoop();
3260
3266
  const container = mouseContainer?.current || glassRef.current;
3261
3267
  let resizeObserver = null;
@@ -3268,7 +3274,7 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
3268
3274
  unsubscribe(), stopLerpLoop(), null !== updateRectRef.current && (cancelAnimationFrame(updateRectRef.current),
3269
3275
  updateRectRef.current = null), resizeObserver && resizeObserver.disconnect();
3270
3276
  };
3271
- }), [ handleGlobalMousePosition, startLerpLoop, stopLerpLoop, mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects ]),
3277
+ }), [ externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects, handleGlobalMousePosition, startLerpLoop, stopLerpLoop, mouseContainer, glassRef ]),
3272
3278
  // Also call updateStyles on other state changes (hover, active, etc)
3273
3279
  React.useEffect((() => {
3274
3280
  updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
@@ -3763,183 +3769,146 @@ function usePerformanceMonitor(config = {}) {
3763
3769
  }
3764
3770
  }
3765
3771
 
3772
+ /** Map an FPS value to a semantic color token string. */ const getQualityColor = quality => {
3773
+ switch (quality) {
3774
+ case "high":
3775
+ return "var(--atomix-color-success, #4ade80)";
3776
+
3777
+ case "medium":
3778
+ return "var(--atomix-color-warning, #fbbf24)";
3779
+
3780
+ case "low":
3781
+ return "var(--atomix-color-danger, #ef4444)";
3782
+
3783
+ default:
3784
+ return "#9ca3af";
3785
+ }
3786
+ }, getFpsLabel = fps => fps >= 58 ? "Optimal" : fps >= 45 ? "Warning" : "Critical";
3787
+
3788
+ /** Map a quality level string to a semantic color token string. */
3789
+ // Inject keyframes once
3790
+ if ("undefined" != typeof document) {
3791
+ const styleId = "perf-dashboard-keyframes";
3792
+ if (!document.getElementById(styleId)) {
3793
+ const styleEl = document.createElement("style");
3794
+ styleEl.id = styleId, styleEl.textContent = "\n@keyframes perf-dashboard-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n",
3795
+ document.head.appendChild(styleEl);
3796
+ }
3797
+ }
3798
+
3766
3799
  /**
3767
- * PerformanceDashboard - Real-time performance monitoring overlay
3800
+ * PerformanceDashboard - Real-time performance monitoring overlay.
3768
3801
  *
3769
- * Displays:
3770
- * - Current FPS with color coding
3771
- * - Frame time statistics
3772
- * - Quality level indicator
3773
- * - GPU memory usage (if available)
3774
- * - Auto-scaling status
3775
- */ const PerformanceDashboard = ({metrics: metrics, isVisible: isVisible = !0, onClose: onClose}) => {
3776
- // Get color for FPS display
3777
- const getFpsColor = fps => fps >= 58 ? "#4ade80" : // Green - good
3778
- fps >= 45 ? "#fbbf24" : "#ef4444" // Red - critical
3779
- , dashboardStyle = React.useMemo((() => ({
3780
- position: "fixed",
3781
- top: "16px",
3782
- right: "16px",
3783
- padding: "12px 16px",
3784
- backgroundColor: "rgba(17, 24, 39, 0.95)",
3785
- borderRadius: "8px",
3786
- boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
3787
- fontFamily: "monospace",
3788
- fontSize: "12px",
3789
- color: "#fff",
3790
- zIndex: 9999,
3791
- minWidth: "200px",
3792
- backdropFilter: "blur(8px)",
3793
- border: "1px solid rgba(255, 255, 255, 0.1)",
3794
- transition: "opacity 0.3s ease",
3795
- opacity: isVisible ? 1 : 0,
3796
- pointerEvents: isVisible ? "auto" : "none"
3797
- })), [ isVisible ]), headerStyle = React.useMemo((() => ({
3798
- display: "flex",
3799
- justifyContent: "space-between",
3800
- alignItems: "center",
3801
- marginBottom: "8px",
3802
- paddingBottom: "8px",
3803
- borderBottom: "1px solid rgba(255, 255, 255, 0.1)"
3804
- })), []), titleStyle = React.useMemo((() => ({
3805
- fontWeight: "bold",
3806
- fontSize: "13px",
3807
- color: "#fff"
3808
- })), []), closeButtonStyle = React.useMemo((() => ({
3809
- background: "transparent",
3810
- border: "none",
3811
- color: "#9ca3af",
3812
- cursor: "pointer",
3813
- fontSize: "16px",
3814
- padding: "0",
3815
- lineHeight: "1"
3816
- })), []), metricRowStyle = React.useMemo((() => ({
3817
- display: "flex",
3818
- justifyContent: "space-between",
3819
- alignItems: "center",
3820
- marginBottom: "6px"
3821
- })), []), labelStyle = React.useMemo((() => ({
3822
- color: "#9ca3af",
3823
- marginRight: "12px"
3824
- })), []), valueStyle = React.useMemo((() => ({
3825
- fontWeight: "bold"
3826
- })), []);
3827
- // Get quality level badge color
3828
- return isVisible ? jsxRuntime.jsxs("div", {
3829
- style: dashboardStyle,
3802
+ * Displays FPS, frame time, quality level, GPU memory, and auto-scaling status.
3803
+ * Rendered only when `debugPerformance={true}` on the parent `AtomixGlass`.
3804
+ */ const PerformanceDashboard = React.memo((({metrics: metrics, isVisible: isVisible = !0, onClose: onClose}) => {
3805
+ if (!isVisible) return null;
3806
+ const fpsColor = (fps = metrics.fps) >= 58 ? "var(--atomix-color-success, #4ade80)" : fps >= 45 ? "var(--atomix-color-warning, #fbbf24)" : "var(--atomix-color-danger, #ef4444)";
3807
+ var fps;
3808
+ const isCritical = metrics.fps < 45;
3809
+ return jsxRuntime.jsxs("div", {
3810
+ className: "c-perf-dashboard u-position-fixed u-top-4 u-end-4 u-p-3 u-px-4 u-text-xs u-font-mono u-text-white u-rounded-md u-border u-border-white-alpha-10 u-shadow-lg",
3811
+ style: {
3812
+ zIndex: 9999,
3813
+ minWidth: "12.5rem",
3814
+ // 200px
3815
+ backgroundColor: "rgba(17, 24, 39, 0.95)",
3816
+ backdropFilter: "blur(8px)",
3817
+ transition: "opacity 0.3s ease"
3818
+ },
3830
3819
  children: [ jsxRuntime.jsxs("div", {
3831
- style: headerStyle,
3820
+ className: "u-flex u-items-center u-justify-between u-mb-2 u-pb-2 u-border-b u-border-white-alpha-10",
3832
3821
  children: [ jsxRuntime.jsx("span", {
3833
- style: titleStyle,
3822
+ className: "u-text-sm u-font-bold u-text-white",
3834
3823
  children: "Performance Monitor"
3835
3824
  }), onClose && jsxRuntime.jsx("button", {
3836
- style: closeButtonStyle,
3825
+ className: "u-bg-transparent u-border-none u-p-0 u-line-height-1 u-text-base u-text-gray-400 u-cursor-pointer hover:u-text-white",
3837
3826
  onClick: onClose,
3838
3827
  "aria-label": "Close performance dashboard",
3828
+ style: {
3829
+ transition: "color 0.2s ease"
3830
+ },
3839
3831
  children: "×"
3840
3832
  }) ]
3841
3833
  }), jsxRuntime.jsxs("div", {
3842
- style: metricRowStyle,
3834
+ className: "u-flex u-items-center u-justify-between u-mb-1-5",
3843
3835
  children: [ jsxRuntime.jsx("span", {
3844
- style: labelStyle,
3836
+ className: "u-text-gray-400 u-me-3",
3845
3837
  children: "FPS"
3846
3838
  }), jsxRuntime.jsx("span", {
3839
+ className: "u-font-bold",
3847
3840
  style: {
3848
- ...valueStyle,
3849
- color: getFpsColor(metrics.fps)
3841
+ color: fpsColor
3850
3842
  },
3851
3843
  children: Math.round(metrics.fps)
3852
3844
  }) ]
3853
3845
  }), jsxRuntime.jsxs("div", {
3854
- style: metricRowStyle,
3846
+ className: "u-flex u-items-center u-justify-between u-mb-1-5",
3855
3847
  children: [ jsxRuntime.jsx("span", {
3856
- style: labelStyle,
3848
+ className: "u-text-gray-400 u-me-3",
3857
3849
  children: "Frame Time"
3858
3850
  }), jsxRuntime.jsxs("span", {
3859
- style: valueStyle,
3851
+ className: "u-font-bold",
3860
3852
  children: [ metrics.frameTime.toFixed(2), "ms" ]
3861
3853
  }) ]
3862
3854
  }), jsxRuntime.jsxs("div", {
3863
- style: metricRowStyle,
3855
+ className: "u-flex u-items-center u-justify-between u-mb-1-5",
3864
3856
  children: [ jsxRuntime.jsx("span", {
3865
- style: labelStyle,
3857
+ className: "u-text-gray-400 u-me-3",
3866
3858
  children: "Quality"
3867
3859
  }), jsxRuntime.jsx("span", {
3860
+ className: "u-font-bold u-text-uppercase",
3868
3861
  style: {
3869
- ...valueStyle,
3870
- color: (quality => {
3871
- switch (quality) {
3872
- case "high":
3873
- return "#4ade80";
3874
-
3875
- case "medium":
3876
- return "#fbbf24";
3877
-
3878
- case "low":
3879
- return "#ef4444";
3880
-
3881
- default:
3882
- return "#9ca3af";
3883
- }
3884
- })(metrics.qualityLevel),
3885
- textTransform: "uppercase",
3886
- fontSize: "11px"
3862
+ fontSize: "0.6875rem",
3863
+ // 11px
3864
+ color: getQualityColor(metrics.qualityLevel)
3887
3865
  },
3888
3866
  children: metrics.qualityLevel
3889
3867
  }) ]
3890
3868
  }), metrics.gpuMemory && jsxRuntime.jsxs("div", {
3891
- style: metricRowStyle,
3869
+ className: "u-flex u-items-center u-justify-between u-mb-1-5",
3892
3870
  children: [ jsxRuntime.jsx("span", {
3893
- style: labelStyle,
3871
+ className: "u-text-gray-400 u-me-3",
3894
3872
  children: "GPU Memory"
3895
3873
  }), jsxRuntime.jsxs("span", {
3896
- style: valueStyle,
3874
+ className: "u-font-bold",
3897
3875
  children: [ "~", Math.round(metrics.gpuMemory / 1024), "MB" ]
3898
3876
  }) ]
3899
3877
  }), metrics.isAutoScaling && jsxRuntime.jsx("div", {
3878
+ className: "u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10 u-text-center",
3900
3879
  style: {
3901
- marginTop: "8px",
3902
- paddingTop: "8px",
3903
- borderTop: "1px solid rgba(255, 255, 255, 0.1)",
3904
- fontSize: "10px",
3905
- color: "#6b7280",
3906
- textAlign: "center"
3880
+ fontSize: "0.625rem",
3881
+ // 10px
3882
+ color: "#6b7280"
3907
3883
  },
3908
3884
  children: "Auto-scaling active"
3909
3885
  }), jsxRuntime.jsxs("div", {
3910
- style: {
3911
- marginTop: "8px",
3912
- paddingTop: "8px",
3913
- borderTop: "1px solid rgba(255, 255, 255, 0.1)",
3914
- display: "flex",
3915
- alignItems: "center",
3916
- gap: "6px"
3917
- },
3886
+ className: "u-flex u-items-center u-gap-2 u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10",
3918
3887
  children: [ jsxRuntime.jsx("div", {
3888
+ className: "u-rounded-full",
3919
3889
  style: {
3920
- width: "8px",
3921
- height: "8px",
3922
- borderRadius: "50%",
3923
- backgroundColor: getFpsColor(metrics.fps),
3924
- animation: metrics.fps < 45 ? "pulse 1s infinite" : "none"
3890
+ width: "0.5rem",
3891
+ height: "0.5rem",
3892
+ flexShrink: 0,
3893
+ backgroundColor: fpsColor,
3894
+ ...isCritical && {
3895
+ animation: "perf-dashboard-pulse 1s infinite"
3896
+ }
3925
3897
  }
3926
3898
  }), jsxRuntime.jsx("span", {
3899
+ className: "u-text-xs",
3927
3900
  style: {
3928
- fontSize: "10px",
3929
- color: metrics.fps >= 58 ? "#4ade80" : metrics.fps >= 45 ? "#fbbf24" : "#ef4444"
3901
+ fontSize: "0.625rem",
3902
+ // 10px
3903
+ color: fpsColor
3930
3904
  },
3931
- children: metrics.fps >= 58 ? "Optimal" : metrics.fps >= 45 ? "Warning" : "Critical"
3905
+ children: getFpsLabel(metrics.fps)
3932
3906
  }) ]
3933
3907
  }) ]
3934
- }) : null;
3935
- };
3908
+ });
3909
+ }));
3936
3910
 
3937
- // Add pulse animation for critical FPS
3938
- if ("undefined" != typeof document) {
3939
- const styleSheet = document.createElement("style");
3940
- styleSheet.textContent = "\n @keyframes pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n ",
3941
- document.head.appendChild(styleSheet);
3942
- }
3911
+ PerformanceDashboard.displayName = "PerformanceDashboard";
3943
3912
 
3944
3913
  /**
3945
3914
  * Mobile optimization presets
@@ -3950,7 +3919,8 @@ if ("undefined" != typeof document) {
3950
3919
  /**
3951
3920
  * Performance preset - Maximum FPS, reduced quality
3952
3921
  * Best for low-end devices or when battery saving is priority
3953
- */ const PERFORMANCE_PRESET = {
3922
+ */
3923
+ const PERFORMANCE_PRESET = {
3954
3924
  distortionOctaves: 2,
3955
3925
  // Minimal FBM layers
3956
3926
  displacementScale: 50,
@@ -4113,90 +4083,21 @@ function getDevicePreset(presetName) {
4113
4083
  getPixelRatio: () => "undefined" == typeof window ? 1 : window.devicePixelRatio || 1,
4114
4084
  /** Check if device has touch support */
4115
4085
  hasTouchSupport: () => "undefined" != typeof window && ("ontouchstart" in window || navigator.maxTouchPoints > 0)
4116
- };
4117
-
4118
- /**
4119
- * AtomixGlass - A high-performance glass morphism component with liquid distortion effects
4120
- *
4121
- * Features:
4122
- * - Hardware-accelerated glass effects with SVG filters
4123
- * - Mouse-responsive liquid distortion
4124
- * - Dynamic border-radius extraction from children CSS properties
4125
- * - Automatic light/dark theme detection via overLight prop
4126
- * - Accessibility and performance optimizations
4127
- * - Multiple displacement modes (standard, polar, prominent, shader)
4128
- * - Design token integration for consistent theming
4129
- * - Focus ring support for keyboard navigation
4130
- * - Responsive breakpoints for mobile optimization
4131
- * - Enhanced ARIA attributes for screen readers
4132
- * - Time-based animation system with FBM distortion
4133
- * - Device preset optimization for performance/quality balance
4134
- *
4135
- * Design System Compliance:
4136
- * - Uses design tokens for opacity, spacing, and colors
4137
- * - Follows BEM methodology for class naming
4138
- * - Implements focus-ring mixin for accessibility
4139
- * - Supports reduced motion and high contrast preferences
4140
- *
4141
- * @example
4142
- * // Basic usage with dynamic border-radius extraction
4143
- * <AtomixGlass>
4144
- * <div style={{ borderRadius: '12px' }}>Content with 12px radius</div>
4145
- * </AtomixGlass>
4146
- *
4147
- * @example
4148
- * // Manual border-radius override
4149
- * <AtomixGlass borderRadius={20}>
4150
- * <div>Content with 20px glass radius</div>
4151
- * </AtomixGlass>
4152
- *
4153
- * @example
4154
- * // Interactive glass with click handler
4155
- * <AtomixGlass onClick={() => console.log('Clicked')} aria-label="Glass card">
4156
- * <div>Clickable content</div>
4157
- * </AtomixGlass>
4158
- *
4159
- * @example
4160
- * // OverLight - Boolean mode (explicit control)
4161
- * <AtomixGlass overLight={true}>
4162
- * <div>Content on light background</div>
4163
- * </AtomixGlass>
4164
- *
4165
- * @example
4166
- * // OverLight - Auto-detection mode
4167
- * <AtomixGlass overLight="auto">
4168
- * <div>Content with auto-detected background</div>
4169
- * </AtomixGlass>
4170
- *
4171
- * @example
4172
- * // OverLight - Object config with custom settings
4173
- * <AtomixGlass
4174
- * overLight={{
4175
- * threshold: 0.8,
4176
- * opacity: 0.6,
4177
- * contrast: 1.8,
4178
- * brightness: 1.0,
4179
- * saturationBoost: 1.5
4180
- * }}
4181
- * >
4182
- * <div>Content with custom overLight config</div>
4183
- * </AtomixGlass>
4184
- *
4185
- * @example
4186
- * // Debug mode for overLight detection
4187
- * <AtomixGlass overLight="auto" debugOverLight={true}>
4188
- * <div>Content with debug logging enabled</div>
4189
- * </AtomixGlass>
4190
- *
4191
- * @example
4192
- * // Performance-optimized for mobile devices
4193
- * <AtomixGlass devicePreset="performance" disableResponsiveBreakpoints={false}>
4194
- * <div>Mobile-optimized glass effect</div>
4195
- * </AtomixGlass>
4196
- */ function AtomixGlass({children: children, displacementScale: displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, aberrationIntensity: aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer = null, className: className = "", padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, style: style = {}, mode: mode = ATOMIX_GLASS.DEFAULTS.MODE, onClick: onClick, shaderVariant: shaderVariant = "liquidGlass", "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, role: role, tabIndex: tabIndex, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, withLiquidBlur: withLiquidBlur = !1, withBorder: withBorder = !0, withOverLightLayers: withOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS, debugPerformance: debugPerformance = !1, debugOverLight: debugOverLight = !1, height: height, width: width, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", devicePreset: devicePreset = "balanced", disableResponsiveBreakpoints: disableResponsiveBreakpoints = !1, ...rest}) {
4197
- const glassRef = React.useRef(null), contentRef = React.useRef(null), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = "fixed" === restStyle.position || "sticky" === restStyle.position, {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveBorderRadius: effectiveBorderRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveWithoutEffects: effectiveWithoutEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, getShaderTime: getShaderTime, applyTimeBasedDistortion: applyTimeBasedDistortion, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
4086
+ }, AtomixGlassInner = React.forwardRef((function({children: children, displacementScale: displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, aberrationIntensity: aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer = null, className: className = "", padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, style: style = {}, mode: mode = ATOMIX_GLASS.DEFAULTS.MODE, onClick: onClick, shaderVariant: shaderVariant = "liquidGlass", "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, role: role, tabIndex: tabIndex, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, withLiquidBlur: withLiquidBlur = !1, withBorder: withBorder = !0, withOverLightLayers: withOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS, debugPerformance: debugPerformance = !1, debugOverLight: debugOverLight = !1, height: height, width: width, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", devicePreset: devicePreset = "balanced", disableResponsiveBreakpoints: disableResponsiveBreakpoints = !1, isFixedOrSticky: propsIsFixedOrSticky, ...rest}, ref) {
4087
+ const glassRef = React.useRef(null), contentRef = React.useRef(null), internalWrapperRef = React.useRef(null), mergedRef = React.useMemo((() =>
4088
+ // Helper to merge refs
4089
+ function(...refs) {
4090
+ return node => {
4091
+ refs.forEach((ref => {
4092
+ "function" == typeof ref ? ref(node) : null != ref && (ref.current = node);
4093
+ }));
4094
+ };
4095
+ }
4096
+ // Internal implementation with forwardRef
4097
+ (ref, internalWrapperRef)), [ ref ]), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = propsIsFixedOrSticky || "fixed" === restStyle.position || "sticky" === restStyle.position, {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveBorderRadius: effectiveBorderRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveWithoutEffects: effectiveWithoutEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, getShaderTime: getShaderTime, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
4198
4098
  glassRef: glassRef,
4199
4099
  contentRef: contentRef,
4100
+ wrapperRef: internalWrapperRef,
4200
4101
  borderRadius: borderRadius,
4201
4102
  globalMousePosition: externalGlobalMousePosition,
4202
4103
  mouseOffset: externalMouseOffset,
@@ -4225,7 +4126,6 @@ function getDevicePreset(presetName) {
4225
4126
  distortionGain: distortionGain,
4226
4127
  distortionQuality: distortionQuality
4227
4128
  });
4228
- // Re-calculate only when devicePreset changes
4229
4129
  // Responsive breakpoint system - automatically adjusts parameters based on viewport
4230
4130
  useResponsiveGlass({
4231
4131
  baseParams: {
@@ -4240,22 +4140,21 @@ function getDevicePreset(presetName) {
4240
4140
  },
4241
4141
  breakpoints: MOBILE_OPTIMIZED_BREAKPOINTS,
4242
4142
  enabled: !disableResponsiveBreakpoints && "undefined" != typeof window,
4243
- // Enable unless disabled
4244
4143
  debug: !1
4245
4144
  });
4246
4145
  // Performance monitoring - tracks FPS, frame time, memory usage
4247
- const {metrics: performanceMetrics, recommendedQuality: recommendedQuality, isUnderperforming: isUnderperforming, setQualityLevel: setQualityLevel, toggleMonitoring: toggleMonitoring} = usePerformanceMonitor({
4248
- enabled: !1,
4249
- // We'll toggle manually based on prop
4146
+ const {metrics: performanceMetrics, toggleMonitoring: toggleMonitoring} = usePerformanceMonitor({
4147
+ enabled: debugPerformance,
4148
+ // Enable when debugPerformance is true
4250
4149
  debug: !1,
4251
4150
  showOverlay: !1
4252
4151
  });
4253
- // Auto-start performance monitoring if enabled (only in development)
4152
+ // Auto-start performance monitoring when debugPerformance is enabled
4254
4153
  React__default.default.useEffect((() => {
4255
- "development" === process.env.NODE_ENV && window?.enablePerformanceMonitoring && toggleMonitoring();
4154
+ debugPerformance && toggleMonitoring();
4256
4155
  // eslint-disable-next-line react-hooks/exhaustive-deps
4257
- }), []);
4258
- // Only run once on mount
4156
+ }), [ debugPerformance ]);
4157
+ // Re-run when debugPerformance changes
4259
4158
  const isOverLight = React.useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, rootLayoutStyle = React.useMemo((() => {
4260
4159
  if (!isFixedOrSticky) return {};
4261
4160
  const {position: p, top: t, left: l, right: r, bottom: b} = restStyle;
@@ -4283,34 +4182,30 @@ function getDevicePreset(presetName) {
4283
4182
  if (isFixedOrSticky) {
4284
4183
  const {position: _p, top: _t, left: _l, right: _r, bottom: _b, ...visualStyle} = restStyle;
4285
4184
  return {
4286
- ...visualStyle,
4287
- ...!effectiveWithoutEffects && {
4288
- transform: transformStyle
4289
- }
4185
+ ...visualStyle
4290
4186
  };
4291
4187
  }
4292
4188
  return {
4293
- ...restStyle,
4294
- ...!effectiveWithoutEffects && {
4295
- transform: transformStyle
4296
- }
4189
+ ...restStyle
4297
4190
  };
4298
- }), [ isFixedOrSticky, restStyle, effectiveWithoutEffects, transformStyle ]);
4191
+ }), [ isFixedOrSticky, restStyle ]);
4299
4192
  // Build className with state modifiers
4300
4193
  const componentClassName = [ ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`, effectiveWithoutEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`, className ].filter(Boolean).join(" "), positionStyles = React.useMemo((() => ({
4301
4194
  position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
4302
- top: isFixedOrSticky ? 0 : restStyle.top || 0,
4303
- left: isFixedOrSticky ? 0 : restStyle.left || 0
4304
- })), [ isFixedOrSticky, restStyle.position, restStyle.top, restStyle.left ]), adjustedSize = React.useMemo((() => {
4195
+ top: isFixedOrSticky ? restStyle.top ?? 0 : 0,
4196
+ left: isFixedOrSticky ? restStyle.left ?? 0 : 0,
4197
+ right: isFixedOrSticky ? restStyle.right ?? "auto" : "auto",
4198
+ bottom: isFixedOrSticky ? restStyle.bottom ?? "auto" : "auto"
4199
+ })), [ isFixedOrSticky, restStyle.position, restStyle.top, restStyle.left, restStyle.right, restStyle.bottom ]), adjustedSize = React.useMemo((() => {
4305
4200
  // Keep a reference to positionStyles to avoid unused-variable lint,
4306
4201
  // but sizing is driven by explicit width/height or measured size.
4307
4202
  positionStyles.position;
4308
- const resolveLength = (value, measured) => void 0 !== value ? "number" == typeof value ? `${value}px` : value : measured > 0 ? `${measured}px` : "100%", effectiveWidth = width ?? restStyle.width, effectiveHeight = height ?? restStyle.height;
4203
+ const resolveLength = (value, measured) => void 0 !== value && isFixedOrSticky ? "number" == typeof value ? `${value}px` : value : measured > 0 && isFixedOrSticky ? `${measured}px` : "100%", effectiveWidth = width ?? restStyle.width, effectiveHeight = height ?? restStyle.height;
4309
4204
  return {
4310
4205
  width: resolveLength(effectiveWidth, glassSize.width),
4311
4206
  height: resolveLength(effectiveHeight, glassSize.height)
4312
4207
  };
4313
- }), [ width, height, restStyle.width, restStyle.height, positionStyles.position, glassSize.width, glassSize.height ]), gradientValues = React.useMemo((() => {
4208
+ }), [ width, height, restStyle.width, restStyle.height, positionStyles.position, glassSize.width, glassSize.height, isFixedOrSticky ]), gradientValues = React.useMemo((() => {
4314
4209
  const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT;
4315
4210
  return {
4316
4211
  borderGradientAngle: GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER,
@@ -4340,33 +4235,32 @@ function getDevicePreset(presetName) {
4340
4235
  absMx: absMx,
4341
4236
  absMy: absMy
4342
4237
  };
4343
- }), [ mouseOffset.x, mouseOffset.y ]), opacityValues = React.useMemo((() => {
4344
- const overLightOpacity = overLightConfig.opacity;
4345
- return {
4346
- hover1: isHovered || isActive ? .5 : 0,
4347
- hover2: isActive ? .5 : 0,
4348
- hover3: isHovered ? .4 : isActive ? .8 : 0,
4349
- base: isOverLight ? overLightOpacity || .4 : 0,
4350
- over: isOverLight ? 1.1 * (overLightOpacity || .4) : 0
4351
- };
4352
- }), [ isHovered, isActive, isOverLight, overLightConfig.opacity ]), glassVars = React.useMemo((() => {
4353
- const whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, {borderGradientAngle: borderGradientAngle, borderStop1: borderStop1, borderStop2: borderStop2, borderOpacities: borderOpacities, hoverPositions: hoverPositions, basePosition: basePosition, mx: mx, my: my, absMx: absMx, absMy: absMy} = gradientValues, configBorderOpacity = overLightConfig?.borderOpacity ?? 1;
4238
+ }), [ mouseOffset.x, mouseOffset.y ]), clampedOverLightOpacity = Math.max(0, Math.min(1, overLightConfig?.opacity ?? .4)), clampedBorderOpacity = Math.max(0, Math.min(1, overLightConfig?.borderOpacity ?? 1)), opacityValues = React.useMemo((() => ({
4239
+ hover1: isHovered || isActive ? .5 : 0,
4240
+ hover2: isActive ? .5 : 0,
4241
+ hover3: isHovered ? .4 : isActive ? .8 : 0,
4242
+ base: isOverLight ? clampedOverLightOpacity || .4 : 0,
4243
+ over: isOverLight ? 1.1 * (clampedOverLightOpacity || .4) : 0
4244
+ })), [ isHovered, isActive, isOverLight, clampedOverLightOpacity ]), glassVars = React.useMemo((() => {
4245
+ const whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, {borderGradientAngle: borderGradientAngle, borderStop1: borderStop1, borderStop2: borderStop2, borderOpacities: borderOpacities, hoverPositions: hoverPositions, basePosition: basePosition, mx: mx, my: my, absMx: absMx, absMy: absMy} = gradientValues;
4354
4246
  return {
4355
4247
  ...void 0 !== customZIndex && {
4356
4248
  "--atomix-glass-base-z-index": customZIndex
4357
4249
  },
4358
4250
  "--atomix-glass-radius": `${effectiveBorderRadius}px`,
4359
4251
  "--atomix-glass-transform": transformStyle || "none",
4360
- // Internal decorative layers are positioned relative to the root;
4361
- "--atomix-glass-position": rootLayoutStyle.position,
4362
- "--atomix-glass-top": `${isFixedOrSticky ? rootLayoutStyle.top : 0}px`,
4363
- "--atomix-glass-left": `${isFixedOrSticky ? rootLayoutStyle.left : 0}px`,
4252
+ "--atomix-glass-container-position": `${isFixedOrSticky ? rootLayoutStyle.position : positionStyles.position}`,
4253
+ "--atomix-glass-position": `${isFixedOrSticky ? rootLayoutStyle.position : positionStyles.position}`,
4254
+ "--atomix-glass-top": `${isFixedOrSticky ? restStyle.top ?? 0 : 0}px`,
4255
+ "--atomix-glass-left": `${isFixedOrSticky ? restStyle.left ?? 0 : 0}px`,
4256
+ "--atomix-glass-right": isFixedOrSticky ? restStyle.right ?? "auto" : "auto",
4257
+ "--atomix-glass-bottom": isFixedOrSticky ? restStyle.bottom ?? "auto" : "auto",
4364
4258
  "--atomix-glass-width": adjustedSize.width,
4365
4259
  "--atomix-glass-height": adjustedSize.height,
4366
- "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
4260
+ "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.125rem)",
4367
4261
  "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay",
4368
- "--atomix-glass-border-gradient-1": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[0] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[1] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
4369
- "--atomix-glass-border-gradient-2": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[2] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[3] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
4262
+ "--atomix-glass-border-gradient-1": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[0] ?? 1) * clampedBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[1] ?? 1) * clampedBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
4263
+ "--atomix-glass-border-gradient-2": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[2] ?? 1) * clampedBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[3] ?? 1) * clampedBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
4370
4264
  "--atomix-glass-hover-1-opacity": opacityValues.hover1,
4371
4265
  "--atomix-glass-hover-1-gradient": isOverLight ? `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_STOP}%)`,
4372
4266
  "--atomix-glass-hover-2-opacity": opacityValues.hover2,
@@ -4380,13 +4274,14 @@ function getDevicePreset(presetName) {
4380
4274
  "--atomix-glass-overlay-highlight-opacity": opacityValues.over * ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER,
4381
4275
  "--atomix-glass-overlay-highlight-bg": `radial-gradient(circle at ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_X}% ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_Y}%, rgba(255, 255, 255, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.WHITE_OPACITY}) 0%, transparent ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.STOP}%)`
4382
4276
  };
4383
- }), [ gradientValues, opacityValues, effectiveBorderRadius, transformStyle, adjustedSize, isOverLight, overLightConfig.borderOpacity, customZIndex, rootLayoutStyle, isFixedOrSticky ]), renderBackgroundLayer = layerType => jsxRuntime.jsx("div", {
4277
+ }), [ gradientValues, opacityValues, effectiveBorderRadius, transformStyle, adjustedSize, isOverLight, clampedBorderOpacity, customZIndex, isFixedOrSticky, positionStyles.position, rootLayoutStyle.position, restStyle.top, restStyle.left, restStyle.right, restStyle.bottom ]), renderBackgroundLayer = layerType => jsxRuntime.jsx("div", {
4384
4278
  className: [ ATOMIX_GLASS.BACKGROUND_LAYER_CLASS, "dark" === layerType ? ATOMIX_GLASS.BACKGROUND_LAYER_DARK_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_BLACK_CLASS, isOverLight ? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS ].filter(Boolean).join(" ")
4385
4279
  });
4386
4280
  // Calculate position and size styles for internal layers
4387
4281
  // When root is fixed/sticky, internal layers use absolute (relative to root)
4388
4282
  return jsxRuntime.jsxs("div", {
4389
4283
  ...rest,
4284
+ ref: mergedRef,
4390
4285
  className: componentClassName,
4391
4286
  style: {
4392
4287
  ...glassVars
@@ -4396,17 +4291,14 @@ function getDevicePreset(presetName) {
4396
4291
  "aria-label": ariaLabel,
4397
4292
  "aria-describedby": ariaDescribedBy,
4398
4293
  "aria-disabled": !(!onClick || !effectiveWithoutEffects) || !onClick && void 0,
4399
- "aria-pressed": !(!onClick || !isActive) || !onClick && void 0,
4294
+ "aria-pressed": void 0,
4400
4295
  onKeyDown: onClick ? handleKeyDown : void 0,
4401
4296
  children: [ jsxRuntime.jsx(AtomixGlassContainer, {
4402
4297
  ref: glassRef,
4403
4298
  contentRef: contentRef,
4404
4299
  className: className,
4405
4300
  style: {
4406
- ...restStyle,
4407
- ...!isFixedOrSticky && {
4408
- position: "relative"
4409
- }
4301
+ ...restStyle
4410
4302
  },
4411
4303
  borderRadius: effectiveBorderRadius,
4412
4304
  displacementScale: effectiveWithoutEffects ? 0 : "shader" === mode ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_DISPLACEMENT : isOverLight ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.OVER_LIGHT_DISPLACEMENT : displacementScale,
@@ -4442,6 +4334,7 @@ function getDevicePreset(presetName) {
4442
4334
  effectiveReducedMotion: effectiveReducedMotion,
4443
4335
  shaderVariant: shaderVariant,
4444
4336
  withLiquidBlur: withLiquidBlur,
4337
+ isFixedOrSticky: isFixedOrSticky,
4445
4338
  // Phase 1: Animation System props
4446
4339
  shaderTime: getShaderTime(),
4447
4340
  withTimeAnimation: withTimeAnimation,
@@ -4470,6 +4363,8 @@ function getDevicePreset(presetName) {
4470
4363
  }) ]
4471
4364
  }), withBorder && jsxRuntime.jsxs(jsxRuntime.Fragment, {
4472
4365
  children: [ jsxRuntime.jsx("span", {
4366
+ className: ATOMIX_GLASS.BORDER_BACKDROP_CLASS
4367
+ }), jsxRuntime.jsx("span", {
4473
4368
  className: ATOMIX_GLASS.BORDER_1_CLASS
4474
4369
  }), jsxRuntime.jsx("span", {
4475
4370
  className: ATOMIX_GLASS.BORDER_2_CLASS
@@ -4480,10 +4375,15 @@ function getDevicePreset(presetName) {
4480
4375
  onClose: () => {}
4481
4376
  }) ]
4482
4377
  });
4483
- }
4378
+ }));
4484
4379
 
4485
- // Default icon
4486
- const DefaultIcon = () => jsxRuntime.jsx("i", {
4380
+ AtomixGlassInner.displayName = "AtomixGlass";
4381
+
4382
+ /**
4383
+ * AtomixGlass - wrapped with React.memo to prevent unnecessary re-renders.
4384
+ * Ref is forwarded to the root `<div>` element.
4385
+ */
4386
+ const AtomixGlass = React.memo(AtomixGlassInner), DefaultIcon = () => jsxRuntime.jsx("i", {
4487
4387
  className: "c-accordion__icon",
4488
4388
  "aria-hidden": "true",
4489
4389
  children: jsxRuntime.jsx("svg", {
@@ -4517,6 +4417,7 @@ const DefaultIcon = () => jsxRuntime.jsx("i", {
4517
4417
  });
4518
4418
  }));
4519
4419
 
4420
+ // Default icon
4520
4421
  AccordionHeader.displayName = "AccordionHeader";
4521
4422
 
4522
4423
  const AccordionBody = React.forwardRef((({children: children, className: className = "", panelRef: panelRef, contentRef: contentRef, ...props}, ref) => {
@@ -5443,7 +5344,100 @@ class ThemeNaming {
5443
5344
 
5444
5345
  ThemeNaming.prefix = "atomix";
5445
5346
 
5446
- const Button = React__default.default.memo( React.forwardRef((({label: label, children: children, onClick: onClick, variant: variant = "primary", size: size = "md", disabled: disabled = !1, loading: loading = !1, loadingText: loadingText, icon: icon, iconName: iconName, iconSize: iconSize = "sm", iconPosition: iconPosition = "start", iconOnly: iconOnly = !1, rounded: rounded = !1, fullWidth: fullWidth = !1, block: block = !1, active: active = !1, selected: selected = !1, type: type = "button", className: className = "", as: Component = "button", href: href, target: target, glass: glass, onHover: onHover, onFocus: onFocus, onBlur: onBlur, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, "aria-expanded": ariaExpanded, "aria-controls": ariaControls, tabIndex: tabIndex, style: style, linkComponent: linkComponent, ...props}, ref) => {
5347
+ 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) {
5348
+ return function(that, callbackfn, argumentsLength, memo) {
5349
+ var O = toObject(that), self = IndexedObject(O), length = lengthOfArrayLike(O);
5350
+ if (aCallable(callbackfn), 0 === length && argumentsLength < 2) throw new $TypeError(REDUCE_EMPTY);
5351
+ var index = IS_RIGHT ? length - 1 : 0, i = IS_RIGHT ? -1 : 1;
5352
+ if (argumentsLength < 2) for (;;) {
5353
+ if (index in self) {
5354
+ memo = self[index], index += i;
5355
+ break;
5356
+ }
5357
+ if (index += i, IS_RIGHT ? index < 0 : length <= index) throw new $TypeError(REDUCE_EMPTY);
5358
+ }
5359
+ for (;IS_RIGHT ? index >= 0 : length > index; index += i) index in self && (memo = callbackfn(memo, self[index], index, O));
5360
+ return memo;
5361
+ };
5362
+ }, arrayReduce = {
5363
+ // `Array.prototype.reduce` method
5364
+ // https://tc39.es/ecma262/#sec-array.prototype.reduce
5365
+ left: createMethod(!1),
5366
+ // `Array.prototype.reduceRight` method
5367
+ // https://tc39.es/ecma262/#sec-array.prototype.reduceright
5368
+ right: createMethod(!0)
5369
+ }, fails = fails$9, globalThis$1 = globalThis_1, userAgent = environmentUserAgent, classof = classofRaw$2, userAgentStartsWith = function(string) {
5370
+ return userAgent.slice(0, string.length) === string;
5371
+ }, 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;
5372
+
5373
+ // `Array.prototype.reduce` method
5374
+ // https://tc39.es/ecma262/#sec-array.prototype.reduce
5375
+ _export({
5376
+ target: "Array",
5377
+ proto: !0,
5378
+ forced: !("NODE" === environment) && environmentV8Version > 79 && environmentV8Version < 83 || !function(METHOD_NAME, argument) {
5379
+ var method = [][METHOD_NAME];
5380
+ return !!method && fails((function() {
5381
+ // eslint-disable-next-line no-useless-call -- required for testing
5382
+ method.call(null, argument || function() {
5383
+ return 1;
5384
+ }, 1);
5385
+ }));
5386
+ }("reduce")
5387
+ }, {
5388
+ reduce: function(callbackfn /* , initialValue */) {
5389
+ var length = arguments.length;
5390
+ return $reduce(this, callbackfn, length, length > 1 ? arguments[1] : void 0);
5391
+ }
5392
+ });
5393
+
5394
+ var reduce$3 = getBuiltInPrototypeMethod$3("Array", "reduce"), isPrototypeOf = objectIsPrototypeOf, method = reduce$3, ArrayPrototype = Array.prototype, _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
5395
+ var own = it.reduce;
5396
+ return it === ArrayPrototype || isPrototypeOf(ArrayPrototype, it) && own === ArrayPrototype.reduce ? method : own;
5397
+ }));
5398
+
5399
+ /**
5400
+ * Render a slot with the given props
5401
+ *
5402
+ * Priority order:
5403
+ * 1. render function
5404
+ * 2. component
5405
+ * 3. children
5406
+ * 4. fallback
5407
+ *
5408
+ * @example
5409
+ * renderSlot(
5410
+ * { render: (props) => <CustomButton {...props} /> },
5411
+ * { onClick: handleClick, children: 'Click me' }
5412
+ * )
5413
+ */
5414
+ function renderSlot(slot, props, fallback) {
5415
+ // No slot provided, use fallback
5416
+ if (!slot) return fallback;
5417
+ // Slot is a plain React node
5418
+ if ( React__default.default.isValidElement(slot) || "string" == typeof slot || "number" == typeof slot) return slot;
5419
+ // Slot is an object with rendering options
5420
+ if ("object" == typeof slot && null !== slot) {
5421
+ const slotObj = slot;
5422
+ // Priority 1: render function
5423
+ if (slotObj.render && "function" == typeof slotObj.render) return slotObj.render(props);
5424
+ // Priority 2: component
5425
+ if (slotObj.component) {
5426
+ const Component = slotObj.component;
5427
+ return jsxRuntime.jsx(Component, {
5428
+ ...props
5429
+ });
5430
+ }
5431
+ // Priority 3: children
5432
+ if (void 0 !== slotObj.children) return slotObj.children;
5433
+ }
5434
+ // Fallback
5435
+ return fallback;
5436
+ }
5437
+
5438
+ /**
5439
+ * Check if a value is a slot configuration
5440
+ */ const Button = React__default.default.memo( React.forwardRef((({label: label, children: children, onClick: onClick, variant: variant = "primary", size: size = "md", disabled: disabled = !1, loading: loading = !1, loadingText: loadingText, icon: icon, iconName: iconName, iconSize: iconSize = "sm", iconPosition: iconPosition = "start", iconOnly: iconOnly = !1, rounded: rounded = !1, fullWidth: fullWidth = !1, block: block = !1, active: active = !1, selected: selected = !1, type: type = "button", className: className = "", as: Component = "button", href: href, target: target, glass: glass, onHover: onHover, onFocus: onFocus, onBlur: onBlur, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, "aria-expanded": ariaExpanded, "aria-controls": ariaControls, tabIndex: tabIndex, style: style, linkComponent: linkComponent, slots: slots, ...props}, ref) => {
5447
5441
  const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href), iconElement = iconName ? jsxRuntime.jsx(Icon, {
5448
5442
  name: iconName,
5449
5443
  size: iconSize
@@ -5459,17 +5453,28 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
5459
5453
  children: [ loading && jsxRuntime.jsx("span", {
5460
5454
  className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.SPINNER_ELEMENT),
5461
5455
  "aria-hidden": "true",
5462
- children: jsxRuntime.jsx(Spinner, {
5456
+ children: renderSlot(slots?.spinner, {
5457
+ className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.SPINNER_ELEMENT),
5463
5458
  size: spinnerSize,
5464
5459
  variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
5465
- })
5460
+ }, jsxRuntime.jsx(Spinner, {
5461
+ size: spinnerSize,
5462
+ variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
5463
+ }))
5466
5464
  }), iconElement && !loading && jsxRuntime.jsx("span", {
5467
5465
  className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.ICON_ELEMENT),
5468
5466
  "aria-hidden": "true",
5469
- children: iconElement
5467
+ children: renderSlot(slots?.icon, {
5468
+ className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.ICON_ELEMENT),
5469
+ children: iconElement,
5470
+ size: iconSize
5471
+ }, iconElement)
5470
5472
  }), !iconOnly && buttonText && jsxRuntime.jsx("span", {
5471
5473
  className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.LABEL_ELEMENT),
5472
- children: buttonText
5474
+ children: renderSlot(slots?.label, {
5475
+ className: ThemeNaming.bemClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.LABEL_ELEMENT),
5476
+ children: buttonText
5477
+ }, buttonText)
5473
5478
  }) ]
5474
5479
  }), buttonProps = {
5475
5480
  className: buttonClass,
@@ -5486,48 +5491,59 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
5486
5491
  tabIndex: void 0 !== tabIndex ? tabIndex : isDisabled ? -1 : 0,
5487
5492
  style: style,
5488
5493
  ...props
5489
- };
5490
- // Determine if we should render as a link
5491
- // If disabled, we still check href, but we might want to render as button or anchor with aria-disabled
5492
- // The previous logic was Boolean(href && !isDisabled). This meant if disabled, it renders as <button>.
5493
- // This is a safe fallback for disabled links.
5494
- let content;
5495
- // Render as anchor if href is provided
5496
- if (shouldRenderAsLink)
5497
- // Use custom linkComponent if provided (e.g., Next.js Link)
5498
- if (linkComponent) {
5499
- const LinkComp = linkComponent, linkProps = {
5494
+ }, buttonChildren = renderSlot(slots?.root, {
5495
+ className: buttonClass,
5496
+ children: buttonContent,
5497
+ disabled: isDisabled,
5498
+ loading: loading,
5499
+ onClick: handleClickEvent,
5500
+ type: type,
5501
+ "aria-label": safeAriaLabel,
5502
+ "aria-disabled": isDisabled,
5503
+ "aria-busy": loading
5504
+ }, (() => {
5505
+ // Render as anchor if href is provided
5506
+ if (shouldRenderAsLink) {
5507
+ // Use custom linkComponent if provided (e.g., Next.js Link)
5508
+ if (linkComponent) {
5509
+ const LinkComp = linkComponent, linkProps = {
5510
+ ...buttonProps,
5511
+ ref: ref,
5512
+ // linkComponent usually forwards ref to anchor
5513
+ href: isDisabled ? void 0 : href,
5514
+ to: isDisabled ? void 0 : href,
5515
+ target: target,
5516
+ rel: "_blank" === target ? "noopener noreferrer" : void 0
5517
+ };
5518
+ return jsxRuntime.jsx(LinkComp, {
5519
+ ...linkProps,
5520
+ children: buttonContent
5521
+ });
5522
+ }
5523
+ // Fallback to regular anchor tag
5524
+ return jsxRuntime.jsx("a", {
5525
+ ...buttonProps,
5526
+ ref: ref,
5527
+ href: isDisabled ? void 0 : href,
5528
+ target: target,
5529
+ rel: "_blank" === target ? "noopener noreferrer" : void 0,
5530
+ children: buttonContent
5531
+ });
5532
+ }
5533
+ // Default button rendering
5534
+ return jsxRuntime.jsx(Component, {
5500
5535
  ...buttonProps,
5501
5536
  ref: ref,
5502
- // linkComponent usually forwards ref to anchor
5503
- href: isDisabled ? void 0 : href,
5504
- to: isDisabled ? void 0 : href,
5505
- target: target,
5506
- rel: "_blank" === target ? "noopener noreferrer" : void 0
5507
- };
5508
- content = jsxRuntime.jsx(LinkComp, {
5509
- ...linkProps,
5537
+ type: "button" === Component ? type : void 0,
5538
+ disabled: isDisabled,
5510
5539
  children: buttonContent
5511
5540
  });
5512
- } else
5513
- // Fallback to regular anchor tag
5514
- content = jsxRuntime.jsx("a", {
5515
- ...buttonProps,
5516
- ref: ref,
5517
- href: isDisabled ? void 0 : href,
5518
- target: target,
5519
- rel: "_blank" === target ? "noopener noreferrer" : void 0,
5520
- children: buttonContent
5521
- }); else
5522
- // Default button rendering
5523
- content = jsxRuntime.jsx(Component, {
5524
- ...buttonProps,
5525
- ref: ref,
5526
- type: "button" === Component ? type : void 0,
5527
- disabled: isDisabled,
5528
- children: buttonContent
5529
- });
5530
- if (glass) {
5541
+ })());
5542
+ // Determine if we should render as a link
5543
+ // If disabled, we still check href, but we might want to render as button or anchor with aria-disabled
5544
+ // The previous logic was Boolean(href && !isDisabled). This meant if disabled, it renders as <button>.
5545
+ // This is a safe fallback for disabled links.
5546
+ if (glass) {
5531
5547
  // Default glass props
5532
5548
  const defaultGlassProps = {
5533
5549
  displacementScale: 20,
@@ -5540,10 +5556,10 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
5540
5556
  };
5541
5557
  return jsxRuntime.jsx(AtomixGlass, {
5542
5558
  ...glassProps,
5543
- children: content
5559
+ children: buttonChildren
5544
5560
  });
5545
5561
  }
5546
- return content;
5562
+ return buttonChildren;
5547
5563
  })));
5548
5564
 
5549
5565
  Button.displayName = "Button";
@@ -5651,7 +5667,7 @@ const CalloutContent = React.forwardRef((({children: children, className: class
5651
5667
 
5652
5668
  CalloutContent.displayName = "CalloutContent";
5653
5669
 
5654
- const Callout = React.memo((({title: title, children: children, icon: icon, variant: variant = "primary", onClose: onClose, actions: actions, compact: compact = !1, isToast: isToast = !1, glass: glass, className: className, style: style, ...props}) => {
5670
+ const CalloutComponentBase = ({title: title, children: children, icon: icon, variant: variant = "primary", onClose: onClose, actions: actions, compact: compact = !1, isToast: isToast = !1, glass: glass, className: className, style: style, ...props}) => {
5655
5671
  const {generateCalloutClass: generateCalloutClass, handleClose: handleClose} =
5656
5672
  /**
5657
5673
  * Callout state and functionality
@@ -5777,7 +5793,7 @@ const Callout = React.memo((({title: title, children: children, icon: icon, var
5777
5793
  style: style,
5778
5794
  children: calloutContent
5779
5795
  });
5780
- }));
5796
+ }, Callout = React.memo(CalloutComponentBase);
5781
5797
 
5782
5798
  Callout.displayName = "Callout",
5783
5799
  // Attach subcomponents
@@ -6067,60 +6083,6 @@ const ElevationCard = ({elevationClass: elevationClass = "is-elevated", classNam
6067
6083
  });
6068
6084
  };
6069
6085
 
6070
- ElevationCard.displayName = "ElevationCard";
6071
-
6072
- 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) {
6073
- return function(that, callbackfn, argumentsLength, memo) {
6074
- var O = toObject(that), self = IndexedObject(O), length = lengthOfArrayLike(O);
6075
- if (aCallable(callbackfn), 0 === length && argumentsLength < 2) throw new $TypeError(REDUCE_EMPTY);
6076
- var index = IS_RIGHT ? length - 1 : 0, i = IS_RIGHT ? -1 : 1;
6077
- if (argumentsLength < 2) for (;;) {
6078
- if (index in self) {
6079
- memo = self[index], index += i;
6080
- break;
6081
- }
6082
- if (index += i, IS_RIGHT ? index < 0 : length <= index) throw new $TypeError(REDUCE_EMPTY);
6083
- }
6084
- for (;IS_RIGHT ? index >= 0 : length > index; index += i) index in self && (memo = callbackfn(memo, self[index], index, O));
6085
- return memo;
6086
- };
6087
- }, arrayReduce = {
6088
- // `Array.prototype.reduce` method
6089
- // https://tc39.es/ecma262/#sec-array.prototype.reduce
6090
- left: createMethod(!1),
6091
- // `Array.prototype.reduceRight` method
6092
- // https://tc39.es/ecma262/#sec-array.prototype.reduceright
6093
- right: createMethod(!0)
6094
- }, fails = fails$9, globalThis$1 = globalThis_1, userAgent = environmentUserAgent, classof = classofRaw$2, userAgentStartsWith = function(string) {
6095
- return userAgent.slice(0, string.length) === string;
6096
- }, 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;
6097
-
6098
- // `Array.prototype.reduce` method
6099
- // https://tc39.es/ecma262/#sec-array.prototype.reduce
6100
- _export({
6101
- target: "Array",
6102
- proto: !0,
6103
- forced: !("NODE" === environment) && environmentV8Version > 79 && environmentV8Version < 83 || !function(METHOD_NAME, argument) {
6104
- var method = [][METHOD_NAME];
6105
- return !!method && fails((function() {
6106
- // eslint-disable-next-line no-useless-call -- required for testing
6107
- method.call(null, argument || function() {
6108
- return 1;
6109
- }, 1);
6110
- }));
6111
- }("reduce")
6112
- }, {
6113
- reduce: function(callbackfn /* , initialValue */) {
6114
- var length = arguments.length;
6115
- return $reduce(this, callbackfn, length, length > 1 ? arguments[1] : void 0);
6116
- }
6117
- });
6118
-
6119
- var reduce$3 = getBuiltInPrototypeMethod$3("Array", "reduce"), isPrototypeOf = objectIsPrototypeOf, method = reduce$3, ArrayPrototype = Array.prototype, _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
6120
- var own = it.reduce;
6121
- return it === ArrayPrototype || isPrototypeOf(ArrayPrototype, it) && own === ArrayPrototype.reduce ? method : own;
6122
- }));
6123
-
6124
6086
  /**
6125
6087
  * Comprehensive chart hook with shared functionality
6126
6088
  * @param initialProps - Initial chart properties
@@ -6158,8 +6120,11 @@ function useChart(initialProps) {
6158
6120
  }), animationFrameRef = React.useRef(null);
6159
6121
  // Default chart properties
6160
6122
  // Cleanup animation frame on unmount
6161
- React.useEffect((() => () => {
6162
- animationFrameRef.current && cancelAnimationFrame(animationFrameRef.current);
6123
+ React.useEffect((() => {
6124
+ const currentRef = animationFrameRef.current;
6125
+ return () => {
6126
+ currentRef && cancelAnimationFrame(currentRef);
6127
+ };
6163
6128
  }), []);
6164
6129
  /**
6165
6130
  * Point interaction handlers
@@ -6550,7 +6515,9 @@ function getDatasetBounds(data) {
6550
6515
 
6551
6516
  /**
6552
6517
  * Hook for managing chart toolbar state and generating chart-specific configurations
6553
- */ const ChartToolbar = React.memo( React.forwardRef((({chartType: chartType = "line", groups: groups = [], enableDefaults: enableDefaults = !0, defaults: defaults = {
6518
+ */ ElevationCard.displayName = "ElevationCard";
6519
+
6520
+ const ChartToolbar = React.memo( React.forwardRef((({chartType: chartType = "line", groups: groups = [], enableDefaults: enableDefaults = !0, defaults: defaults = {
6554
6521
  refresh: !0,
6555
6522
  export: !0,
6556
6523
  fullscreen: !0,
@@ -7040,8 +7007,8 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
7040
7007
  }), [ chartType ]), finalDefaults = React.useMemo((() => ({
7041
7008
  ...getChartDefaults(),
7042
7009
  ...defaults
7043
- })), [ getChartDefaults, defaults ]), enhancedHandlers = {
7044
- onRefresh: React.useCallback((() => {
7010
+ })), [ getChartDefaults, defaults ]), enhancedHandlers = React.useMemo((() => ({
7011
+ onRefresh: () => {
7045
7012
  setState((prev => ({
7046
7013
  ...prev,
7047
7014
  isRefreshing: !0
@@ -7051,8 +7018,8 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
7051
7018
  isRefreshing: !1
7052
7019
  })));
7053
7020
  }), 1e3);
7054
- }), [ handlers.onRefresh ]),
7055
- onExport: React.useCallback((async format => {
7021
+ },
7022
+ onExport: async format => {
7056
7023
  setState((prev => ({
7057
7024
  ...prev,
7058
7025
  isExporting: !0
@@ -7065,70 +7032,70 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
7065
7032
  isExporting: !1
7066
7033
  })));
7067
7034
  }
7068
- }), [ handlers.onExport ]),
7069
- onFullscreen: React.useCallback((isFullscreen => {
7035
+ },
7036
+ onFullscreen: isFullscreen => {
7070
7037
  setState((prev => ({
7071
7038
  ...prev,
7072
7039
  isFullscreen: isFullscreen
7073
7040
  }))), handlers.onFullscreen?.(isFullscreen);
7074
- }), [ handlers.onFullscreen ]),
7075
- onZoomIn: React.useCallback((() => {
7041
+ },
7042
+ onZoomIn: () => {
7076
7043
  setState((prev => ({
7077
7044
  ...prev,
7078
7045
  zoomLevel: Math.min(1.2 * prev.zoomLevel, 5)
7079
7046
  }))), handlers.onZoomIn?.();
7080
- }), [ handlers.onZoomIn ]),
7081
- onZoomOut: React.useCallback((() => {
7047
+ },
7048
+ onZoomOut: () => {
7082
7049
  setState((prev => ({
7083
7050
  ...prev,
7084
7051
  zoomLevel: Math.max(prev.zoomLevel / 1.2, .2)
7085
7052
  }))), handlers.onZoomOut?.();
7086
- }), [ handlers.onZoomOut ]),
7087
- onZoomReset: React.useCallback((() => {
7053
+ },
7054
+ onZoomReset: () => {
7088
7055
  setState((prev => ({
7089
7056
  ...prev,
7090
7057
  zoomLevel: 1
7091
7058
  }))), handlers.onZoomReset?.();
7092
- }), [ handlers.onZoomReset ]),
7093
- onPanToggle: React.useCallback((enabled => {
7059
+ },
7060
+ onPanToggle: enabled => {
7094
7061
  setState((prev => ({
7095
7062
  ...prev,
7096
7063
  panEnabled: enabled
7097
7064
  }))), handlers.onPanToggle?.(enabled);
7098
- }), [ handlers.onPanToggle ]),
7099
- onReset: React.useCallback((() => {
7065
+ },
7066
+ onReset: () => {
7100
7067
  setState((prev => ({
7101
7068
  ...prev,
7102
7069
  zoomLevel: 1,
7103
7070
  panEnabled: !1
7104
7071
  }))), handlers.onReset?.();
7105
- }), [ handlers.onReset ]),
7106
- onGridToggle: React.useCallback((show => {
7072
+ },
7073
+ onGridToggle: show => {
7107
7074
  setState((prev => ({
7108
7075
  ...prev,
7109
7076
  showGrid: show
7110
7077
  }))), handlers.onGridToggle?.(show);
7111
- }), [ handlers.onGridToggle ]),
7112
- onLegendToggle: React.useCallback((show => {
7078
+ },
7079
+ onLegendToggle: show => {
7113
7080
  setState((prev => ({
7114
7081
  ...prev,
7115
7082
  showLegend: show
7116
7083
  }))), handlers.onLegendToggle?.(show);
7117
- }), [ handlers.onLegendToggle ]),
7118
- onTooltipsToggle: React.useCallback((show => {
7084
+ },
7085
+ onTooltipsToggle: show => {
7119
7086
  setState((prev => ({
7120
7087
  ...prev,
7121
7088
  showTooltips: show
7122
7089
  }))), handlers.onTooltipsToggle?.(show);
7123
- }), [ handlers.onTooltipsToggle ]),
7124
- onAnimationsToggle: React.useCallback((enabled => {
7090
+ },
7091
+ onAnimationsToggle: enabled => {
7125
7092
  setState((prev => ({
7126
7093
  ...prev,
7127
7094
  animationsEnabled: enabled
7128
7095
  }))), handlers.onAnimationsToggle?.(enabled);
7129
- }), [ handlers.onAnimationsToggle ]),
7130
- onSettings: React.useCallback((() => {}), [])
7131
- }, generateToolbarGroups = React.useCallback((() => {
7096
+ },
7097
+ onSettings: () => {}
7098
+ })), [ handlers ]), generateToolbarGroups = React.useCallback((() => {
7132
7099
  const groups = [], dataActions = [];
7133
7100
  // Data actions group
7134
7101
  finalDefaults.refresh && dataActions.push({
@@ -7253,7 +7220,7 @@ toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, custom
7253
7220
  actions: customActions
7254
7221
  });
7255
7222
  return groups;
7256
- }), [ chartType, finalDefaults, state, enhancedHandlers, customActions, customGroups ]);
7223
+ }), [ finalDefaults, state, enhancedHandlers, customActions, customGroups ]);
7257
7224
  // Keyboard shortcuts
7258
7225
  return React.useEffect((() => {
7259
7226
  const handleKeyDown = event => {
@@ -7845,7 +7812,7 @@ const ChartRenderer = React.memo( React.forwardRef((({datasets: datasets = [],
7845
7812
  announcement: announcement,
7846
7813
  focusedPoint: focusedPoint,
7847
7814
  getAccessibleDescription: () => "Chart description"
7848
- })), [ announcement, focusedPoint ]), transform = React.useMemo((() => chartContext ? `translate(${chartContext.panOffset.x}px, ${chartContext.panOffset.y}px) scale(${chartContext.zoomLevel})` : ""), [ chartContext?.panOffset.x, chartContext?.panOffset.y, chartContext?.zoomLevel ]), chartData = React.useMemo((() => {
7815
+ })), [ announcement, focusedPoint ]), transform = React.useMemo((() => chartContext ? `translate(${chartContext.panOffset.x}px, ${chartContext.panOffset.y}px) scale(${chartContext.zoomLevel})` : ""), [ chartContext ]), chartData = React.useMemo((() => {
7849
7816
  // Return null if dimensions not ready to prevent calculation with invalid dimensions
7850
7817
  if (!isInitialized || 0 === dimensions.width || 0 === dimensions.height) return null;
7851
7818
  const scales = calculateScales(processedData, dimensions.width, dimensions.height, void 0, config);
@@ -8258,7 +8225,7 @@ function useBarChart(datasets, options = {}) {
8258
8225
  opacity: .4
8259
8226
  } ]
8260
8227
  };
8261
- })) : []), [ options.useGradients ]), formatValue = React.useCallback((value => options.valueFormatter ? options.valueFormatter(value) : value.toString()), [ options.valueFormatter ]);
8228
+ })) : []), [ options.useGradients ]), formatValue = React.useCallback((value => options.valueFormatter ? options.valueFormatter(value) : value.toString()), [ options ]);
8262
8229
  return {
8263
8230
  // State
8264
8231
  hoveredBar: hoveredBar,
@@ -8284,7 +8251,7 @@ function useBarChart(datasets, options = {}) {
8284
8251
  y: horizontal ? y + height / 2 : y - 5
8285
8252
  };
8286
8253
  }
8287
- }), [ options.dataLabelPosition ]),
8254
+ }), [ options ]),
8288
8255
  // Handlers
8289
8256
  handleBarHover: handleBarHover,
8290
8257
  handleBarLeave: handleBarLeave,
@@ -8594,13 +8561,13 @@ const DonutChart = React.memo( React.forwardRef((({datasets: datasets = [], con
8594
8561
  roundedCorners: !0
8595
8562
  }, onDataPointClick: onDataPointClick, ...props}, ref) => {
8596
8563
  // Use the first dataset for donut chart
8597
- const dataset = datasets.length > 0 ? datasets[0] : {
8564
+ const dataset = React.useMemo((() => datasets.length > 0 ? datasets[0] : {
8598
8565
  label: "",
8599
8566
  data: []
8600
- }, chartData = React.useMemo((() => {
8567
+ }), [ datasets ]), chartData = React.useMemo((() => {
8601
8568
  if (!dataset?.data?.length) return null;
8602
8569
  // Filter out invalid data points
8603
- const validDataPoints = dataset?.data?.filter((point => "number" == typeof point.value && !isNaN(point.value) && isFinite(point.value) && point.value > 0));
8570
+ const validDataPoints = (dataset?.data || []).filter((point => "number" == typeof point.value && !isNaN(point.value) && isFinite(point.value) && point.value > 0));
8604
8571
  return validDataPoints.length ? {
8605
8572
  validDataPoints: validDataPoints
8606
8573
  } : null;
@@ -9559,7 +9526,7 @@ function usePieChart(data, options = {}) {
9559
9526
  const parts = [];
9560
9527
  return !1 !== options.showLabels && parts.push(slice.label), options.showPercentages && parts.push(`${Math.round(slice.percentage)}%`),
9561
9528
  options.showValues && parts.push(slice.value.toString()), parts.join(" - ");
9562
- }), [ options.labelFormatter, options.showLabels, options.showPercentages, options.showValues ]), getSliceTransform = React.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 = React.useCallback((index => selectedSlices.has(index)), [ selectedSlices ]);
9529
+ }), [ options ]), getSliceTransform = React.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 = React.useCallback((index => selectedSlices.has(index)), [ selectedSlices ]);
9563
9530
  return {
9564
9531
  // Data
9565
9532
  processedData: processedData,
@@ -10995,7 +10962,7 @@ const DataTable = React.memo((({data: data, columns: columns, className: classN
10995
10962
  const newOrder = columns.map((col => col.key)), currentOrderSet = new Set(columnOrder), newOrderSet = new Set(newOrder);
10996
10963
  // Only update if there are actual differences
10997
10964
  newOrder.length === columnOrder.length && newOrder.every((key => currentOrderSet.has(key))) && columnOrder.every((key => newOrderSet.has(key))) || setColumnOrder(newOrder);
10998
- }), [ columns ]),
10965
+ }), [ columns, columnOrder ]),
10999
10966
  // Update column visibility when columns prop changes
11000
10967
  React.useEffect((() => {
11001
10968
  setColumnVisibility((prev => {
@@ -11540,7 +11507,7 @@ function formatDate(date, format) {
11540
11507
  /**
11541
11508
  * Check if a date is within a min and max range
11542
11509
  */ 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} = {}) {
11543
- const [isOpen, setIsOpen] = React.useState(inline), [inputValue, setInputValue] = React.useState(value ? formatDate(value, format) : ""), [rangeInputValue, setRangeInputValue] = React.useState(startDate && endDate ? `${formatDate(startDate, format)} - ${formatDate(endDate, format)}` : startDate ? `${formatDate(startDate, format)} - Select end date` : ""), [viewDate, setViewDate] = React.useState(value || startDate || new Date), [viewMode, setViewMode] = React.useState("days"), [rangeSelectionState, setRangeSelectionState] = React.useState(!startDate || startDate && endDate ? "start" : "end"), datePickerRef = React.useRef(null), inputRef = React.useRef(null), today = new Date, currentMonth = viewDate.getMonth(), currentYear = viewDate.getFullYear(), daysInMonth = getDaysInMonth(currentYear, currentMonth), firstDayOfMonth = new Date(currentYear, currentMonth, 1).getDay();
11510
+ const [isOpen, setIsOpen] = React.useState(inline), [inputValue, setInputValue] = React.useState(value ? formatDate(value, format) : ""), [rangeInputValue, setRangeInputValue] = React.useState(startDate && endDate ? `${formatDate(startDate, format)} - ${formatDate(endDate, format)}` : startDate ? `${formatDate(startDate, format)} - Select end date` : ""), [viewDate, setViewDate] = React.useState(value || startDate || new Date), [viewMode, setViewMode] = React.useState("days"), [rangeSelectionState, setRangeSelectionState] = React.useState(!startDate || startDate && endDate ? "start" : "end"), datePickerRef = React.useRef(null), inputRef = React.useRef(null), today = React.useMemo((() => new Date), []), currentMonth = viewDate.getMonth(), currentYear = viewDate.getFullYear(), daysInMonth = getDaysInMonth(currentYear, currentMonth), firstDayOfMonth = new Date(currentYear, currentMonth, 1).getDay();
11544
11511
  // Update input value when value or range dates change externally
11545
11512
  React.useEffect((() => {
11546
11513
  "single" === selectionMode ? setInputValue(value ? formatDate(value, format) : "") : (setRangeInputValue(startDate && endDate ? `${formatDate(startDate, format)} - ${formatDate(endDate, format)}` : startDate ? `${formatDate(startDate, format)} - Select end date` : ""),
@@ -12063,21 +12030,11 @@ const DatePicker = React.forwardRef((({value: value, onChange: onChange, select
12063
12030
  * @returns EdgePanel state and methods
12064
12031
  */
12065
12032
  function useEdgePanel(initialProps) {
12066
- // Default EdgePanel properties
12067
- const defaultProps = {
12068
- position: "start",
12069
- mode: "slide",
12070
- isOpen: !1,
12071
- backdrop: !0,
12072
- closeOnBackdropClick: !0,
12073
- closeOnEscape: !0,
12074
- glass: void 0,
12075
- ...initialProps
12076
- }, [isOpen, setIsOpen] = React.useState(defaultProps.isOpen || !1), containerRef = React.useRef(null), backdropRef = React.useRef(null), adjustBodyPadding = React.useCallback((() => {
12077
- if (!containerRef.current || "push" !== defaultProps.mode) return;
12078
- const {position: position} = defaultProps, size = "top" === position || "bottom" === position ? containerRef.current.clientHeight : containerRef.current.clientWidth;
12033
+ 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] = React.useState(propIsOpen || !1), containerRef = React.useRef(null), backdropRef = React.useRef(null), adjustBodyPadding = React.useCallback((() => {
12034
+ if (!containerRef.current || "push" !== mode) return;
12035
+ const size = "top" === position || "bottom" === position ? containerRef.current.clientHeight : containerRef.current.clientWidth;
12079
12036
  // Map position to CSS padding property
12080
- let paddingProperty;
12037
+ let paddingProperty;
12081
12038
  switch (position) {
12082
12039
  case "start":
12083
12040
  paddingProperty = "paddingLeft";
@@ -12092,9 +12049,8 @@ function useEdgePanel(initialProps) {
12092
12049
  paddingProperty = `padding${position.charAt(0).toUpperCase() + position.slice(1)}`;
12093
12050
  }
12094
12051
  document.body.style[paddingProperty] = `${size}px`, document.body.classList.add("is-pushed");
12095
- }), [ defaultProps.mode, defaultProps.position ]), resetBodyPadding = React.useCallback((() => {
12096
- if ("push" !== defaultProps.mode) return;
12097
- const {position: position} = defaultProps;
12052
+ }), [ mode, position ]), resetBodyPadding = React.useCallback((() => {
12053
+ if ("push" !== mode) return;
12098
12054
  // Map position to CSS padding property
12099
12055
  let paddingProperty;
12100
12056
  switch (position) {
@@ -12111,11 +12067,10 @@ function useEdgePanel(initialProps) {
12111
12067
  paddingProperty = `padding${position.charAt(0).toUpperCase() + position.slice(1)}`;
12112
12068
  }
12113
12069
  document.body.style[paddingProperty] = "", document.body.classList.remove("is-pushed");
12114
- }), [ defaultProps.mode, defaultProps.position ]), openPanel = React.useCallback(((useFadeAnimation = !1) => {
12070
+ }), [ mode, position ]), openPanel = React.useCallback(((useFadeAnimation = !1) => {
12115
12071
  if (setIsOpen(!0), document.body.classList.add("is-edgepanel-open"), containerRef.current) {
12116
- const {mode: mode} = defaultProps;
12117
12072
  // Only add animation if not in 'none' mode
12118
- if ("none" !== mode) if (useFadeAnimation) {
12073
+ if ("none" !== mode) if (useFadeAnimation) {
12119
12074
  // Add fade animation class
12120
12075
  containerRef.current.classList.add("is-fade-animating"), containerRef.current.offsetHeight;
12121
12076
  // Remove animation class after animation completes
@@ -12135,14 +12090,13 @@ function useEdgePanel(initialProps) {
12135
12090
  // Set transform or opacity based on animation type
12136
12091
  useFadeAnimation ? (containerRef.current.style.opacity = "1", containerRef.current.style.transform = "") : containerRef.current.style.transform = "translate(0)",
12137
12092
  // If push mode, adjust body padding
12138
- "push" === defaultProps.mode && adjustBodyPadding();
12093
+ "push" === mode && adjustBodyPadding();
12139
12094
  }
12140
- defaultProps.onOpenChange && defaultProps.onOpenChange(!0);
12141
- }), [ defaultProps, adjustBodyPadding ]), closePanel = React.useCallback(((useFadeAnimation = !1) => {
12095
+ onOpenChange && onOpenChange(!0);
12096
+ }), [ mode, adjustBodyPadding, onOpenChange ]), closePanel = React.useCallback(((useFadeAnimation = !1) => {
12142
12097
  if (containerRef.current) {
12143
- const {position: position, mode: mode} = defaultProps;
12144
12098
  // Only add animation if not in 'none' mode
12145
- if ("none" !== mode) if (useFadeAnimation) {
12099
+ if ("none" !== mode) if (useFadeAnimation) {
12146
12100
  // Add fade out animation class
12147
12101
  containerRef.current.classList.add("is-fade-animating-out");
12148
12102
  // Capture container for setTimeout
@@ -12164,46 +12118,42 @@ function useEdgePanel(initialProps) {
12164
12118
  // Then set transform
12165
12119
  containerRef.current.style.transform = position ? EDGE_PANEL.TRANSFORM_VALUES[position] : "",
12166
12120
  // Reset body padding if push mode
12167
- "push" === defaultProps.mode && resetBodyPadding(), setTimeout((() => {
12168
- setIsOpen(!1), document.body.classList.remove("is-edgepanel-open"), defaultProps.onOpenChange && defaultProps.onOpenChange(!1);
12121
+ "push" === mode && resetBodyPadding(), setTimeout((() => {
12122
+ setIsOpen(!1), document.body.classList.remove("is-edgepanel-open"), onOpenChange && onOpenChange(!1);
12169
12123
  }), "none" === mode ? 0 : EDGE_PANEL.ANIMATION_DURATION);
12170
- } else setIsOpen(!1), document.body.classList.remove("is-edgepanel-open"), defaultProps.onOpenChange && defaultProps.onOpenChange(!1);
12171
- }), [ defaultProps, resetBodyPadding ]), handleEscapeKey = React.useCallback((event => {
12172
- defaultProps.closeOnEscape && "Escape" === event.key && isOpen && closePanel();
12173
- }), [ closePanel, defaultProps.closeOnEscape, isOpen ]), handleBackdropClick = React.useCallback((event => {
12174
- defaultProps.closeOnBackdropClick && event.target === event.currentTarget && closePanel();
12175
- }), [ closePanel, defaultProps.closeOnBackdropClick ]);
12124
+ } else setIsOpen(!1), document.body.classList.remove("is-edgepanel-open"), onOpenChange && onOpenChange(!1);
12125
+ }), [ mode, position, onOpenChange, resetBodyPadding ]), handleEscapeKey = React.useCallback((event => {
12126
+ closeOnEscape && "Escape" === event.key && isOpen && closePanel();
12127
+ }), [ closePanel, closeOnEscape, isOpen ]), handleBackdropClick = React.useCallback((event => {
12128
+ closeOnBackdropClick && event.target === event.currentTarget && closePanel();
12129
+ }), [ closePanel, closeOnBackdropClick ]);
12176
12130
  /**
12177
12131
  * Set up event listeners for keyboard events
12178
12132
  */
12179
- return React.useEffect((() => (isOpen && defaultProps.closeOnEscape && document.addEventListener("keydown", handleEscapeKey),
12133
+ return React.useEffect((() => (isOpen && closeOnEscape && document.addEventListener("keydown", handleEscapeKey),
12180
12134
  () => {
12181
12135
  document.removeEventListener("keydown", handleEscapeKey);
12182
- })), [ isOpen, handleEscapeKey, defaultProps.closeOnEscape ]),
12136
+ })), [ isOpen, handleEscapeKey, closeOnEscape ]),
12183
12137
  /**
12184
12138
  * Set initial transform values
12185
12139
  */
12186
12140
  React.useEffect((() => {
12187
- if (containerRef.current) {
12188
- const {position: position, mode: mode} = defaultProps;
12189
- isOpen || "slide" !== mode && "push" !== mode || !position || (containerRef.current.style.transform = EDGE_PANEL.TRANSFORM_VALUES[position],
12190
- // Set initial opacity for fade animations
12191
- defaultProps.glass && (containerRef.current.style.opacity = "0"));
12192
- }
12193
- }), [ defaultProps.mode, defaultProps.position, defaultProps.glass, isOpen ]),
12141
+ containerRef.current && (isOpen || "slide" !== mode && "push" !== mode || !position || (containerRef.current.style.transform = EDGE_PANEL.TRANSFORM_VALUES[position],
12142
+ // Set initial opacity for fade animations
12143
+ glass && (containerRef.current.style.opacity = "0")));
12144
+ }), [ mode, position, glass, isOpen ]),
12194
12145
  /**
12195
12146
  * Sync with prop changes
12196
12147
  */
12197
12148
  React.useEffect((() => {
12198
- void 0 !== defaultProps.isOpen && defaultProps.isOpen !== isOpen && (defaultProps.isOpen ? openPanel(!!defaultProps.glass) : closePanel(!!defaultProps.glass));
12199
- }), [ defaultProps.isOpen, closePanel, isOpen, openPanel, defaultProps.glass ]),
12200
- {
12149
+ void 0 !== propIsOpen && propIsOpen !== isOpen && (propIsOpen ? openPanel(!!glass) : closePanel(!!glass));
12150
+ }), [ propIsOpen, closePanel, isOpen, openPanel, glass ]), {
12201
12151
  isOpen: isOpen,
12202
12152
  containerRef: containerRef,
12203
12153
  backdropRef: backdropRef,
12204
12154
  generateEdgePanelClass: props => {
12205
- const {position: position = defaultProps.position, className: className = "", isOpen: propIsOpen} = props, baseClass = EDGE_PANEL.CLASSES.BASE;
12206
- return `${baseClass} ${position ? `${baseClass}--${position}` : ""} ${propIsOpen ?? isOpen ? EDGE_PANEL.CLASSES.IS_OPEN : ""} ${className}`.trim();
12155
+ const {position: propPosition = position, className: propClassName = className, isOpen: argIsOpen} = props, baseClass = EDGE_PANEL.CLASSES.BASE;
12156
+ return `${baseClass} ${propPosition ? `${baseClass}--${propPosition}` : ""} ${argIsOpen ?? isOpen ? EDGE_PANEL.CLASSES.IS_OPEN : ""} ${propClassName}`.trim();
12207
12157
  },
12208
12158
  openPanel: openPanel,
12209
12159
  closePanel: closePanel,
@@ -12254,7 +12204,7 @@ const EdgePanelCloseButton = React.forwardRef((({className: className = "", onC
12254
12204
 
12255
12205
  EdgePanelCloseButton.displayName = "EdgePanelCloseButton";
12256
12206
 
12257
- const EdgePanel = React.memo((({title: title, children: children, position: position = "start", mode: mode = "slide", isOpen: isOpen = !1, onOpenChange: onOpenChange, backdrop: backdrop = !0, closeOnBackdropClick: closeOnBackdropClick = !0, closeOnEscape: closeOnEscape = !0, className: className = "", style: style, glass: glass}) => {
12207
+ const EdgePanelComponentBase = ({title: title, children: children, position: position = "start", mode: mode = "slide", isOpen: isOpen = !1, onOpenChange: onOpenChange, backdrop: backdrop = !0, closeOnBackdropClick: closeOnBackdropClick = !0, closeOnEscape: closeOnEscape = !0, className: className = "", style: style, glass: glass}) => {
12258
12208
  const {isOpen: isOpenState, containerRef: containerRef, backdropRef: backdropRef, generateEdgePanelClass: generateEdgePanelClass, closePanel: closePanel, handleBackdropClick: handleBackdropClick} = useEdgePanel({
12259
12209
  position: position,
12260
12210
  mode: mode,
@@ -12330,7 +12280,7 @@ const EdgePanel = React.memo((({title: title, children: children, position: pos
12330
12280
  }) : panelContent
12331
12281
  }) ]
12332
12282
  });
12333
- }));
12283
+ }, EdgePanel = React.memo(EdgePanelComponentBase);
12334
12284
 
12335
12285
  /**
12336
12286
  * Form state and functionality
@@ -12585,7 +12535,7 @@ function useHero(initialProps) {
12585
12535
  * @returns Slider state and methods
12586
12536
  */
12587
12537
  function(config) {
12588
- const {slides: slides, autoplay: autoplay, loop: loop = !0, transition: transition = "fade", transitionDuration: transitionDuration = 1e3} = config, [currentIndex, setCurrentIndex] = React.useState(0), [isTransitioning, setIsTransitioning] = React.useState(!1), autoplayRef = React.useRef(null), isPausedRef = React.useRef(!1), callbackRef = React.useRef(), slideRefs = React.useMemo((() => slides.map((() => React__default.default.createRef()))), [ slides.length ]), videoRefs = React.useMemo((() => slides.map((() => React__default.default.createRef()))), [ slides.length ]), handleSlideTransition = React.useCallback((nextIndex => {
12538
+ const {slides: slides, autoplay: autoplay, loop: loop = !0, transition: transition = "fade", transitionDuration: transitionDuration = 1e3} = config, [currentIndex, setCurrentIndex] = React.useState(0), [isTransitioning, setIsTransitioning] = React.useState(!1), autoplayRef = React.useRef(null), isPausedRef = React.useRef(!1), callbackRef = React.useRef(void 0), slideRefs = React.useMemo((() => slides.map((() => React__default.default.createRef()))), [ slides ]), videoRefs = React.useMemo((() => slides.map((() => React__default.default.createRef()))), [ slides ]), handleSlideTransition = React.useCallback((nextIndex => {
12589
12539
  if (nextIndex === currentIndex || isTransitioning) return;
12590
12540
  if (nextIndex < 0 || nextIndex >= slides.length) return;
12591
12541
  setIsTransitioning(!0),
@@ -12904,22 +12854,15 @@ function useHero(initialProps) {
12904
12854
  * @param initialProps - Initial side menu properties
12905
12855
  * @returns SideMenu state and methods
12906
12856
  */ function useSideMenu(initialProps) {
12907
- // Default side menu properties
12908
- const defaultProps = {
12909
- collapsible: !0,
12910
- collapsibleDesktop: !1,
12911
- defaultCollapsedDesktop: !1,
12912
- isOpen: !1,
12913
- ...initialProps
12914
- }, [isOpenState, setIsOpenState] = React.useState(void 0 !== defaultProps.defaultCollapsedDesktop ? !defaultProps.defaultCollapsedDesktop : defaultProps.isOpen || !1), wrapperRef = React.useRef(null), innerRef = React.useRef(null), sideMenuRef = React.useRef(null);
12857
+ const {collapsible: collapsible = !0, collapsibleDesktop: collapsibleDesktop = !1, defaultCollapsedDesktop: defaultCollapsedDesktop = !1, isOpen: isOpen, onToggle: onToggle, disabled: disabled = !1} = initialProps || {}, [isOpenState, setIsOpenState] = React.useState(void 0 !== defaultCollapsedDesktop ? !defaultCollapsedDesktop : isOpen || !1), wrapperRef = React.useRef(null), innerRef = React.useRef(null), sideMenuRef = React.useRef(null);
12915
12858
  // Local open state for when not controlled externally
12916
12859
  // Update local state when external state changes
12917
12860
  React.useEffect((() => {
12918
- void 0 !== defaultProps.isOpen ? setIsOpenState(defaultProps.isOpen) : void 0 !== defaultProps.defaultCollapsedDesktop && setIsOpenState(!defaultProps.defaultCollapsedDesktop);
12919
- }), [ defaultProps.isOpen, defaultProps.defaultCollapsedDesktop ]),
12861
+ void 0 !== isOpen ? setIsOpenState(isOpen) : void 0 !== defaultCollapsedDesktop && setIsOpenState(!defaultCollapsedDesktop);
12862
+ }), [ isOpen, defaultCollapsedDesktop ]),
12920
12863
  // Set initial height on mount
12921
12864
  React.useEffect((() => {
12922
- const shouldCollapse = window.innerWidth < 768 ? defaultProps.collapsible : defaultProps.collapsibleDesktop, currentOpen = void 0 !== defaultProps.isOpen ? defaultProps.isOpen : isOpenState;
12865
+ const shouldCollapse = window.innerWidth < 768 ? collapsible : collapsibleDesktop, currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
12923
12866
  if (shouldCollapse && wrapperRef.current && innerRef.current) {
12924
12867
  // Use setTimeout to ensure DOM is fully rendered
12925
12868
  const timeoutId = setTimeout((() => {
@@ -12928,14 +12871,14 @@ function useHero(initialProps) {
12928
12871
  return () => clearTimeout(timeoutId);
12929
12872
  }
12930
12873
  !shouldCollapse && wrapperRef.current && (wrapperRef.current.style.height = "auto");
12931
- }), []), // Only run on mount
12874
+ }), [ collapsible, collapsibleDesktop, isOpen, isOpenState ]),
12932
12875
  // Handle responsive behavior - vertical collapse for both mobile and desktop
12933
12876
  React.useEffect((() => {
12934
12877
  const handleResize = () => {
12935
- if (window.innerWidth < 768 ? defaultProps.collapsible : defaultProps.collapsibleDesktop) {
12878
+ if (window.innerWidth < 768 ? collapsible : collapsibleDesktop) {
12936
12879
  if (wrapperRef.current && innerRef.current) {
12937
12880
  // Set proper height for vertical animation (both mobile and desktop)
12938
- const currentOpen = void 0 !== defaultProps.isOpen ? defaultProps.isOpen : isOpenState;
12881
+ const currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
12939
12882
  // Use requestAnimationFrame to ensure DOM is ready
12940
12883
  requestAnimationFrame((() => {
12941
12884
  wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
@@ -12949,12 +12892,12 @@ function useHero(initialProps) {
12949
12892
  return window.addEventListener("resize", handleResize), () => {
12950
12893
  clearTimeout(timeoutId), window.removeEventListener("resize", handleResize);
12951
12894
  };
12952
- }), [ defaultProps.collapsible, defaultProps.collapsibleDesktop, defaultProps.isOpen, defaultProps.onToggle, isOpenState ]),
12895
+ }), [ collapsible, collapsibleDesktop, isOpen, onToggle, isOpenState ]),
12953
12896
  // Update wrapper height when open state changes (both mobile and desktop)
12954
12897
  React.useEffect((() => {
12955
- const shouldCollapse = window.innerWidth < 768 ? defaultProps.collapsible : defaultProps.collapsibleDesktop;
12898
+ const shouldCollapse = window.innerWidth < 768 ? collapsible : collapsibleDesktop;
12956
12899
  if (shouldCollapse && wrapperRef.current && innerRef.current) {
12957
- const currentOpen = void 0 !== defaultProps.isOpen ? defaultProps.isOpen : isOpenState;
12900
+ const currentOpen = void 0 !== isOpen ? isOpen : isOpenState;
12958
12901
  // Use requestAnimationFrame to ensure DOM is ready
12959
12902
  requestAnimationFrame((() => {
12960
12903
  wrapperRef.current && innerRef.current && (wrapperRef.current.style.height = currentOpen ? `${innerRef.current.scrollHeight}px` : "0px");
@@ -12962,26 +12905,25 @@ function useHero(initialProps) {
12962
12905
  } else !shouldCollapse && wrapperRef.current && (
12963
12906
  // Not collapsible - always show content
12964
12907
  wrapperRef.current.style.height = "auto");
12965
- }), [ defaultProps.isOpen, isOpenState, defaultProps.collapsible, defaultProps.collapsibleDesktop ]);
12908
+ }), [ isOpen, isOpenState, collapsible, collapsibleDesktop ]);
12966
12909
  /**
12967
12910
  * Generate side menu class based on properties
12968
12911
  * @param props - Side menu properties
12969
12912
  * @returns Class string
12970
12913
  */
12971
12914
  const handleToggle = () => {
12972
- if (defaultProps.disabled) return;
12973
- const newState = void 0 !== defaultProps.isOpen ? !defaultProps.isOpen : !isOpenState;
12974
- "function" == typeof defaultProps.onToggle ?
12915
+ if (disabled) return;
12916
+ const newState = void 0 !== isOpen ? !isOpen : !isOpenState;
12917
+ "function" == typeof onToggle ?
12975
12918
  // Controlled component
12976
- defaultProps.onToggle(newState) :
12919
+ onToggle(newState) :
12977
12920
  // Uncontrolled component
12978
12921
  setIsOpenState(newState);
12979
- }, getCurrentOpenState = () => void 0 !== defaultProps.isOpen ? defaultProps.isOpen : isOpenState;
12922
+ }, getCurrentOpenState = () => void 0 !== isOpen ? isOpen : isOpenState;
12980
12923
  /**
12981
12924
  * Generate wrapper class
12982
12925
  * @returns Class string
12983
12926
  */ return {
12984
- defaultProps: defaultProps,
12985
12927
  isOpenState: getCurrentOpenState(),
12986
12928
  wrapperRef: wrapperRef,
12987
12929
  innerRef: innerRef,
@@ -13684,7 +13626,7 @@ SelectOption.displayName = "SelectOption";
13684
13626
  /**
13685
13627
  * Select - A component for dropdown selection
13686
13628
  */
13687
- const Select = React.memo((({options: options, value: value, onChange: onChange, onBlur: onBlur, onFocus: onFocus, placeholder: placeholder = "Select an option", className: className = "", style: style, disabled: disabled = !1, required: required = !1, id: id, name: name, size: size = "md", invalid: invalid = !1, valid: valid = !1, multiple: multiple = !1, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, glass: glass, 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}) => {
13688
13630
  const {generateSelectClass: generateSelectClass} = useSelect({
13689
13631
  size: size,
13690
13632
  disabled: disabled,
@@ -13875,7 +13817,7 @@ const Select = React.memo((({options: options, value: value, onChange: onChange
13875
13817
  });
13876
13818
  }
13877
13819
  return selectContent;
13878
- }));
13820
+ }, Select = React.memo(SelectComponentBase);
13879
13821
 
13880
13822
  Select.displayName = "Select", Select.Option = SelectOption;
13881
13823
 
@@ -14442,7 +14384,7 @@ Footer.displayName = "Footer";
14442
14384
  */
14443
14385
  const MasonryGrid = React.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) => {
14444
14386
  // === REFS & STATE ===
14445
- const [columns, setColumns] = React.useState(xs), [positions, setPositions] = React.useState([]), [layoutComplete, setLayoutComplete] = React.useState(!1), [loadingImages, setLoadingImages] = React.useState(!1), containerRef = React.useRef(null), columnHeights = React.useRef([]), imagesLoadedCount = React.useRef(0), totalImagesCount = React.useRef(0), imageElements = React.useRef(new Map);
14387
+ const [columns, setColumns] = React.useState(xs), [positions, setPositions] = React.useState([]), [, setLayoutComplete] = React.useState(!1), [loadingImages, setLoadingImages] = React.useState(!1), containerRef = React.useRef(null), columnHeights = React.useRef([]), imagesLoadedCount = React.useRef(0), totalImagesCount = React.useRef(0), imageElements = React.useRef(new Map);
14446
14388
  React.useEffect((() => {
14447
14389
  setLoadingImages(!!imagesLoaded);
14448
14390
  }), [ columns, imagesLoaded ]),
@@ -14471,34 +14413,45 @@ const MasonryGrid = React.forwardRef((({children: children, className: classNam
14471
14413
  });
14472
14414
  })), setItems(newItems);
14473
14415
  }), [ children ]);
14474
- // === TRACK & MANAGE IMAGES ===
14475
- const handleImageLoad = React.useCallback((img => {
14476
- if (!imageElements.current.get(img)) {
14477
- // Add loaded class for animation
14478
- if (imageElements.current.set(img, !0), imagesLoadedCount.current += 1, containerRef.current && imagesLoaded) {
14479
- const itemElement = img.closest(".o-masonry-grid > div");
14480
- itemElement && (itemElement.offsetHeight, itemElement.classList.add("o-masonry-grid__item-loaded"),
14481
- itemElement.classList.remove("o-masonry-grid__item-loading"));
14416
+ // === MANAGE ITEM LAYOUT ===
14417
+ const calculateLayout = React.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
+ };
14482
14432
  }
14483
- // Ensure layout is recalculated after DOM paints the item image (prevents overlap on slow/late image loads)
14484
- requestAnimationFrame((() => {
14485
- requestAnimationFrame((() => {
14486
- calculateLayout();
14487
- }));
14488
- })), onImageLoad?.(imagesLoadedCount.current, totalImagesCount.current),
14489
- // If all images have loaded, update loading state and complete layout
14490
- imagesLoadedCount.current >= totalImagesCount.current && totalImagesCount.current > 0 && (setLayoutComplete(!0),
14491
- setLoadingImages(!1), // This ensures the loading class is removed *immediately* after images load
14492
- // Force a double requestAnimationFrame for final layout calculation after all images are loaded (guarantees DOM paint)
14493
- requestAnimationFrame((() => {
14494
- requestAnimationFrame((() => {
14495
- calculateLayout(),
14496
- // As a failsafe, if still present for some render lag, force another setLoadingImages(false)
14497
- setLoadingImages(!1);
14498
- }));
14499
- })), onLayoutComplete?.());
14433
+ })), setPositions(newPositions);
14434
+ }), [ items, columns, gap ]), handleImageLoad = React.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"));
14500
14441
  }
14501
- }), [ onImageLoad, onLayoutComplete, imagesLoaded ]), trackImages = React.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 = React.useCallback((() => {
14502
14455
  if (!imagesLoaded || !containerRef.current) return;
14503
14456
  imageElements.current.clear(), imagesLoadedCount.current = 0;
14504
14457
  const images = containerRef.current.querySelectorAll("img");
@@ -14517,30 +14470,21 @@ const MasonryGrid = React.forwardRef((({children: children, className: classNam
14517
14470
  img.removeEventListener("error", masonryImg._masonryLoadHandler), delete masonryImg._masonryLoadHandler);
14518
14471
  }));
14519
14472
  });
14520
- }), [ imagesLoaded, handleImageLoad, onLayoutComplete ]), calculateLayout = React.useCallback((() => {
14521
- if (!containerRef.current || 0 === items.length) return;
14522
- const colWidth = (containerRef.current.offsetWidth - gap * (columns - 1)) / columns;
14523
- columnHeights.current = Array(columns).fill(0);
14524
- const newPositions = [];
14525
- items.forEach(((item, index) => {
14526
- if (item.ref.current) {
14527
- // Find the shortest column
14528
- const shortestCol = columnHeights.current.indexOf(Math.min(...columnHeights.current)), left = shortestCol * (colWidth + gap), top = columnHeights.current[shortestCol] ?? 0, height = item.ref.current.offsetHeight;
14529
- columnHeights.current[shortestCol] = top + height + gap, newPositions[index] = {
14530
- left: left,
14531
- top: top,
14532
- width: colWidth,
14533
- height: height
14534
- };
14535
- }
14536
- })), setPositions(newPositions);
14537
- }), [ items, columns, gap ]);
14538
- // === OBSERVE CONTAINER RESIZE ===
14473
+ }), [ imagesLoaded, handleImageLoad, onLayoutComplete ]);
14474
+ // === TRACK & MANAGE IMAGES ===
14475
+ // === OBSERVE CONTAINER RESIZE ===
14539
14476
  React.useEffect((() => {
14540
14477
  if (!containerRef.current) return;
14541
- let animationFrame = null;
14542
- const observer = new ResizeObserver((() => {
14543
- 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
+ })));
14544
14488
  }));
14545
14489
  return observer.observe(containerRef.current), () => {
14546
14490
  observer.disconnect(), animationFrame && cancelAnimationFrame(animationFrame);
@@ -14551,24 +14495,21 @@ const MasonryGrid = React.forwardRef((({children: children, className: classNam
14551
14495
  setLayoutComplete(!0), void setLoadingImages(!1))
14552
14496
  // Only reset layoutComplete when items or columns change
14553
14497
  ), [ items, columns, calculateLayout, imagesLoaded, trackImages ]),
14554
- // === NEW: Add ResizeObservers to all grid items for bulletproof image+content measurement ===
14498
+ // === ADD RESIZEOBSERVERS TO GRID ITEMS FOR DYNAMIC CONTENT MEASUREMENT ===
14555
14499
  React__default.default.useEffect((() => {
14556
- // Clean up old observers if items ever change
14557
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
+ };
14558
14506
  return items.forEach((item => {
14559
14507
  if (item.ref.current) {
14560
- const obs = new ResizeObserver((() => {
14561
- // Double rAF: ensures layout only runs after DOM/paint/async renders
14562
- requestAnimationFrame((() => {
14563
- requestAnimationFrame((() => {
14564
- calculateLayout();
14565
- }));
14566
- }));
14567
- }));
14508
+ const obs = new ResizeObserver(debouncedCalculateLayout);
14568
14509
  obs.observe(item.ref.current), observers.push(obs);
14569
14510
  }
14570
14511
  })), () => {
14571
- observers.forEach((obs => obs.disconnect()));
14512
+ observers.forEach((obs => obs.disconnect())), animationFrame && cancelAnimationFrame(animationFrame);
14572
14513
  };
14573
14514
  }), [ items, calculateLayout ]);
14574
14515
  // Ensure loadingImages state resets when items/columns/imagesLoaded change
@@ -15053,7 +14994,7 @@ const ListItem = React.forwardRef((({children: children, className: className =
15053
14994
 
15054
14995
  ListItem.displayName = "ListItem";
15055
14996
 
15056
- const List = React.memo((({children: children, variant: variant = "default", className: className = "", style: style, ...props}) => {
14997
+ const ListComponentBase = ({children: children, variant: variant = "default", className: className = "", style: style, ...props}) => {
15057
14998
  var _context;
15058
14999
  // Generate CSS classes
15059
15000
  const listClasses = [ LIST.BASE_CLASS, "default" !== variant && `c-list--${variant}`, className ].filter(Boolean).join(" "), ListElement = _includesInstanceProperty(_context = [ "number", "text" ]).call(_context, variant) ? "ol" : "ul";
@@ -15067,7 +15008,7 @@ const List = React.memo((({children: children, variant: variant = "default", cl
15067
15008
  children: child
15068
15009
  })))
15069
15010
  });
15070
- }));
15011
+ }, List = React.memo(ListComponentBase);
15071
15012
 
15072
15013
  List.displayName = "List", List.Item = ListItem;
15073
15014
 
@@ -16018,12 +15959,12 @@ const SideMenu = React.forwardRef((({title: title, children: children, menuItem
16018
15959
  const index = Number(key);
16019
15960
  index >= currentLength && (delete nestedWrapperRefs.current[index], delete nestedInnerRefs.current[index]);
16020
15961
  })));
16021
- }), [ menuItems?.length ]);
15962
+ }), [ menuItems ]);
16022
15963
  // Helper function to update nested wrapper height
16023
- const updateNestedHeight = (index, isOpen) => {
15964
+ const updateNestedHeight = React.useCallback(((index, isOpen) => {
16024
15965
  const wrapper = nestedWrapperRefs.current[index], inner = nestedInnerRefs.current[index];
16025
15966
  wrapper && inner && (wrapper.style.height = isOpen ? `${inner.scrollHeight}px` : "0px");
16026
- };
15967
+ }), []);
16027
15968
  // Set initial heights for nested wrappers on mount and when menuItems change
16028
15969
  React.useEffect((() => {
16029
15970
  if (!menuItems?.length) return;
@@ -16037,7 +15978,7 @@ const SideMenu = React.forwardRef((({title: title, children: children, menuItem
16037
15978
  // Only run when menuItems change, nestedItemStates is read but not in deps to avoid loops
16038
15979
  // eslint-disable-next-line react-hooks/exhaustive-deps
16039
15980
  ;
16040
- }), [ menuItems?.length ]),
15981
+ }), [ menuItems, updateNestedHeight ]),
16041
15982
  // Update nested wrapper heights when state changes
16042
15983
  React.useEffect((() => {
16043
15984
  if (!menuItems?.length) return;
@@ -16050,7 +15991,7 @@ const SideMenu = React.forwardRef((({title: title, children: children, menuItem
16050
15991
  })), () => {
16051
15992
  frameIds.forEach((id => cancelAnimationFrame(id)));
16052
15993
  };
16053
- }), [ nestedItemStates, menuItems?.length ]);
15994
+ }), [ nestedItemStates, menuItems, updateNestedHeight ]);
16054
15995
  // Combine refs using utility
16055
15996
  const combinedRef = useForkRef(sideMenuRef, ref), sideMenuClass = generateSideMenuClass({
16056
15997
  className: className,
@@ -16953,7 +16894,7 @@ React.useEffect((() => {
16953
16894
  }
16954
16895
  };
16955
16896
  }));
16956
- }), [ isMounted, currentIndex, calculateBounds, constrainPosition ]), setImagePosition = React.useCallback((position => {
16897
+ }), [ currentIndex, calculateBounds, constrainPosition ]), setImagePosition = React.useCallback((position => {
16957
16898
  setImageStates((prev => {
16958
16899
  const currentState = prev[currentIndex] || {
16959
16900
  zoomLevel: 1,
@@ -17003,7 +16944,7 @@ React.useEffect((() => {
17003
16944
  }
17004
16945
  };
17005
16946
  }));
17006
- }), [ isMounted, currentIndex, calculateBounds, constrainPosition ]), handleWheel = React.useCallback((event => {
16947
+ }), [ currentIndex, calculateBounds, constrainPosition ]), handleWheel = React.useCallback((event => {
17007
16948
  var _context;
17008
16949
  if (!isMounted || !event || !event.currentTarget) return;
17009
16950
  // Additional safety check for the target element
@@ -17360,7 +17301,7 @@ React.useEffect((() => {
17360
17301
  }
17361
17302
  return prev;
17362
17303
  }));
17363
- }), [ isMounted, enableGestures, isDragging, startDragPosition, currentIndex, constrainPosition, calculateBounds ]), handleTouchEnd = React.useCallback((() => {
17304
+ }), [ enableGestures, isDragging, startDragPosition, currentIndex, constrainPosition, calculateBounds ]), handleTouchEnd = React.useCallback((() => {
17364
17305
  setIsDragging(!1), lastDistanceRef.current = null, lastMidpointRef.current = null;
17365
17306
  }), []), currentState = imageStates[currentIndex] || {
17366
17307
  zoomLevel: 1,
@@ -17564,9 +17505,9 @@ const PopoverContext = React.createContext({
17564
17505
  triggerType: "click"
17565
17506
  }), 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}) => {
17566
17507
  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}) => {
17567
- const [isOpen, setIsOpenState] = React.useState(defaultOpen), [currentPosition, setCurrentPosition] = React.useState("auto" === position ? "top" : position), triggerRef = React.useRef(null), popoverRef = React.useRef(null), arrowRef = React.useRef(null), timeoutRef = React.useRef(null), popoverId = id || `popover-${Math.random().toString(36).slice(2, 11)}`, isControlled = void 0 !== controlledIsOpen, isOpenState = isControlled ? controlledIsOpen : isOpen, setIsOpen = newIsOpen => {
17508
+ const [isOpen, setIsOpenState] = React.useState(defaultOpen), [currentPosition, setCurrentPosition] = React.useState("auto" === position ? "top" : position), triggerRef = React.useRef(null), popoverRef = React.useRef(null), arrowRef = React.useRef(null), timeoutRef = React.useRef(null), popoverId = id || `popover-${Math.random().toString(36).slice(2, 11)}`, isControlled = void 0 !== controlledIsOpen, isOpenState = isControlled ? controlledIsOpen : isOpen, setIsOpen = React.useCallback((newIsOpen => {
17568
17509
  isControlled || setIsOpenState(newIsOpen), onOpenChange && onOpenChange(newIsOpen);
17569
- };
17510
+ }), [ isControlled, onOpenChange ]);
17570
17511
  // Handle hover events if trigger is hover
17571
17512
  React.useEffect((() => {
17572
17513
  if ("hover" !== trigger || !triggerRef.current || !popoverRef.current) return;
@@ -17586,17 +17527,16 @@ const PopoverContext = React.createContext({
17586
17527
  setIsOpen(!1);
17587
17528
  };
17588
17529
  // Add hover event listeners
17589
- return triggerRef.current.addEventListener("mouseenter", handleTriggerMouseEnter),
17590
- triggerRef.current.addEventListener("mouseleave", handleTriggerMouseLeave), popoverRef.current.addEventListener("mouseenter", handlePopoverMouseEnter),
17591
- popoverRef.current.addEventListener("mouseleave", handlePopoverMouseLeave), () => {
17592
- triggerRef.current && (triggerRef.current.removeEventListener("mouseenter", handleTriggerMouseEnter),
17593
- triggerRef.current.removeEventListener("mouseleave", handleTriggerMouseLeave)),
17594
- popoverRef.current && (popoverRef.current.removeEventListener("mouseenter", handlePopoverMouseEnter),
17595
- popoverRef.current.removeEventListener("mouseleave", handlePopoverMouseLeave)),
17596
- null !== timeoutRef.current && window.clearTimeout(timeoutRef.current);
17530
+ triggerRef.current.addEventListener("mouseenter", handleTriggerMouseEnter), triggerRef.current.addEventListener("mouseleave", handleTriggerMouseLeave),
17531
+ popoverRef.current.addEventListener("mouseenter", handlePopoverMouseEnter), popoverRef.current.addEventListener("mouseleave", handlePopoverMouseLeave);
17532
+ const currentTrigger = triggerRef.current, currentPopover = popoverRef.current;
17533
+ return () => {
17534
+ currentTrigger && (currentTrigger.removeEventListener("mouseenter", handleTriggerMouseEnter),
17535
+ currentTrigger.removeEventListener("mouseleave", handleTriggerMouseLeave)), currentPopover && (currentPopover.removeEventListener("mouseenter", handlePopoverMouseEnter),
17536
+ currentPopover.removeEventListener("mouseleave", handlePopoverMouseLeave)), null !== timeoutRef.current && window.clearTimeout(timeoutRef.current);
17597
17537
  };
17598
- }), [ trigger, delay, isOpenState ]);
17599
- const updatePosition = event => {
17538
+ }), [ trigger, delay, isOpenState, setIsOpen ]);
17539
+ const updatePosition = React.useCallback((event => {
17600
17540
  if (!triggerRef.current || !popoverRef.current) return;
17601
17541
  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;
17602
17542
  // If this is a scroll update and trigger isn't near edges, skip repositioning
@@ -17657,9 +17597,9 @@ const PopoverContext = React.createContext({
17657
17597
  // Add scroll position to convert viewport coordinates to absolute position
17658
17598
  const absoluteTop = top + window.scrollY, absoluteLeft = left + window.scrollX;
17659
17599
  // Apply position using absolute positioning to follow when scrolling
17660
- popoverRef.current.style.position = "absolute", popoverRef.current.style.top = `${absoluteTop}px`,
17661
- popoverRef.current.style.left = `${absoluteLeft}px`;
17662
- };
17600
+ popoverRef.current && (popoverRef.current.style.position = "absolute", popoverRef.current.style.top = `${absoluteTop}px`,
17601
+ popoverRef.current.style.left = `${absoluteLeft}px`);
17602
+ }), [ position, offset ]);
17663
17603
  // Position the popover
17664
17604
  return React.useEffect((() => {
17665
17605
  if (!isOpenState || !triggerRef.current || !popoverRef.current) return;
@@ -17685,7 +17625,7 @@ const PopoverContext = React.createContext({
17685
17625
  window.removeEventListener("resize", updatePosition), window.removeEventListener("scroll", handleScroll),
17686
17626
  scrollTimeout && clearTimeout(scrollTimeout), clearInterval(intervalId);
17687
17627
  };
17688
- }), [ isOpenState, position, offset ]),
17628
+ }), [ isOpenState, updatePosition ]),
17689
17629
  // Handle click outside to close popover
17690
17630
  React.useEffect((() => {
17691
17631
  if (!isOpenState || !closeOnClickOutside) return;
@@ -17695,7 +17635,7 @@ const PopoverContext = React.createContext({
17695
17635
  return document.addEventListener("mousedown", handleClickOutside), () => {
17696
17636
  document.removeEventListener("mousedown", handleClickOutside);
17697
17637
  };
17698
- }), [ isOpenState, closeOnClickOutside ]),
17638
+ }), [ isOpenState, closeOnClickOutside, setIsOpen ]),
17699
17639
  // Handle escape key to close popover
17700
17640
  React.useEffect((() => {
17701
17641
  if (!isOpenState || !closeOnEscape) return;
@@ -17705,7 +17645,7 @@ const PopoverContext = React.createContext({
17705
17645
  return document.addEventListener("keydown", handleEscapeKey), () => {
17706
17646
  document.removeEventListener("keydown", handleEscapeKey);
17707
17647
  };
17708
- }), [ isOpenState, closeOnEscape ]),
17648
+ }), [ isOpenState, closeOnEscape, setIsOpen ]),
17709
17649
  // Clean up on unmount
17710
17650
  React.useEffect((() => () => {
17711
17651
  null !== timeoutRef.current && window.clearTimeout(timeoutRef.current);
@@ -17886,10 +17826,11 @@ const calculateStarValue = (e, starValue, allowHalf) => {
17886
17826
  }), [ readOnly, onChange, allowHalf ]);
17887
17827
  // Use vanilla JS implementation if specified
17888
17828
  React.useEffect((() => {
17889
- if (useVanillaJS && "undefined" != typeof window && internalRef.current)
17829
+ if (!useVanillaJS || "undefined" == typeof window || !internalRef.current) return;
17830
+ const currentInstance = ratingInstance.current;
17890
17831
  // Cleanup on unmount
17891
- return () => {
17892
- ratingInstance.current && ratingInstance.current.destroy();
17832
+ return () => {
17833
+ currentInstance && currentInstance.destroy();
17893
17834
  };
17894
17835
  }), [ useVanillaJS, valueProp, defaultValue, maxValue, allowHalf, readOnly, size, variant, onChange ]),
17895
17836
  // Update vanilla JS implementation when props change
@@ -18010,10 +17951,11 @@ const ProductReview = ({productName: productName, productImage: productImage, in
18010
17951
  const [rating, setRating] = React.useState(initialRating), [comment, setComment] = React.useState(""), [submitted, setSubmitted] = React.useState(!1), reviewRef = React.useRef(null), reviewInstance = React.useRef(null);
18011
17952
  React.useEffect((() => {
18012
17953
  // Only run on client-side
18013
- if ("undefined" != typeof window && reviewRef.current)
17954
+ if ("undefined" == typeof window || !reviewRef.current) return;
17955
+ const currentInstance = reviewInstance.current;
18014
17956
  // Cleanup on unmount
18015
- return () => {
18016
- reviewInstance.current && reviewInstance.current.destroy();
17957
+ return () => {
17958
+ currentInstance && currentInstance.destroy();
18017
17959
  };
18018
17960
  }), [ productName, productImage, initialRating, maxRating, allowHalf, ratingColor, onSubmit ]);
18019
17961
  const handleSubmit = e => {
@@ -18258,10 +18200,11 @@ const SectionIntro = ({title: title, label: label, text: text, actions: actions,
18258
18200
  const sectionIntroRef = React.useRef(null), sectionIntroInstance = React.useRef(null);
18259
18201
  React.useEffect((() => {
18260
18202
  // Only run on client-side
18261
- if ("undefined" != typeof window && sectionIntroRef.current)
18203
+ if ("undefined" == typeof window || !sectionIntroRef.current) return;
18204
+ const currentInstance = sectionIntroInstance.current;
18262
18205
  // Cleanup on unmount
18263
- return () => {
18264
- sectionIntroInstance.current && sectionIntroInstance.current.destroy();
18206
+ return () => {
18207
+ currentInstance && currentInstance.destroy();
18265
18208
  };
18266
18209
  }), [ alignment, backgroundImageSrc, showOverlay, size, skeleton ]);
18267
18210
  // Determine CSS classes
@@ -18345,7 +18288,7 @@ SectionIntro.displayName = "SectionIntro";
18345
18288
 
18346
18289
  const Slider = React.forwardRef(((props, ref) => {
18347
18290
  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) {
18348
- 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 = React.useRef(null), wrapperRef = React.useRef(null), repositioningRef = React.useRef(!1), autoplayRef = React.useRef(null), [autoplayRunning, setAutoplayRunning] = React.useState(!1), sliderStateRef = React.useRef({
18291
+ 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 = React.useMemo((() => Array.isArray(rawSlides) ? rawSlides : []), [ rawSlides ]), containerRef = React.useRef(null), wrapperRef = React.useRef(null), repositioningRef = React.useRef(!1), autoplayRef = React.useRef(null), [autoplayRunning, setAutoplayRunning] = React.useState(!1), sliderStateRef = React.useRef({
18349
18292
  isTransitioning: !1,
18350
18293
  loop: loop,
18351
18294
  slides: slides,
@@ -18480,7 +18423,7 @@ const Slider = React.forwardRef(((props, ref) => {
18480
18423
  setIsTransitioning(!1), onSlideChange?.(nextIndex);
18481
18424
  }), speed);
18482
18425
  }
18483
- }), [ realIndex, internalIndex, slides.length, slidesToShow, loop, isTransitioning, speed, onSlideChange, allSlides.length, loopedSlides, autoplay ]), slidePrev = React.useCallback((() => {
18426
+ }), [ realIndex, internalIndex, slides.length, slidesToShow, loop, isTransitioning, speed, onSlideChange, autoplay ]), slidePrev = React.useCallback((() => {
18484
18427
  if (!isTransitioning) if (
18485
18428
  // Stop autoplay on interaction if disableOnInteraction is true
18486
18429
  autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
@@ -18502,7 +18445,7 @@ const Slider = React.forwardRef(((props, ref) => {
18502
18445
  setIsTransitioning(!1), onSlideChange?.(prevIndex);
18503
18446
  }), speed);
18504
18447
  }
18505
- }), [ realIndex, internalIndex, slides.length, loop, isTransitioning, speed, onSlideChange, allSlides.length, loopedSlides, autoplay ]), goToSlide = React.useCallback((index => {
18448
+ }), [ realIndex, internalIndex, slides.length, loop, isTransitioning, speed, onSlideChange, autoplay ]), goToSlide = React.useCallback((index => {
18506
18449
  isTransitioning || index === realIndex || (
18507
18450
  // Stop autoplay on interaction if disableOnInteraction is true
18508
18451
  autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
@@ -18510,7 +18453,7 @@ const Slider = React.forwardRef(((props, ref) => {
18510
18453
  setRealIndex(index), setInternalIndex(loop ? slides.length + index : index), setTimeout((() => {
18511
18454
  setIsTransitioning(!1), onSlideChange?.(index);
18512
18455
  }), speed));
18513
- }), [ realIndex, isTransitioning, speed, onSlideChange, loop, loopedSlides, autoplay ]), handleTouchStart = React.useCallback((e => {
18456
+ }), [ realIndex, isTransitioning, speed, onSlideChange, loop, slides.length, autoplay ]), handleTouchStart = React.useCallback((e => {
18514
18457
  if (!allowTouchMove) return;
18515
18458
  // Stop autoplay on interaction if disableOnInteraction is true
18516
18459
  autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
@@ -18765,7 +18708,7 @@ const Steps = ({items: items, activeIndex: activeIndex = 0, vertical: vertical =
18765
18708
  let content;
18766
18709
  React.useEffect((() => {
18767
18710
  currentStep !== activeIndex && setCurrentStep(activeIndex);
18768
- }), [ activeIndex ]),
18711
+ }), [ activeIndex, currentStep ]),
18769
18712
  // Legacy rendering
18770
18713
  content = items && items.length > 0 ? items.map(((item, index) => jsxRuntime.jsx(StepsItem, {
18771
18714
  index: index,
@@ -18909,7 +18852,7 @@ const TabsPanel = React.forwardRef((({children: children, className: className
18909
18852
 
18910
18853
  TabsPanel.displayName = "TabsPanel";
18911
18854
 
18912
- const Tabs = React.memo((({items: items, activeIndex: activeIndex = TAB.DEFAULTS.ACTIVE_INDEX, onTabChange: onTabChange, className: className = "", style: style, glass: glass, children: children}) => {
18855
+ const TabsComponentBase = ({items: items, activeIndex: activeIndex = TAB.DEFAULTS.ACTIVE_INDEX, onTabChange: onTabChange, className: className = "", style: style, glass: glass, children: children}) => {
18913
18856
  const [currentTab, setCurrentTab] = React.useState(activeIndex), handleTabClick = index => {
18914
18857
  setCurrentTab(index), onTabChange && onTabChange(index);
18915
18858
  }, handleKeyDown = (event, totalTabs) => {
@@ -19025,7 +18968,7 @@ const Tabs = React.memo((({items: items, activeIndex: activeIndex = TAB.DEFAULT
19025
18968
  });
19026
18969
  }
19027
18970
  return wrapper;
19028
- }));
18971
+ }, Tabs = React.memo(TabsComponentBase);
19029
18972
 
19030
18973
  Tabs.displayName = "Tabs", Tabs.List = TabsList, Tabs.Trigger = TabsTrigger, Tabs.Panels = TabsPanels,
19031
18974
  Tabs.Panel = TabsPanel;
@@ -19037,10 +18980,11 @@ const Testimonial = ({quote: quote, author: author, size: size = "", skeleton: s
19037
18980
  const testimonialRef = React.useRef(null), testimonialInstance = React.useRef(null);
19038
18981
  React.useEffect((() => {
19039
18982
  // Only run on client-side
19040
- if ("undefined" != typeof window && testimonialRef.current)
18983
+ if ("undefined" == typeof window || !testimonialRef.current) return;
18984
+ const currentInstance = testimonialInstance.current;
19041
18985
  // Cleanup on unmount
19042
- return () => {
19043
- testimonialInstance.current && testimonialInstance.current.destroy();
18986
+ return () => {
18987
+ currentInstance && currentInstance.destroy();
19044
18988
  };
19045
18989
  }), [ size, skeleton ]);
19046
18990
  // Determine CSS classes
@@ -20181,11 +20125,13 @@ const VideoPlayer = React.forwardRef((({src: src, type: type = "video", youtube
20181
20125
  detectBorderRadius();
20182
20126
  // Create ResizeObserver to watch for style changes
20183
20127
  let resizeObserver = null;
20184
- return "undefined" != typeof ResizeObserver && containerRef.current && (resizeObserver = new ResizeObserver(detectBorderRadius),
20128
+ "undefined" != typeof ResizeObserver && containerRef.current && (resizeObserver = new ResizeObserver(detectBorderRadius),
20185
20129
  resizeObserver.observe(containerRef.current)),
20186
20130
  // Also listen for window resize (in case styles change)
20187
- window.addEventListener("resize", detectBorderRadius), () => {
20188
- window.removeEventListener("resize", detectBorderRadius), resizeObserver && containerRef.current && (resizeObserver.unobserve(containerRef.current),
20131
+ window.addEventListener("resize", detectBorderRadius);
20132
+ const currentContainer = containerRef.current;
20133
+ return () => {
20134
+ window.removeEventListener("resize", detectBorderRadius), resizeObserver && currentContainer && (resizeObserver.unobserve(currentContainer),
20189
20135
  resizeObserver.disconnect());
20190
20136
  };
20191
20137
  }), []);
@@ -22536,7 +22482,7 @@ const logger = getLogger(), ThemeProvider = ({children: children, defaultTheme:
22536
22482
  // If defaultTheme is provided, use it
22537
22483
  return null != defaultTheme ? defaultTheme : "default";
22538
22484
  // Default fallback
22539
- }), [ defaultTheme, enablePersistence, storageKey ]), [currentTheme, setCurrentTheme] = React.useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : "tokens-theme")), [activeTokens, setActiveTokens] = React.useState((() => {
22485
+ }), [ defaultTheme, enablePersistence, storageKey, storageAdapter ]), [currentTheme, setCurrentTheme] = React.useState((() => "string" == typeof initialDefaultTheme ? initialDefaultTheme : "tokens-theme")), [activeTokens, setActiveTokens] = React.useState((() => {
22540
22486
  // If defaultTheme is DesignTokens, validate and store them
22541
22487
  if (defaultTheme && "string" != typeof defaultTheme) {
22542
22488
  const {tokens: tokens, validation: validation} = validateAndMergeTokens(defaultTheme);
@@ -23839,7 +23785,7 @@ class ThemeValidator {
23839
23785
  *
23840
23786
  * Provides detailed inspection and debugging information for themes
23841
23787
  */ const ThemeInspector = ({theme: theme, showValidation: showValidation = !0, showCSSVariables: showCSSVariables = !0, showStructure: showStructure = !0, className: className, style: style}) => {
23842
- const [activeTab, setActiveTab] = React.useState("overview"), [expandedSections, setExpandedSections] = React.useState(new Set([ "palette" ])), [searchQuery, setSearchQuery] = React.useState(""), [debouncedSearchQuery, setDebouncedSearchQuery] = React.useState(""), [copiedPath, setCopiedPath] = React.useState(null), searchTimeoutRef = React.useRef();
23788
+ const [activeTab, setActiveTab] = React.useState("overview"), [expandedSections, setExpandedSections] = React.useState(new Set([ "palette" ])), [searchQuery, setSearchQuery] = React.useState(""), [debouncedSearchQuery, setDebouncedSearchQuery] = React.useState(""), [copiedPath, setCopiedPath] = React.useState(null), searchTimeoutRef = React.useRef(void 0);
23843
23789
  // Debounce search query
23844
23790
  React.useEffect((() => (searchTimeoutRef.current && clearTimeout(searchTimeoutRef.current),
23845
23791
  searchTimeoutRef.current = setTimeout((() => {
@@ -24245,7 +24191,7 @@ class ThemeValidator {
24245
24191
  }) ]
24246
24192
  });
24247
24193
  }, ThemeComparator = ({themeA: themeA, themeB: themeB, showOnlyDifferences: showOnlyDifferences = !1, className: className, style: style}) => {
24248
- const [searchQuery, setSearchQuery] = React.useState(""), [debouncedSearchQuery, setDebouncedSearchQuery] = React.useState(""), [filterType, setFilterType] = React.useState("all"), [filterCategory, setFilterCategory] = React.useState("all"), searchTimeoutRef = React.useRef();
24194
+ const [searchQuery, setSearchQuery] = React.useState(""), [debouncedSearchQuery, setDebouncedSearchQuery] = React.useState(""), [filterType, setFilterType] = React.useState("all"), [filterCategory, setFilterCategory] = React.useState("all"), searchTimeoutRef = React.useRef(void 0);
24249
24195
  // Debounce search query
24250
24196
  React.useEffect((() => (searchTimeoutRef.current && clearTimeout(searchTimeoutRef.current),
24251
24197
  searchTimeoutRef.current = setTimeout((() => {
@@ -25041,7 +24987,7 @@ const ThemeLiveEditor = ({initialTheme: initialTheme, onChange: onChange, classN
25041
24987
  } catch (err) {
25042
24988
  setError(err instanceof Error ? err.message : "Invalid JSON");
25043
24989
  }
25044
- }), [ updateTheme ]), jsonUpdateTimeoutRef = React.useRef();
24990
+ }), [ updateTheme ]), jsonUpdateTimeoutRef = React.useRef(void 0);
25045
24991
  // Debounced JSON update to history
25046
24992
  React.useEffect((() => {
25047
24993
  if (!error) {
@@ -26185,45 +26131,21 @@ function mergePartStyles(base, override) {
26185
26131
  }
26186
26132
 
26187
26133
  /**
26188
- * Render a slot with the given props
26189
- *
26190
- * Priority order:
26191
- * 1. render function
26192
- * 2. component
26193
- * 3. children
26194
- * 4. fallback
26134
+ * Hook to merge theme overrides with component props
26195
26135
  *
26196
26136
  * @example
26197
- * renderSlot(
26198
- * { render: (props) => <CustomButton {...props} /> },
26199
- * { onClick: handleClick, children: 'Click me' }
26200
- * )
26201
- */ function renderSlot(slot, props, fallback) {
26202
- // No slot provided, use fallback
26203
- if (!slot) return fallback;
26204
- // Slot is a plain React node
26205
- if ( React__default.default.isValidElement(slot) || "string" == typeof slot || "number" == typeof slot) return slot;
26206
- // Slot is an object with rendering options
26207
- if ("object" == typeof slot && null !== slot) {
26208
- const slotObj = slot;
26209
- // Priority 1: render function
26210
- if (slotObj.render && "function" == typeof slotObj.render) return slotObj.render(props);
26211
- // Priority 2: component
26212
- if (slotObj.component) {
26213
- const Component = slotObj.component;
26214
- return jsxRuntime.jsx(Component, {
26215
- ...props
26216
- });
26217
- }
26218
- // Priority 3: children
26219
- if (void 0 !== slotObj.children) return slotObj.children;
26220
- }
26221
- // Fallback
26222
- return fallback;
26223
- }
26224
-
26225
- /**
26226
- * Check if a value is a slot configuration
26137
+ * function Button(props: ButtonProps) {
26138
+ * const customization = useComponentCustomization('Button', props);
26139
+ *
26140
+ * return (
26141
+ * <button
26142
+ * className={customization.className}
26143
+ * style={customization.style}
26144
+ * >
26145
+ * {props.children}
26146
+ * </button>
26147
+ * );
26148
+ * }
26227
26149
  */
26228
26150
  // Import and re-export as namespaces with proper typing
26229
26151
  // Export as namespaces with explicit typing
@@ -26626,25 +26548,7 @@ function(theme, selector = ":root") {
26626
26548
  }, exports.types = types, exports.unregisterTheme = unregisterTheme, exports.useAccordion = useAccordion,
26627
26549
  exports.useAtomixGlass = useAtomixGlass, exports.useBadge = useBadge, exports.useBarChart = useBarChart,
26628
26550
  exports.useBlock = useBlock, exports.useChartData = useChartData, exports.useChartInteraction = useChartInteraction,
26629
- exports.useChartScale = useChartScale, exports.useComponentCustomization =
26630
- /**
26631
- * Hook to merge theme overrides with component props
26632
- *
26633
- * @example
26634
- * function Button(props: ButtonProps) {
26635
- * const customization = useComponentCustomization('Button', props);
26636
- *
26637
- * return (
26638
- * <button
26639
- * className={customization.className}
26640
- * style={customization.style}
26641
- * >
26642
- * {props.children}
26643
- * </button>
26644
- * );
26645
- * }
26646
- */
26647
- function(component, props) {
26551
+ exports.useChartScale = useChartScale, exports.useComponentCustomization = function(component, props) {
26648
26552
  const {theme: theme} = useTheme(), cssVars = React.useMemo((() => mergeCSSVars(theme?.components?.[component]?.cssVars || {}, props.cssVars || {})), [ theme, component, props.cssVars ]), parts = React.useMemo((() => {
26649
26553
  const themeParts = theme?.components?.[component]?.parts || {}, propParts = props.parts || {}, merged = {};
26650
26554
  return new Set([ ...Object.keys(themeParts), ...Object.keys(propParts) ]).forEach((partName => {