@shohojdhara/atomix 0.4.8 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/atomix.config.ts +58 -1
  2. package/dist/atomix.css +148 -120
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +1 -1
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/charts.d.ts +33 -0
  7. package/dist/charts.js +1227 -122
  8. package/dist/charts.js.map +1 -1
  9. package/dist/core.d.ts +33 -10
  10. package/dist/core.js +1052 -41
  11. package/dist/core.js.map +1 -1
  12. package/dist/forms.d.ts +33 -0
  13. package/dist/forms.js +2086 -1035
  14. package/dist/forms.js.map +1 -1
  15. package/dist/heavy.d.ts +42 -1
  16. package/dist/heavy.js +1620 -600
  17. package/dist/heavy.js.map +1 -1
  18. package/dist/index.d.ts +441 -270
  19. package/dist/index.esm.js +1900 -638
  20. package/dist/index.esm.js.map +1 -1
  21. package/dist/index.js +1935 -670
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.min.js +1 -1
  24. package/dist/index.min.js.map +1 -1
  25. package/package.json +6 -3
  26. package/scripts/atomix-cli.js +148 -4
  27. package/scripts/cli/__tests__/basic.test.js +3 -2
  28. package/scripts/cli/__tests__/clean.test.js +278 -0
  29. package/scripts/cli/__tests__/component-validator.test.js +433 -0
  30. package/scripts/cli/__tests__/generator.test.js +613 -0
  31. package/scripts/cli/__tests__/glass-motion.test.js +256 -0
  32. package/scripts/cli/__tests__/integration.test.js +719 -108
  33. package/scripts/cli/__tests__/migrate.test.js +74 -0
  34. package/scripts/cli/__tests__/security.test.js +206 -0
  35. package/scripts/cli/__tests__/test-setup.js +3 -1
  36. package/scripts/cli/__tests__/theme-bridge.test.js +507 -0
  37. package/scripts/cli/__tests__/token-provider.test.js +361 -0
  38. package/scripts/cli/__tests__/utils.test.js +5 -5
  39. package/scripts/cli/commands/benchmark.js +105 -0
  40. package/scripts/cli/commands/build-theme.js +4 -1
  41. package/scripts/cli/commands/clean.js +109 -0
  42. package/scripts/cli/commands/doctor.js +88 -0
  43. package/scripts/cli/commands/generate.js +135 -14
  44. package/scripts/cli/commands/init.js +45 -18
  45. package/scripts/cli/commands/migrate.js +106 -0
  46. package/scripts/cli/commands/sync-tokens.js +206 -0
  47. package/scripts/cli/commands/theme-bridge.js +248 -0
  48. package/scripts/cli/commands/tokens.js +157 -0
  49. package/scripts/cli/commands/validate.js +194 -0
  50. package/scripts/cli/internal/ai-engine.js +156 -0
  51. package/scripts/cli/internal/component-validator.js +443 -0
  52. package/scripts/cli/internal/config-loader.js +162 -0
  53. package/scripts/cli/internal/filesystem.js +102 -2
  54. package/scripts/cli/internal/generator.js +359 -39
  55. package/scripts/cli/internal/glass-generator.js +398 -0
  56. package/scripts/cli/internal/hook-generator.js +369 -0
  57. package/scripts/cli/internal/hooks.js +61 -0
  58. package/scripts/cli/internal/itcss-generator.js +565 -0
  59. package/scripts/cli/internal/motion-generator.js +679 -0
  60. package/scripts/cli/internal/template-engine.js +301 -0
  61. package/scripts/cli/internal/theme-bridge.js +664 -0
  62. package/scripts/cli/internal/tokens/engine.js +122 -0
  63. package/scripts/cli/internal/tokens/provider.js +34 -0
  64. package/scripts/cli/internal/tokens/providers/figma.js +50 -0
  65. package/scripts/cli/internal/tokens/providers/style-dictionary.js +48 -0
  66. package/scripts/cli/internal/tokens/providers/w3c.js +48 -0
  67. package/scripts/cli/internal/tokens/token-provider.js +443 -0
  68. package/scripts/cli/internal/tokens/token-validator.js +513 -0
  69. package/scripts/cli/internal/validator.js +276 -0
  70. package/scripts/cli/internal/wizard.js +60 -6
  71. package/scripts/cli/mappings.js +23 -0
  72. package/scripts/cli/migration-tools.js +164 -94
  73. package/scripts/cli/plugins/style-dictionary.js +46 -0
  74. package/scripts/cli/templates/README.md +525 -95
  75. package/scripts/cli/templates/common-templates.js +40 -14
  76. package/scripts/cli/templates/components/react-component.ts +282 -0
  77. package/scripts/cli/templates/config/project-config.ts +112 -0
  78. package/scripts/cli/templates/hooks/use-component.ts +477 -0
  79. package/scripts/cli/templates/index.js +19 -4
  80. package/scripts/cli/templates/index.ts +171 -0
  81. package/scripts/cli/templates/next-templates.js +72 -0
  82. package/scripts/cli/templates/react-templates.js +70 -126
  83. package/scripts/cli/templates/scss-templates.js +35 -35
  84. package/scripts/cli/templates/stories/storybook-story.ts +241 -0
  85. package/scripts/cli/templates/styles/scss-component.ts +255 -0
  86. package/scripts/cli/templates/tests/vitest-test.ts +229 -0
  87. package/scripts/cli/templates/token-templates.js +337 -1
  88. package/scripts/cli/templates/tokens/token-generators.ts +1088 -0
  89. package/scripts/cli/templates/types/component-types.ts +145 -0
  90. package/scripts/cli/templates/utils/testing-utils.ts +144 -0
  91. package/scripts/cli/templates/vanilla-templates.js +39 -0
  92. package/scripts/cli/token-manager.js +8 -2
  93. package/scripts/cli/utils/cache-manager.js +240 -0
  94. package/scripts/cli/utils/detector.js +46 -0
  95. package/scripts/cli/utils/diagnostics.js +289 -0
  96. package/scripts/cli/utils/error.js +45 -3
  97. package/scripts/cli/utils/helpers.js +24 -0
  98. package/scripts/cli/utils/logger.js +1 -1
  99. package/scripts/cli/utils/security.js +302 -0
  100. package/scripts/cli/utils/telemetry.js +115 -0
  101. package/scripts/cli/utils/validation.js +4 -38
  102. package/scripts/cli/utils.js +46 -0
  103. package/src/components/Accordion/Accordion.stories.tsx +0 -18
  104. package/src/components/Accordion/Accordion.test.tsx +0 -17
  105. package/src/components/Accordion/Accordion.tsx +0 -4
  106. package/src/components/AtomixGlass/AtomixGlass.tsx +102 -2
  107. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +125 -12
  108. package/src/components/AtomixGlass/PerformanceDashboard.tsx +219 -0
  109. package/src/components/AtomixGlass/README.md +25 -10
  110. package/src/components/AtomixGlass/animation-system.ts +578 -0
  111. package/src/components/AtomixGlass/shader-utils.ts +3 -0
  112. package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +653 -0
  113. package/src/components/AtomixGlass/stories/AnimationTests.stories.tsx +95 -0
  114. package/src/components/AtomixGlass/stories/CardExamples.stories.tsx +212 -0
  115. package/src/components/AtomixGlass/stories/DashboardExamples.stories.tsx +348 -0
  116. package/src/components/AtomixGlass/stories/EcommerceExamples.stories.tsx +410 -0
  117. package/src/components/AtomixGlass/stories/FormExamples.stories.tsx +436 -0
  118. package/src/components/AtomixGlass/stories/HeroExamples.stories.tsx +264 -0
  119. package/src/components/AtomixGlass/stories/InteractivePlayground.stories.tsx +247 -0
  120. package/src/components/AtomixGlass/stories/MobileUIExamples.stories.tsx +418 -0
  121. package/src/components/AtomixGlass/stories/ModalExamples.stories.tsx +402 -0
  122. package/src/components/AtomixGlass/stories/Overview.stories.tsx +157 -6
  123. package/src/components/AtomixGlass/stories/Playground.stories.tsx +658 -93
  124. package/src/components/AtomixGlass/stories/PresetGallery.stories.tsx +335 -0
  125. package/src/components/AtomixGlass/stories/WidgetExamples.stories.tsx +441 -0
  126. package/src/components/AtomixGlass/stories/argTypes.ts +384 -0
  127. package/src/components/AtomixGlass/stories/shared-components.tsx +91 -1
  128. package/src/components/AtomixGlass/stories/types.ts +127 -0
  129. package/src/components/Avatar/Avatar.tsx +1 -1
  130. package/src/components/Button/Button.stories.disabled-link.tsx +10 -0
  131. package/src/components/Button/Button.stories.tsx +10 -0
  132. package/src/components/Button/Button.test.tsx +16 -11
  133. package/src/components/Button/Button.tsx +4 -4
  134. package/src/components/Card/Card.tsx +1 -1
  135. package/src/components/Dropdown/Dropdown.tsx +12 -12
  136. package/src/components/Form/Select.tsx +62 -3
  137. package/src/components/Modal/Modal.tsx +14 -3
  138. package/src/components/Navigation/Navbar/Navbar.tsx +44 -0
  139. package/src/components/Slider/Slider.stories.tsx +3 -3
  140. package/src/components/Slider/Slider.tsx +38 -0
  141. package/src/components/Steps/Steps.tsx +3 -3
  142. package/src/components/Tabs/Tabs.tsx +77 -8
  143. package/src/components/Testimonial/Testimonial.tsx +1 -1
  144. package/src/components/TypedButton/TypedButton.stories.tsx +59 -0
  145. package/src/components/TypedButton/TypedButton.tsx +39 -0
  146. package/src/components/TypedButton/index.ts +2 -0
  147. package/src/components/VideoPlayer/VideoPlayer.tsx +11 -4
  148. package/src/lib/composables/index.ts +4 -7
  149. package/src/lib/composables/types.ts +45 -0
  150. package/src/lib/composables/useAccordion.ts +0 -7
  151. package/src/lib/composables/useAtomixGlass.ts +144 -5
  152. package/src/lib/composables/useChartExport.ts +3 -13
  153. package/src/lib/composables/useDropdown.ts +66 -0
  154. package/src/lib/composables/useFocusTrap.ts +80 -0
  155. package/src/lib/composables/usePerformanceMonitor.ts +448 -0
  156. package/src/lib/composables/useResponsiveGlass.presets.ts +192 -0
  157. package/src/lib/composables/useResponsiveGlass.ts +441 -0
  158. package/src/lib/composables/useTooltip.ts +16 -0
  159. package/src/lib/composables/useTypedButton.ts +66 -0
  160. package/src/lib/config/index.ts +62 -5
  161. package/src/lib/constants/components.ts +55 -0
  162. package/src/lib/theme/devtools/__tests__/useHistory.test.tsx +150 -0
  163. package/src/lib/theme/tokens/centralized-tokens.ts +120 -0
  164. package/src/lib/theme/utils/__tests__/domUtils.test.ts +101 -0
  165. package/src/lib/types/components.ts +37 -11
  166. package/src/lib/types/glass.ts +35 -0
  167. package/src/lib/types/index.ts +1 -0
  168. package/src/lib/utils/displacement-generator.ts +1 -1
  169. package/src/styles/01-settings/_settings.testtypecheck.scss +53 -0
  170. package/src/styles/01-settings/_settings.typedbutton.scss +53 -0
  171. package/src/styles/06-components/_components.testbutton.scss +212 -0
  172. package/src/styles/06-components/_components.testtypecheck.scss +212 -0
  173. package/src/styles/06-components/_components.typedbutton.scss +212 -0
  174. package/src/styles/99-utilities/_index.scss +1 -0
  175. package/src/styles/99-utilities/_utilities.text.scss +1 -1
  176. package/src/styles/99-utilities/_utilities.touch-target.scss +36 -0
  177. package/src/styles/06-components/old.chart.styles.scss +0 -2788
package/dist/index.js CHANGED
@@ -413,6 +413,14 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
413
413
  ICON_ELEMENT: "icon",
414
414
  LABEL_ELEMENT: "label",
415
415
  SPINNER_ELEMENT: "spinner"
416
+ }, TYPEDBUTTON = {
417
+ BASE_CLASS: "c-typedbutton",
418
+ VARIANT_PREFIX: "c-typedbutton--",
419
+ CLASSES: {
420
+ BASE: "c-typedbutton",
421
+ DISABLED: "c-typedbutton--disabled",
422
+ GLASS: "c-typedbutton--glass"
423
+ }
416
424
  }, BUTTON = {
417
425
  BASE_CLASS: "c-btn",
418
426
  ICON_CLASS: "c-btn__icon",
@@ -1750,7 +1758,16 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
1750
1758
  PADDING: "0",
1751
1759
  MODE: "standard",
1752
1760
  OVER_LIGHT: !1,
1753
- ENABLE_OVER_LIGHT_LAYERS: !0
1761
+ ENABLE_OVER_LIGHT_LAYERS: !0,
1762
+ // Phase 1: Time-Based Animation System defaults
1763
+ WITH_TIME_ANIMATION: !0,
1764
+ ANIMATION_SPEED: 1,
1765
+ // Phase 1: Multi-Layer Distortion System defaults
1766
+ WITH_MULTI_LAYER_DISTORTION: !1,
1767
+ DISTORTION_OCTAVES: 5,
1768
+ DISTORTION_LACUNARITY: 2,
1769
+ DISTORTION_GAIN: .5,
1770
+ DISTORTION_QUALITY: "high"
1754
1771
  },
1755
1772
  CONSTANTS: {
1756
1773
  ACTIVATION_ZONE: 200,
@@ -1913,6 +1930,44 @@ const THEME_COLORS = [ "primary", "secondary", "success", "info", "warning", "er
1913
1930
  // Saturation constants
1914
1931
  SATURATION: {
1915
1932
  HIGH_CONTRAST: 200
1933
+ },
1934
+ // Phase 1: Animation System Constants
1935
+ ANIMATION: {
1936
+ // Breathing effect timing (in milliseconds)
1937
+ BREATHING_CYCLE: 2e3,
1938
+ // 2-second breathing cycle
1939
+ // Flow animation speed
1940
+ FLOW_SPEED_X: .1,
1941
+ // Horizontal flow speed
1942
+ FLOW_SPEED_Y: .15,
1943
+ // Vertical flow speed
1944
+ // Wave propagation
1945
+ WAVE_SPEED: .05,
1946
+ // Radial wave speed
1947
+ WAVE_AMPLITUDE: .02
1948
+ },
1949
+ // Phase 1: Multi-Layer Distortion Quality Presets
1950
+ DISTORTION_QUALITY_PRESETS: {
1951
+ low: {
1952
+ octaves: 2,
1953
+ lacunarity: 2,
1954
+ gain: .5
1955
+ },
1956
+ medium: {
1957
+ octaves: 4,
1958
+ lacunarity: 2,
1959
+ gain: .5
1960
+ },
1961
+ high: {
1962
+ octaves: 5,
1963
+ lacunarity: 2,
1964
+ gain: .5
1965
+ },
1966
+ ultra: {
1967
+ octaves: 7,
1968
+ lacunarity: 2,
1969
+ gain: .5
1970
+ }
1916
1971
  }
1917
1972
  }
1918
1973
  };
@@ -1961,9 +2016,7 @@ function useAccordion(initialProps) {
1961
2016
  toggle: () => {
1962
2017
  if (!defaultProps.disabled) {
1963
2018
  const nextOpen = !isOpen;
1964
- isControlled || setInternalOpen(nextOpen), defaultProps.onOpenChange?.(nextOpen),
1965
- // Call legacy handlers
1966
- nextOpen ? defaultProps.onOpen?.() : defaultProps.onClose?.();
2019
+ isControlled || setInternalOpen(nextOpen), defaultProps.onOpenChange?.(nextOpen);
1967
2020
  }
1968
2021
  },
1969
2022
  updatePanelHeight: updatePanelHeight,
@@ -2050,7 +2103,7 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateDistance = (pos1, pos2)
2050
2103
  // Silently handle errors
2051
2104
  }
2052
2105
  return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
2053
- }, lerp = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
2106
+ }, lerp$1 = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
2054
2107
  switch (mode) {
2055
2108
  case "standard":
2056
2109
  return displacementMap;
@@ -2220,14 +2273,16 @@ const sharedShaderCache = new Map, AtomixGlassContainer = React.forwardRef((({c
2220
2273
  }, 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 = {
2221
2274
  width: 0,
2222
2275
  height: 0
2223
- }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, contentRef: contentRef}, ref) => {
2276
+ }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1,
2277
+ // Phase 1: Animation System props
2278
+ 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) => {
2224
2279
  // Generate a stable, deterministic ID for SSR compatibility
2225
2280
  // Use a module-level counter that's consistent across server and client
2226
- const filterId = React.useMemo((() => "atomix-glass-filter-" + ++idCounter), []), [shaderMapUrl, setShaderMapUrl] = React.useState(""), shaderGeneratorRef = React.useRef(null), shaderUtilsRef = React.useRef(null), shaderDebounceTimeoutRef = React.useRef(null);
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);
2227
2282
  // Lazy load shader utilities only when shader mode is needed
2228
2283
  React.useEffect((() => {
2229
2284
  "shader" === mode ?
2230
- // Dynamic import shader utilities
2285
+ // Dynamic import shader utilities with animation support
2231
2286
  Promise.resolve().then((function() {
2232
2287
  return shaderUtils;
2233
2288
  })).then((shaderUtils => {
@@ -2244,7 +2299,7 @@ const sharedShaderCache = new Map, AtomixGlassContainer = React.forwardRef((({c
2244
2299
  // Generate shader map with debouncing and caching
2245
2300
  React.useEffect((() => {
2246
2301
  // Enhanced validation for shader mode
2247
- if ("shader" === mode && glassSize && validateGlassSize(glassSize) && shaderUtilsRef.current) {
2302
+ if ("shader" === mode && glassSize && validateGlassSize(glassSize)) {
2248
2303
  // Create cache key from size and variant
2249
2304
  const cacheKey = `${glassSize.width}x${glassSize.height}-${shaderVariant}`, cachedUrl = (key => {
2250
2305
  const entry = sharedShaderCache.get(key);
@@ -2266,11 +2321,9 @@ const sharedShaderCache = new Map, AtomixGlassContainer = React.forwardRef((({c
2266
2321
  width: glassSize.width,
2267
2322
  height: glassSize.height,
2268
2323
  fragment: selectedShader
2269
- }),
2270
- // Defer shader generation with longer delay to avoid blocking
2271
- setTimeout((() => {
2324
+ }), shaderUpdateTimeoutRef.current = setTimeout((() => {
2272
2325
  const url = shaderGeneratorRef.current?.updateShader() || "";
2273
- ((key, url) => {
2326
+ url && ((key, url) => {
2274
2327
  // Evict oldest entries if at capacity
2275
2328
  if (sharedShaderCache.size >= 15) {
2276
2329
  const entries = Array.from(sharedShaderCache.entries());
@@ -2302,7 +2355,8 @@ const sharedShaderCache = new Map, AtomixGlassContainer = React.forwardRef((({c
2302
2355
  // Cleanup function with error handling
2303
2356
  return () => {
2304
2357
  shaderDebounceTimeoutRef.current && (clearTimeout(shaderDebounceTimeoutRef.current),
2305
- shaderDebounceTimeoutRef.current = null);
2358
+ shaderDebounceTimeoutRef.current = null), shaderUpdateTimeoutRef.current && (clearTimeout(shaderUpdateTimeoutRef.current),
2359
+ shaderUpdateTimeoutRef.current = null);
2306
2360
  try {
2307
2361
  shaderGeneratorRef.current?.destroy();
2308
2362
  } catch (error) {
@@ -2311,7 +2365,37 @@ const sharedShaderCache = new Map, AtomixGlassContainer = React.forwardRef((({c
2311
2365
  shaderGeneratorRef.current = null;
2312
2366
  }
2313
2367
  };
2314
- }), [ mode, glassSize, shaderVariant ]);
2368
+ }), [ mode, glassSize, shaderVariant ]),
2369
+ // Phase 1: Time-Based Animation Loop - Continuous shader regeneration
2370
+ React.useEffect((() => {
2371
+ // Only run animations in shader mode with time animation enabled
2372
+ if ("shader" !== mode || !withTimeAnimation || effectiveReducedMotion || effectiveWithoutEffects)
2373
+ // Cancel any existing animation frame
2374
+ return void (null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
2375
+ animationFrameRef.current = null));
2376
+ const baseFps = "ultra" === distortionQuality ? 60 : "high" === distortionQuality ? 30 : "medium" === distortionQuality ? 24 : 20, effectiveSpeed = Math.max(.5, Math.min(2, animationSpeed || 1)), complexity = withMultiLayerDistortion ? Math.max(1, (distortionOctaves || 3) / 3 + .25 * Math.max(0, (distortionLacunarity || 2) - 2) + Math.max(0, (distortionGain || .5) - .5)) : 1, frameInterval = 1e3 / Math.max(12, Math.min(60, Math.round(baseFps * effectiveSpeed / complexity)));
2377
+ let lastUpdate = 0, isCancelled = !1;
2378
+ const animate = currentTime => {
2379
+ if (!isCancelled) {
2380
+ if (currentTime - lastUpdate >= frameInterval && shaderGeneratorRef.current) {
2381
+ lastUpdate = currentTime;
2382
+ try {
2383
+ const animatedShaderUrl = shaderGeneratorRef.current.updateShader();
2384
+ animatedShaderUrl && setShaderMapUrl(animatedShaderUrl);
2385
+ } catch (error) {
2386
+ console.warn("AtomixGlassContainer: Error in animation loop", error);
2387
+ }
2388
+ }
2389
+ animationFrameRef.current = requestAnimationFrame(animate);
2390
+ }
2391
+ };
2392
+ // Start animation loop
2393
+ // Cleanup animation on unmount or dependency change
2394
+ return animationFrameRef.current = requestAnimationFrame(animate), () => {
2395
+ isCancelled = !0, null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
2396
+ animationFrameRef.current = null);
2397
+ };
2398
+ }), [ mode, withTimeAnimation, animationSpeed, displacementScale, withMultiLayerDistortion, distortionOctaves, distortionLacunarity, distortionGain, distortionQuality, effectiveReducedMotion, effectiveWithoutEffects, glassSize ]);
2315
2399
  // Removed forced reflow to avoid layout thrash and potential feedback sizing loops
2316
2400
  const [rectCache, setRectCache] = React.useState(null);
2317
2401
  React.useEffect((() => {
@@ -2645,12 +2729,144 @@ class {
2645
2729
  style.setProperty("--atomix-glass-container-text-shadow", isOverLight ? "0px 1px 2px rgba(255, 255, 255, 0.15)" : "0px 2px 12px rgba(0, 0, 0, 0.4)"),
2646
2730
  style.setProperty("--atomix-glass-container-box-shadow", isOverLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)");
2647
2731
  }
2648
- }, {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
2732
+ };
2649
2733
 
2650
2734
  /**
2651
2735
  * Updates the styles of the AtomixGlass wrapper and container elements imperatively
2652
2736
  * to avoid React re-renders on mouse movement.
2653
- */ const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new WeakMap, setCachedBackgroundDetection = (parentElement, overLightConfig, result, threshold) => {
2737
+ */
2738
+ /**
2739
+ * Animation System for AtomixGlass Component
2740
+ *
2741
+ * Implements Phase 1 features from the AtomixGlass Feature Implementation Roadmap:
2742
+ * - Feature 1.1: Time-Based Animation System
2743
+ * - Feature 1.2: Multi-Layer Distortion System (FBM)
2744
+ *
2745
+ * @packageDocumentation
2746
+ */
2747
+ // ============================================================================
2748
+ // Noise Functions for FBM (Feature 1.2)
2749
+ // ============================================================================
2750
+ /**
2751
+ * Perlin noise implementation for smooth gradient noise
2752
+ *
2753
+ * @param x - X coordinate
2754
+ * @param y - Y coordinate
2755
+ * @returns Noise value in range [0, 1]
2756
+ */
2757
+ function perlinNoise(x, y) {
2758
+ // Simplified Perlin noise using pseudo-random gradients
2759
+ const X = 255 & Math.floor(x), Y = 255 & Math.floor(y), xf = x - Math.floor(x), yf = y - Math.floor(y), u = fade(xf), v = fade(yf), A = p[X] + Y & 255, B = p[X + 1] + Y & 255, ga = grad(p[A], xf, yf), gb = grad(p[B], xf - 1, yf), gc = grad(p[A + 1 & 255], xf, yf - 1), gd = grad(p[B + 1 & 255], xf - 1, yf - 1), lerpX1 = lerp(ga, gb, u), lerpX2 = lerp(gc, gd, u);
2760
+ // Scale to [0, 1] range
2761
+ return (lerp(lerpX1, lerpX2, v) + 1) / 2;
2762
+ }
2763
+
2764
+ // ============================================================================
2765
+ // Fractal Brownian Motion (FBM) Engine (Feature 1.2)
2766
+ // ============================================================================
2767
+ /**
2768
+ * Creates an FBM engine with configurable parameters
2769
+ *
2770
+ * @param config - FBM configuration (octaves, lacunarity, gain)
2771
+ * @returns Object with fbm function
2772
+ *
2773
+ * @example
2774
+ * ```typescript
2775
+ * const fbmEngine = createFBMEngine({ octaves: 5, lacunarity: 2, gain: 0.5 });
2776
+ *
2777
+ * // Generate noise at position (0.5, 0.5) with time animation
2778
+ * const noiseValue = fbmEngine.fbm(0.5, 0.5, Date.now());
2779
+ * ```
2780
+ */ function createFBMEngine(config) {
2781
+ /**
2782
+ * Fractal Brownian Motion function
2783
+ * Combines multiple octaves of noise for complex, natural patterns
2784
+ *
2785
+ * @param x - X coordinate
2786
+ * @param y - Y coordinate
2787
+ * @param time - Optional time value for animation
2788
+ * @returns FBM noise value in range [0, 1]
2789
+ */
2790
+ const fbm = (x, y, time = 0) => {
2791
+ let value = 0, amplitude = .5, frequency = 1, phase = .001 * time;
2792
+ // Convert to seconds for reasonable animation speed
2793
+ for (let i = 0; i < config.octaves; i++)
2794
+ // Apply time-based phase shift to all octaves
2795
+ value += perlinNoise(x * frequency + phase, y * frequency + phase) * amplitude,
2796
+ frequency *= config.lacunarity, // Increase frequency
2797
+ amplitude *= config.gain;
2798
+ return value;
2799
+ };
2800
+ /**
2801
+ * Get FBM with simple time factor
2802
+ */ return {
2803
+ fbm: fbm,
2804
+ fbmWithTime: (x, y, time) => fbm(x, y, time)
2805
+ };
2806
+ }
2807
+
2808
+ /**
2809
+ * Gets optimal FBM config based on quality preset
2810
+ *
2811
+ * @param quality - Quality preset level
2812
+ * @returns FBM configuration for the quality level
2813
+ */ const fbmEngineCache = new Map;
2814
+
2815
+ // ============================================================================
2816
+ // Shader Utility Functions for Time-Based Effects
2817
+ // ============================================================================
2818
+ /**
2819
+ * Liquid glass distortion with time-based animation
2820
+ * Uses FBM to create organic, flowing liquid effects
2821
+ *
2822
+ * @param uv - UV coordinates (normalized 0-1)
2823
+ * @param time - Elapsed time in milliseconds
2824
+ * @param config - FBM configuration
2825
+ * @returns Distorted UV coordinates
2826
+ */ function liquidGlassWithTime(uv, time, config) {
2827
+ const configKey = `${config.octaves}-${config.lacunarity}-${config.gain}`;
2828
+ let fbmEngine = fbmEngineCache.get(configKey);
2829
+ fbmEngine || (fbmEngine = createFBMEngine(config), fbmEngineCache.set(configKey, fbmEngine));
2830
+ // Animate noise with time
2831
+ const animatedNoise = fbmEngine.fbmWithTime(2 * uv.x + 1e-4 * time, 2 * uv.y + 15e-5 * time, time);
2832
+ return {
2833
+ x: uv.x + .04 * (animatedNoise - .5),
2834
+ y: uv.y + .04 * (animatedNoise - .5)
2835
+ };
2836
+ }
2837
+
2838
+ // ============================================================================
2839
+ // Helper Functions
2840
+ // ============================================================================
2841
+ /**
2842
+ * Fade curve for smooth interpolation (Perlin's fade function)
2843
+ */ function fade(t) {
2844
+ return t * t * t * (t * (6 * t - 15) + 10);
2845
+ }
2846
+
2847
+ /**
2848
+ * Linear interpolation
2849
+ */ function lerp(a, b, t) {
2850
+ return a + t * (b - a);
2851
+ }
2852
+
2853
+ /**
2854
+ * Gradient calculation for Perlin noise
2855
+ */ function grad(hash, x, y) {
2856
+ const h = 15 & hash, u = h < 8 ? x : y, v = h < 4 ? y : 12 === h || 14 === h ? x : 0;
2857
+ return (1 & h ? -u : u) + (2 & h ? -v : v);
2858
+ }
2859
+
2860
+ /**
2861
+ * Permutation table for Perlin noise
2862
+ */ const p = (() => {
2863
+ const permutation = [];
2864
+ for (let i = 0; i < 256; i++) permutation[i] = Math.floor(256 * Math.random());
2865
+ // Duplicate for overflow handling
2866
+ return [ ...permutation, ...permutation ];
2867
+ })(), {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
2868
+
2869
+ const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new WeakMap, setCachedBackgroundDetection = (parentElement, overLightConfig, result, threshold) => {
2654
2870
  parentElement && backgroundDetectionCache.set(parentElement, {
2655
2871
  result: result,
2656
2872
  timestamp: Date.now(),
@@ -2663,7 +2879,9 @@ class {
2663
2879
  * Composable hook for AtomixGlass component logic
2664
2880
  * Manages all state, calculations, and event handlers
2665
2881
  */
2666
- function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef: wrapperRef, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, elasticity: elasticity = .05, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, children: children, blurAmount: blurAmount, saturation: saturation, padding: padding, withLiquidBlur: withLiquidBlur, isFixedOrSticky: isFixedOrSticky = !1}) {
2882
+ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef: wrapperRef, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, elasticity: elasticity = .05, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, children: children, blurAmount: blurAmount, saturation: saturation, padding: padding, withLiquidBlur: withLiquidBlur, isFixedOrSticky: isFixedOrSticky = !1, withTimeAnimation:
2883
+ // Phase 1: Animation System Props
2884
+ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: animationSpeed = ATOMIX_GLASS.DEFAULTS.ANIMATION_SPEED, withMultiLayerDistortion: withMultiLayerDistortion = ATOMIX_GLASS.DEFAULTS.WITH_MULTI_LAYER_DISTORTION, distortionOctaves: distortionOctaves = ATOMIX_GLASS.DEFAULTS.DISTORTION_OCTAVES, distortionLacunarity: distortionLacunarity = ATOMIX_GLASS.DEFAULTS.DISTORTION_LACUNARITY, distortionGain: distortionGain = ATOMIX_GLASS.DEFAULTS.DISTORTION_GAIN, distortionQuality: distortionQuality = ATOMIX_GLASS.DEFAULTS.DISTORTION_QUALITY}) {
2667
2885
  // State
2668
2886
  const [isHovered, setIsHovered] = React.useState(!1), [isActive, setIsActive] = React.useState(!1), cachedRectRef = React.useRef(null), internalGlobalMousePositionRef = React.useRef({
2669
2887
  x: 0,
@@ -2677,7 +2895,47 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2677
2895
  }), targetGlobalMousePositionRef = React.useRef({
2678
2896
  x: 0,
2679
2897
  y: 0
2680
- }), lerpRafRef = React.useRef(null), lerpActiveRef = React.useRef(!1), [dynamicBorderRadius, setDynamicCornerRadius] = React.useState(CONSTANTS.DEFAULT_CORNER_RADIUS), [userPrefersReducedMotion, setUserPrefersReducedMotion] = React.useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = React.useState(!1), [detectedOverLight, setDetectedOverLight] = React.useState(!1), effectiveBorderRadius = React.useMemo((() => void 0 !== borderRadius ? Math.max(0, borderRadius) : Math.max(0, dynamicBorderRadius)), [ borderRadius, dynamicBorderRadius ]), {glassSize: glassSize} = function({glassRef: glassRef, effectiveBorderRadius: effectiveBorderRadius, cachedRectRef: cachedRectRef}) {
2898
+ }), lerpRafRef = React.useRef(null), lerpActiveRef = React.useRef(!1), [dynamicBorderRadius, setDynamicCornerRadius] = React.useState(CONSTANTS.DEFAULT_CORNER_RADIUS), [userPrefersReducedMotion, setUserPrefersReducedMotion] = React.useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = React.useState(!1), [detectedOverLight, setDetectedOverLight] = React.useState(!1), animationFrameIdRef = React.useRef(null), animationStartTimeRef = React.useRef(0), elapsedTimeRef = React.useRef(0), shaderTimeRef = React.useRef(0), fbmConfig = React.useMemo((() => {
2899
+ // If quality preset is provided, use it as base
2900
+ const preset = (quality = distortionQuality, ATOMIX_GLASS.CONSTANTS.DISTORTION_QUALITY_PRESETS[quality]);
2901
+ // Override with custom values if provided
2902
+ var quality;
2903
+ return {
2904
+ octaves: distortionOctaves ?? preset.octaves,
2905
+ lacunarity: distortionLacunarity ?? preset.lacunarity,
2906
+ gain: distortionGain ?? preset.gain
2907
+ };
2908
+ }), [ distortionQuality, distortionOctaves, distortionLacunarity, distortionGain ]), fbmEngine = React.useMemo((() => withMultiLayerDistortion ? createFBMEngine(fbmConfig) : null), [ withMultiLayerDistortion, fbmConfig ]), effectiveReducedMotion = React.useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveWithTimeAnimation = React.useMemo((() => withTimeAnimation && !effectiveReducedMotion), [ withTimeAnimation, effectiveReducedMotion ]);
2909
+ /**
2910
+ * Animation loop for time-based effects
2911
+ */
2912
+ React.useEffect((() => {
2913
+ if (!effectiveWithTimeAnimation || "undefined" == typeof window) return;
2914
+ let lastFrameTime = performance.now();
2915
+ /**
2916
+ * Animation frame handler
2917
+ */ const animate = currentTime => {
2918
+ // Calculate delta time
2919
+ const deltaTime = currentTime - lastFrameTime;
2920
+ lastFrameTime = currentTime;
2921
+ // Apply animation speed multiplier
2922
+ const scaledDelta = deltaTime * animationSpeed;
2923
+ elapsedTimeRef.current += scaledDelta, shaderTimeRef.current = elapsedTimeRef.current,
2924
+ // Continue animation loop
2925
+ animationFrameIdRef.current = requestAnimationFrame(animate);
2926
+ };
2927
+ // Start animation
2928
+ // Cleanup
2929
+ return animationStartTimeRef.current = performance.now(), animationFrameIdRef.current = requestAnimationFrame(animate),
2930
+ () => {
2931
+ null !== animationFrameIdRef.current && (cancelAnimationFrame(animationFrameIdRef.current),
2932
+ animationFrameIdRef.current = null);
2933
+ };
2934
+ }), [ effectiveWithTimeAnimation, animationSpeed ]);
2935
+ /**
2936
+ * Get current shader time for animations
2937
+ */
2938
+ const getShaderTime = React.useCallback((() => shaderTimeRef.current), []), applyTimeBasedDistortion = React.useCallback((uv => effectiveWithTimeAnimation && fbmEngine ? liquidGlassWithTime(uv, shaderTimeRef.current, fbmConfig) : uv), [ effectiveWithTimeAnimation, fbmEngine, fbmConfig ]), effectiveBorderRadius = React.useMemo((() => void 0 !== borderRadius ? Math.max(0, borderRadius) : Math.max(0, dynamicBorderRadius)), [ borderRadius, dynamicBorderRadius ]), {glassSize: glassSize} = function({glassRef: glassRef, effectiveBorderRadius: effectiveBorderRadius, cachedRectRef: cachedRectRef}) {
2681
2939
  const [glassSize, setGlassSize] = React.useState({
2682
2940
  width: 270,
2683
2941
  height: 69
@@ -2736,7 +2994,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2736
2994
  glassRef: glassRef,
2737
2995
  effectiveBorderRadius: effectiveBorderRadius,
2738
2996
  cachedRectRef: cachedRectRef
2739
- }), effectiveReducedMotion = React.useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveHighContrast = React.useMemo((() => highContrast || userPrefersHighContrast), [ highContrast, userPrefersHighContrast ]), effectiveWithoutEffects = React.useMemo((() => withoutEffects || effectiveReducedMotion), [ withoutEffects, effectiveReducedMotion ]), globalMousePosition = externalGlobalMousePosition || internalGlobalMousePositionRef.current, mouseOffset = externalMouseOffset || internalMouseOffsetRef.current;
2997
+ }), effectiveHighContrast = React.useMemo((() => highContrast || userPrefersHighContrast), [ highContrast, userPrefersHighContrast ]), effectiveWithoutEffects = React.useMemo((() => withoutEffects || effectiveReducedMotion), [ withoutEffects, effectiveReducedMotion ]), globalMousePosition = externalGlobalMousePosition || internalGlobalMousePositionRef.current, mouseOffset = externalMouseOffset || internalMouseOffsetRef.current;
2998
+ /**
2999
+ * Apply time-based distortion to UV coordinates
3000
+ */
2740
3001
  // Extract border-radius from children
2741
3002
  React.useEffect((() => {
2742
3003
  const extractRadius = () => {
@@ -2939,6 +3200,8 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2939
3200
  lerpActiveRef.current = !0;
2940
3201
  const LERP_T = CONSTANTS.LERP_FACTOR, tick = () => {
2941
3202
  if (!lerpActiveRef.current) return;
3203
+ // Add ref validity check to prevent memory leaks
3204
+ if (!glassRef.current || !wrapperRef?.current) return void (lerpActiveRef.current = !1);
2942
3205
  const cur = internalMouseOffsetRef.current, tgt = targetMouseOffsetRef.current, dx = tgt.x - cur.x, dy = tgt.y - cur.y;
2943
3206
  // If we're close enough, snap and park
2944
3207
  if (Math.abs(dx) < .05 && Math.abs(dy) < .05) internalMouseOffsetRef.current = {
@@ -2947,17 +3210,17 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2947
3210
  ...targetGlobalMousePositionRef.current
2948
3211
  }; else {
2949
3212
  internalMouseOffsetRef.current = {
2950
- x: lerp(cur.x, tgt.x, LERP_T),
2951
- y: lerp(cur.y, tgt.y, LERP_T)
3213
+ x: lerp$1(cur.x, tgt.x, LERP_T),
3214
+ y: lerp$1(cur.y, tgt.y, LERP_T)
2952
3215
  };
2953
3216
  const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
2954
3217
  internalGlobalMousePositionRef.current = {
2955
- x: lerp(curG.x, tgtG.x, LERP_T),
2956
- y: lerp(curG.y, tgtG.y, LERP_T)
3218
+ x: lerp$1(curG.x, tgtG.x, LERP_T),
3219
+ y: lerp$1(curG.y, tgtG.y, LERP_T)
2957
3220
  };
2958
3221
  }
2959
3222
  // Imperative style update with the smoothed values
2960
- updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
3223
+ updateAtomixGlassStyles(wrapperRef.current, glassRef.current, {
2961
3224
  mouseOffset: internalMouseOffsetRef.current,
2962
3225
  globalMousePosition: internalGlobalMousePositionRef.current,
2963
3226
  glassSize: glassSize,
@@ -3048,6 +3311,8 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
3048
3311
  // This is now static (refs or props) unless prop changes
3049
3312
  overLightConfig: overLightConfig,
3050
3313
  transformStyle: transformStyle,
3314
+ getShaderTime: getShaderTime,
3315
+ applyTimeBasedDistortion: applyTimeBasedDistortion,
3051
3316
  handleMouseEnter: handleMouseEnter,
3052
3317
  handleMouseLeave: handleMouseLeave,
3053
3318
  handleMouseDown: handleMouseDown,
@@ -3056,6 +3321,800 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
3056
3321
  };
3057
3322
  }
3058
3323
 
3324
+ /**
3325
+ * Default responsive breakpoints configuration
3326
+ *
3327
+ * These breakpoints are optimized for glass effect performance across device classes:
3328
+ * - Mobile: Reduced complexity for 60 FPS target
3329
+ * - Tablet: Balanced quality and performance
3330
+ * - Desktop: Full fidelity effects
3331
+ */ const DEFAULT_BREAKPOINTS = {
3332
+ mobile: {
3333
+ maxWidth: 640,
3334
+ params: {
3335
+ distortionOctaves: 3,
3336
+ displacementScale: .7,
3337
+ blurAmount: .8,
3338
+ animationSpeed: .8,
3339
+ chromaticIntensity: .5
3340
+ }
3341
+ },
3342
+ tablet: {
3343
+ minWidth: 641,
3344
+ maxWidth: 1024,
3345
+ params: {
3346
+ distortionOctaves: 4,
3347
+ displacementScale: .85,
3348
+ blurAmount: .9,
3349
+ animationSpeed: .9,
3350
+ chromaticIntensity: .75
3351
+ }
3352
+ },
3353
+ desktop: {
3354
+ minWidth: 1025,
3355
+ params: {
3356
+ distortionOctaves: 5,
3357
+ displacementScale: 1,
3358
+ blurAmount: 1,
3359
+ animationSpeed: 1,
3360
+ chromaticIntensity: 1
3361
+ }
3362
+ }
3363
+ };
3364
+
3365
+ /**
3366
+ * Device performance tier detection
3367
+ *
3368
+ * Uses Device Memory API and Hardware Concurrency API to classify devices
3369
+ * into performance tiers for automatic quality adjustment.
3370
+ *
3371
+ * @returns Performance tier classification
3372
+ */
3373
+ /**
3374
+ * Responsive Glass Parameters Hook
3375
+ *
3376
+ * Automatically adjusts glass effect parameters based on:
3377
+ * 1. Screen size (mobile/tablet/desktop breakpoints)
3378
+ * 2. Device performance (RAM and CPU detection)
3379
+ * 3. Custom breakpoint configuration
3380
+ *
3381
+ * Features:
3382
+ * - Debounced resize handling
3383
+ * - Performance-based quality adjustment
3384
+ * - Smooth parameter transitions
3385
+ * - Debug mode for development
3386
+ *
3387
+ * @example
3388
+ * ```typescript
3389
+ * const { responsiveParams, currentBreakpoint } = useResponsiveGlass({
3390
+ * baseParams: {
3391
+ * distortionOctaves: 5,
3392
+ * displacementScale: 20,
3393
+ * blurAmount: 10,
3394
+ * },
3395
+ * debug: true,
3396
+ * });
3397
+ * ```
3398
+ *
3399
+ * @param options Hook configuration options
3400
+ * @returns Responsive parameters and metadata
3401
+ */
3402
+ function useResponsiveGlass({baseParams: baseParams, breakpoints: breakpoints = DEFAULT_BREAKPOINTS, enabled: enabled = !0, enablePerformanceAdjustment: enablePerformanceAdjustment = !0, debug: debug = !1}) {
3403
+ const [responsiveParams, setResponsiveParams] = React.useState(baseParams), [currentBreakpoint, setCurrentBreakpoint] = React.useState("desktop"), [performanceTier, setPerformanceTier] = React.useState("high"), [isActive, setIsActive] = React.useState(enabled), baseParamsRef = React.useRef(baseParams), breakpointsRef = React.useRef(breakpoints);
3404
+ // Update refs when props change
3405
+ baseParamsRef.current = baseParams, breakpointsRef.current = breakpoints;
3406
+ /**
3407
+ * Calculate and apply responsive parameters
3408
+ */
3409
+ const calculateParams = React.useCallback((() => {
3410
+ if (!enabled || "undefined" == typeof window) return setIsActive(!1), setResponsiveParams(baseParamsRef.current),
3411
+ void setCurrentBreakpoint("disabled");
3412
+ setIsActive(!0);
3413
+ // Get current screen width
3414
+ const width = window.innerWidth, {name: name, params: breakpointParams} = ((width, breakpoints) => {
3415
+ // Convert breakpoints to array and sort by minWidth descending
3416
+ const sortedBreakpoints = Object.entries(breakpoints).filter((([_, bp]) => void 0 !== bp.minWidth)).sort(((a, b) => (b[1].minWidth || 0) - (a[1].minWidth || 0)));
3417
+ // Find first breakpoint where width >= minWidth
3418
+ for (const [name, bp] of sortedBreakpoints) if (width >= (bp.minWidth || 0)) return {
3419
+ name: name,
3420
+ params: bp.params
3421
+ };
3422
+ // If no minWidth matched, check maxWidth breakpoints
3423
+ const maxWidthBreakpoints = Object.entries(breakpoints).filter((([_, bp]) => void 0 !== bp.maxWidth)).sort(((a, b) => (a[1].maxWidth || 1 / 0) - (b[1].maxWidth || 1 / 0)));
3424
+ for (const [name, bp] of maxWidthBreakpoints) if (width <= (bp.maxWidth || 1 / 0)) return {
3425
+ name: name,
3426
+ params: bp.params
3427
+ };
3428
+ // Fallback to first available breakpoint
3429
+ const entries = Object.entries(breakpoints);
3430
+ if (0 === entries.length)
3431
+ // Ultimate fallback - return sensible defaults
3432
+ return {
3433
+ name: "desktop",
3434
+ params: {
3435
+ distortionOctaves: 5,
3436
+ displacementScale: 1,
3437
+ blurAmount: 1
3438
+ }
3439
+ };
3440
+ const firstEntry = entries[0];
3441
+ if (!firstEntry) return {
3442
+ name: "desktop",
3443
+ params: {
3444
+ distortionOctaves: 5,
3445
+ displacementScale: 1,
3446
+ blurAmount: 1
3447
+ }
3448
+ };
3449
+ const [fallbackName, fallbackBreakpoint] = firstEntry;
3450
+ return {
3451
+ name: fallbackName,
3452
+ params: fallbackBreakpoint.params
3453
+ };
3454
+ })(width, breakpointsRef.current);
3455
+ // Determine current breakpoint
3456
+ setCurrentBreakpoint(name);
3457
+ // Merge base params with breakpoint params
3458
+ let mergedParams = ((baseParams, breakpointParams) => {
3459
+ const result = {
3460
+ ...baseParams
3461
+ }, scaleProperties = [ "displacementScale", "blurAmount", "saturation", "aberrationIntensity", "animationSpeed", "chromaticIntensity" ];
3462
+ // Apply scaling for specific properties
3463
+ for (const prop of scaleProperties) void 0 !== breakpointParams[prop] && void 0 !== baseParams[prop] && (result[prop] = baseParams[prop] * breakpointParams[prop]);
3464
+ // Override properties that should be set directly (not scaled)
3465
+ const overrideProperties = [ "distortionOctaves", "distortionLacunarity", "distortionGain" ];
3466
+ for (const prop of overrideProperties) void 0 !== breakpointParams[prop] && (result[prop] = breakpointParams[prop]);
3467
+ return result;
3468
+ })(baseParamsRef.current, breakpointParams);
3469
+ // Apply performance adjustments if enabled
3470
+ if (enablePerformanceAdjustment) {
3471
+ const tier = (() => {
3472
+ // Check if we're in a browser environment
3473
+ if ("undefined" == typeof window || "undefined" == typeof navigator) return "high"; // Default to high for SSR
3474
+ // Device Memory API (Chrome, Edge, Opera)
3475
+ // Returns RAM in GB: 0.25, 0.5, 1, 2, 4, 8
3476
+ const deviceMemory = navigator.deviceMemory || 4, hardwareConcurrency = navigator.hardwareConcurrency || 4;
3477
+ // Hardware Concurrency API (logical CPU cores)
3478
+ // Low-end: ≤2GB RAM OR ≤2 CPU cores
3479
+ return deviceMemory <= 2 || hardwareConcurrency <= 2 ? "low" :
3480
+ // High-end: ≥4GB RAM AND ≥4 CPU cores
3481
+ deviceMemory >= 4 && hardwareConcurrency >= 4 ? "high" : "medium";
3482
+ })();
3483
+ setPerformanceTier(tier), mergedParams = ((baseParams, performanceTier) => {
3484
+ if ("high" === performanceTier) return baseParams;
3485
+ // No adjustment needed
3486
+ const multiplier = "low" === performanceTier ? .7 : .85;
3487
+ return {
3488
+ ...baseParams,
3489
+ distortionOctaves: Math.max(2, Math.round((baseParams.distortionOctaves || 5) * multiplier)),
3490
+ displacementScale: (baseParams.displacementScale || 1) * multiplier,
3491
+ blurAmount: (baseParams.blurAmount || 1) * multiplier,
3492
+ animationSpeed: (baseParams.animationSpeed || 1) * multiplier,
3493
+ chromaticIntensity: (baseParams.chromaticIntensity || 1) * multiplier
3494
+ };
3495
+ })(mergedParams, tier);
3496
+ }
3497
+ setResponsiveParams(mergedParams);
3498
+ }), [ enabled, enablePerformanceAdjustment, debug ]), debouncedCalculate = (func => {
3499
+ const timeoutRef = React.useRef(null);
3500
+ return React.useEffect((() => () => {
3501
+ timeoutRef.current && clearTimeout(timeoutRef.current);
3502
+ }), []), React.useCallback(((...args) => {
3503
+ timeoutRef.current && clearTimeout(timeoutRef.current), timeoutRef.current = setTimeout((() => {
3504
+ func(...args);
3505
+ }), 200);
3506
+ }), [ func, 200 ]);
3507
+ })(calculateParams);
3508
+ /**
3509
+ * Debounced parameter calculation for resize events
3510
+ */
3511
+ /**
3512
+ * Handle window resize
3513
+ */
3514
+ return React.useEffect((() => {
3515
+ if (enabled)
3516
+ // Cleanup
3517
+ // Initial calculation
3518
+ return calculateParams(),
3519
+ // Listen for resize events
3520
+ window.addEventListener("resize", debouncedCalculate), () => {
3521
+ window.removeEventListener("resize", debouncedCalculate);
3522
+ };
3523
+ // eslint-disable-next-line react-hooks/exhaustive-deps
3524
+ }), [ enabled ]), {
3525
+ responsiveParams: responsiveParams,
3526
+ currentBreakpoint: currentBreakpoint,
3527
+ performanceTier: performanceTier,
3528
+ isActive: isActive,
3529
+ recalculate: React.useCallback((() => {
3530
+ calculateParams();
3531
+ }), [ calculateParams ])
3532
+ };
3533
+ }
3534
+
3535
+ /**
3536
+ * Utility function to get default breakpoints
3537
+ * Useful for documentation and debugging
3538
+ */ function getDefaultBreakpoints() {
3539
+ return {
3540
+ ...DEFAULT_BREAKPOINTS
3541
+ };
3542
+ }
3543
+
3544
+ /**
3545
+ * Utility function to create custom breakpoints
3546
+ *
3547
+ * @param customBreakpoints Partial breakpoint overrides
3548
+ * @returns Complete breakpoint configuration
3549
+ */ function createBreakpoints$1(customBreakpoints) {
3550
+ return {
3551
+ ...DEFAULT_BREAKPOINTS,
3552
+ ...customBreakpoints
3553
+ };
3554
+ }
3555
+
3556
+ /**
3557
+ * Get GPU memory info if available (Chrome DevTools only)
3558
+ */
3559
+ /**
3560
+ * Performance Monitor Hook
3561
+ *
3562
+ * Real-time performance tracking with automatic quality scaling.
3563
+ * Monitors FPS, frame time, and GPU memory to optimize glass effects.
3564
+ *
3565
+ * Features:
3566
+ * - Real-time FPS measurement
3567
+ * - Frame timing analysis
3568
+ * - Automatic quality scaling
3569
+ * - Debug overlay option
3570
+ * - Manual override capability
3571
+ *
3572
+ * @example
3573
+ * ```typescript
3574
+ * const { metrics, recommendedQuality, setQualityLevel } = usePerformanceMonitor({
3575
+ * targetFps: 60,
3576
+ * minFps: 45,
3577
+ * debug: true,
3578
+ * });
3579
+ * ```
3580
+ *
3581
+ * @param config Monitor configuration
3582
+ * @returns Performance metrics and controls
3583
+ */
3584
+ function usePerformanceMonitor(config = {}) {
3585
+ const {enabled: enabled = !0, targetFps: targetFps = 60, minFps: minFps = 45, scaleUpThreshold: scaleUpThreshold = 58, lowFpsFrames: lowFpsFrames = 3, highFpsFrames: highFpsFrames = 10, debug: debug = !1, showOverlay: showOverlay = !1} = config, [metrics, setMetrics] = React.useState({
3586
+ fps: 0,
3587
+ frameTime: 0,
3588
+ gpuMemory: null,
3589
+ qualityLevel: "medium",
3590
+ timestamp: 0,
3591
+ isAutoScaling: !0,
3592
+ lowFpsCount: 0
3593
+ }), [manualOverride, setManualOverride] = React.useState(!1), [isEnabled, setIsEnabled] = React.useState(enabled), frameCountRef = React.useRef(0), lastFpsUpdateRef = React.useRef(0), lastFrameTimeRef = React.useRef(0), animationFrameRef = React.useRef(null), lowFpsCountRef = React.useRef(0), highFpsCountRef = React.useRef(0), qualityLevelRef = React.useRef("medium"), updateMetrics = React.useCallback((newMetrics => {
3594
+ setMetrics((prev => ({
3595
+ ...prev,
3596
+ ...newMetrics,
3597
+ timestamp: performance.now()
3598
+ })));
3599
+ }), []), applyAutoScaling = React.useCallback((currentFps => {
3600
+ if (manualOverride) return;
3601
+ const currentQuality = qualityLevelRef.current;
3602
+ // Check for low FPS
3603
+ if (currentFps < minFps) lowFpsCountRef.current++, highFpsCountRef.current = 0,
3604
+ // Scale down after N consecutive low-FPS frames
3605
+ lowFpsCountRef.current >= lowFpsFrames && "low" !== currentQuality && (qualityLevelRef.current = "low",
3606
+ updateMetrics({
3607
+ qualityLevel: "low",
3608
+ lowFpsCount: lowFpsCountRef.current
3609
+ })); else if (currentFps >= scaleUpThreshold) {
3610
+ // Scale up after N consecutive high-FPS frames
3611
+ if (highFpsCountRef.current++, lowFpsCountRef.current = 0, highFpsCountRef.current >= highFpsFrames) {
3612
+ const newQuality = "low" === currentQuality ? "medium" : "high";
3613
+ qualityLevelRef.current = newQuality, updateMetrics({
3614
+ qualityLevel: newQuality,
3615
+ lowFpsCount: 0
3616
+ }), highFpsCountRef.current = 0;
3617
+ }
3618
+ } else
3619
+ // FPS in normal range, reset counters
3620
+ lowFpsCountRef.current = 0, highFpsCountRef.current = 0;
3621
+ }), [ manualOverride, minFps, scaleUpThreshold, lowFpsFrames, highFpsFrames, debug, updateMetrics ]), measureFrame = React.useCallback((currentTime => {
3622
+ if (!isEnabled) return;
3623
+ frameCountRef.current++;
3624
+ // Calculate frame time
3625
+ const frameTime = currentTime - lastFrameTimeRef.current;
3626
+ // Update FPS every 100ms for responsiveness
3627
+ if (lastFrameTimeRef.current = currentTime, currentTime - lastFpsUpdateRef.current >= 100) {
3628
+ const elapsed = currentTime - lastFpsUpdateRef.current, fps = Math.round(1e3 * frameCountRef.current / elapsed);
3629
+ // Apply auto-scaling
3630
+ applyAutoScaling(fps), updateMetrics({
3631
+ fps: fps,
3632
+ frameTime: frameTime,
3633
+ qualityLevel: qualityLevelRef.current,
3634
+ lowFpsCount: lowFpsCountRef.current
3635
+ }),
3636
+ // Reset for next measurement period
3637
+ frameCountRef.current = 0, lastFpsUpdateRef.current = currentTime;
3638
+ }
3639
+ // Continue measurement loop
3640
+ animationFrameRef.current = requestAnimationFrame(measureFrame);
3641
+ }), [ isEnabled, applyAutoScaling, updateMetrics ]);
3642
+ /**
3643
+ * Initialize GPU memory tracking
3644
+ */
3645
+ React.useEffect((() => {
3646
+ if (!isEnabled || "undefined" == typeof window) return;
3647
+ let mounted = !0;
3648
+ return (async () => {
3649
+ const memory = await new Promise((resolve => {
3650
+ // Check for WebGL debug renderer info
3651
+ if ("undefined" != typeof window && "undefined" != typeof document) try {
3652
+ const canvas = document.createElement("canvas"), gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
3653
+ if (gl) {
3654
+ const debugInfo = gl.getExtension("WEBGL_debug_renderer_info");
3655
+ if (debugInfo) {
3656
+ var _context, _context2, _context3;
3657
+ // Note: Actual memory info is not directly available via WebGL
3658
+ // We estimate based on renderer
3659
+ const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
3660
+ // Rough estimation based on renderer type
3661
+ return void ((null == (_context = renderer) ? void 0 : Function.call.bind(_includesInstanceProperty(_context), _context))?.("Integrated") ? resolve(256) : (null == (_context2 = renderer) ? void 0 : Function.call.bind(_includesInstanceProperty(_context2), _context2))?.("AMD") || (null == (_context3 = renderer) ? void 0 : Function.call.bind(_includesInstanceProperty(_context3), _context3))?.("NVIDIA") ? resolve(512) : resolve(null));
3662
+ }
3663
+ }
3664
+ } catch (e) {
3665
+ // WebGL not available or error occurred
3666
+ }
3667
+ resolve(null);
3668
+ }));
3669
+ mounted && updateMetrics({
3670
+ gpuMemory: memory
3671
+ });
3672
+ })(), () => {
3673
+ mounted = !1;
3674
+ };
3675
+ }), [ isEnabled, updateMetrics ]),
3676
+ /**
3677
+ * Start/stop monitoring based on enabled state
3678
+ */
3679
+ React.useEffect((() => {
3680
+ if (isEnabled)
3681
+ // Cleanup
3682
+ // Initialize
3683
+ return lastFpsUpdateRef.current = performance.now(), lastFrameTimeRef.current = performance.now(),
3684
+ animationFrameRef.current = requestAnimationFrame(measureFrame), () => {
3685
+ null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
3686
+ animationFrameRef.current = null);
3687
+ };
3688
+ // eslint-disable-next-line react-hooks/exhaustive-deps
3689
+ null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
3690
+ animationFrameRef.current = null);
3691
+ }), [ isEnabled ]);
3692
+ // measureFrame is stable via useCallback, avoid re-creating RAF loop
3693
+ /**
3694
+ * Manually set quality level (disables auto-scaling)
3695
+ */
3696
+ const setQualityLevel = React.useCallback((level => {
3697
+ setManualOverride(!0), qualityLevelRef.current = level, updateMetrics({
3698
+ qualityLevel: level,
3699
+ isAutoScaling: !1
3700
+ });
3701
+ }), [ updateMetrics, debug ]), resetAutoScaling = React.useCallback((() => {
3702
+ setManualOverride(!1), lowFpsCountRef.current = 0, highFpsCountRef.current = 0,
3703
+ updateMetrics({
3704
+ isAutoScaling: !0,
3705
+ lowFpsCount: 0
3706
+ });
3707
+ }), [ updateMetrics, debug ]), toggleMonitoring = React.useCallback((() => {
3708
+ setIsEnabled((prev => !prev));
3709
+ }), []);
3710
+ /**
3711
+ * Reset to auto-scaling mode
3712
+ */ var fps, currentQuality;
3713
+ return {
3714
+ metrics: metrics,
3715
+ recommendedQuality: (fps = metrics.fps, currentQuality = metrics.qualityLevel, fps >= 58 ? "high" : fps >= 45 ? "high" === currentQuality ? "high" : "medium" : "low"),
3716
+ isUnderperforming: metrics.fps < minFps,
3717
+ setQualityLevel: setQualityLevel,
3718
+ resetAutoScaling: resetAutoScaling,
3719
+ toggleMonitoring: toggleMonitoring
3720
+ };
3721
+ }
3722
+
3723
+ /**
3724
+ * Debug Overlay Component (Optional)
3725
+ *
3726
+ * Shows real-time performance metrics on screen.
3727
+ * Only rendered when showOverlay is enabled.
3728
+ */ function PerformanceOverlay({metrics: metrics}) {
3729
+ return null;
3730
+ // Performance overlay removed - will be implemented as separate component
3731
+ }
3732
+
3733
+ /**
3734
+ * Utility to get quality multipliers for glass parameters
3735
+ */ function getQualityMultipliers(quality) {
3736
+ switch (quality) {
3737
+ case "low":
3738
+ return {
3739
+ distortionOctaves: 2,
3740
+ displacementScale: .6,
3741
+ blurAmount: .7,
3742
+ animationSpeed: .8,
3743
+ chromaticIntensity: .5
3744
+ };
3745
+
3746
+ case "medium":
3747
+ return {
3748
+ distortionOctaves: 4,
3749
+ displacementScale: .85,
3750
+ blurAmount: .9,
3751
+ animationSpeed: .95,
3752
+ chromaticIntensity: .75
3753
+ };
3754
+
3755
+ case "high":
3756
+ return {
3757
+ distortionOctaves: 5,
3758
+ displacementScale: 1,
3759
+ blurAmount: 1,
3760
+ animationSpeed: 1,
3761
+ chromaticIntensity: 1
3762
+ };
3763
+ }
3764
+ }
3765
+
3766
+ /**
3767
+ * PerformanceDashboard - Real-time performance monitoring overlay
3768
+ *
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,
3830
+ children: [ jsxRuntime.jsxs("div", {
3831
+ style: headerStyle,
3832
+ children: [ jsxRuntime.jsx("span", {
3833
+ style: titleStyle,
3834
+ children: "Performance Monitor"
3835
+ }), onClose && jsxRuntime.jsx("button", {
3836
+ style: closeButtonStyle,
3837
+ onClick: onClose,
3838
+ "aria-label": "Close performance dashboard",
3839
+ children: "×"
3840
+ }) ]
3841
+ }), jsxRuntime.jsxs("div", {
3842
+ style: metricRowStyle,
3843
+ children: [ jsxRuntime.jsx("span", {
3844
+ style: labelStyle,
3845
+ children: "FPS"
3846
+ }), jsxRuntime.jsx("span", {
3847
+ style: {
3848
+ ...valueStyle,
3849
+ color: getFpsColor(metrics.fps)
3850
+ },
3851
+ children: Math.round(metrics.fps)
3852
+ }) ]
3853
+ }), jsxRuntime.jsxs("div", {
3854
+ style: metricRowStyle,
3855
+ children: [ jsxRuntime.jsx("span", {
3856
+ style: labelStyle,
3857
+ children: "Frame Time"
3858
+ }), jsxRuntime.jsxs("span", {
3859
+ style: valueStyle,
3860
+ children: [ metrics.frameTime.toFixed(2), "ms" ]
3861
+ }) ]
3862
+ }), jsxRuntime.jsxs("div", {
3863
+ style: metricRowStyle,
3864
+ children: [ jsxRuntime.jsx("span", {
3865
+ style: labelStyle,
3866
+ children: "Quality"
3867
+ }), jsxRuntime.jsx("span", {
3868
+ 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"
3887
+ },
3888
+ children: metrics.qualityLevel
3889
+ }) ]
3890
+ }), metrics.gpuMemory && jsxRuntime.jsxs("div", {
3891
+ style: metricRowStyle,
3892
+ children: [ jsxRuntime.jsx("span", {
3893
+ style: labelStyle,
3894
+ children: "GPU Memory"
3895
+ }), jsxRuntime.jsxs("span", {
3896
+ style: valueStyle,
3897
+ children: [ "~", Math.round(metrics.gpuMemory / 1024), "MB" ]
3898
+ }) ]
3899
+ }), metrics.isAutoScaling && jsxRuntime.jsx("div", {
3900
+ 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"
3907
+ },
3908
+ children: "Auto-scaling active"
3909
+ }), 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
+ },
3918
+ children: [ jsxRuntime.jsx("div", {
3919
+ style: {
3920
+ width: "8px",
3921
+ height: "8px",
3922
+ borderRadius: "50%",
3923
+ backgroundColor: getFpsColor(metrics.fps),
3924
+ animation: metrics.fps < 45 ? "pulse 1s infinite" : "none"
3925
+ }
3926
+ }), jsxRuntime.jsx("span", {
3927
+ style: {
3928
+ fontSize: "10px",
3929
+ color: metrics.fps >= 58 ? "#4ade80" : metrics.fps >= 45 ? "#fbbf24" : "#ef4444"
3930
+ },
3931
+ children: metrics.fps >= 58 ? "Optimal" : metrics.fps >= 45 ? "Warning" : "Critical"
3932
+ }) ]
3933
+ }) ]
3934
+ }) : null;
3935
+ };
3936
+
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
+ }
3943
+
3944
+ /**
3945
+ * Mobile optimization presets
3946
+ *
3947
+ * These presets adjust glass effect parameters based on device performance tier
3948
+ * to ensure smooth animations and responsive interactions.
3949
+ */
3950
+ /**
3951
+ * Performance preset - Maximum FPS, reduced quality
3952
+ * Best for low-end devices or when battery saving is priority
3953
+ */ const PERFORMANCE_PRESET = {
3954
+ distortionOctaves: 2,
3955
+ // Minimal FBM layers
3956
+ displacementScale: 50,
3957
+ // Subtle displacement
3958
+ blurAmount: 5,
3959
+ // Light blur
3960
+ saturation: 80,
3961
+ // Reduced saturation
3962
+ aberrationIntensity: .3,
3963
+ // Minimal chromatic aberration
3964
+ animationSpeed: .8,
3965
+ // Slightly slower for performance
3966
+ chromaticIntensity: .3,
3967
+ // Low chromatic effect
3968
+ distortionLacunarity: 1.5,
3969
+ // Simpler noise pattern
3970
+ distortionGain: .3
3971
+ }, BALANCED_PRESET = {
3972
+ distortionOctaves: 3,
3973
+ // Moderate FBM layers
3974
+ displacementScale: 75,
3975
+ // Medium displacement
3976
+ blurAmount: 8,
3977
+ // Moderate blur
3978
+ saturation: 90,
3979
+ // Near-full saturation
3980
+ aberrationIntensity: .5,
3981
+ // Moderate chromatic aberration
3982
+ animationSpeed: 1,
3983
+ // Normal speed
3984
+ chromaticIntensity: .5,
3985
+ // Moderate chromatic effect
3986
+ distortionLacunarity: 2,
3987
+ // Standard noise pattern
3988
+ distortionGain: .4
3989
+ }, QUALITY_PRESET = {
3990
+ distortionOctaves: 4,
3991
+ // More FBM layers for detail
3992
+ displacementScale: 100,
3993
+ // Stronger displacement
3994
+ blurAmount: 12,
3995
+ // Smoother blur
3996
+ saturation: 100,
3997
+ // Full saturation
3998
+ aberrationIntensity: .7,
3999
+ // Pronounced chromatic aberration
4000
+ animationSpeed: 1.2,
4001
+ // Slightly faster for drama
4002
+ chromaticIntensity: .7,
4003
+ // Strong chromatic effect
4004
+ distortionLacunarity: 2.2,
4005
+ // Richer noise pattern
4006
+ distortionGain: .5
4007
+ };
4008
+
4009
+ /**
4010
+ * Balanced preset - Good quality with reasonable performance
4011
+ * Default preset for most mobile devices
4012
+ */
4013
+ /**
4014
+ * Get preset by name
4015
+ */
4016
+ function getDevicePreset(presetName) {
4017
+ switch (presetName) {
4018
+ case "performance":
4019
+ return PERFORMANCE_PRESET;
4020
+
4021
+ case "balanced":
4022
+ default:
4023
+ return BALANCED_PRESET;
4024
+
4025
+ case "quality":
4026
+ return QUALITY_PRESET;
4027
+ }
4028
+ }
4029
+
4030
+ /**
4031
+ * Mobile-optimized responsive breakpoints
4032
+ * Automatically applies appropriate presets based on viewport size
4033
+ */ const MOBILE_OPTIMIZED_BREAKPOINTS = {
4034
+ /** Desktop - Full quality */
4035
+ desktop: {
4036
+ minWidth: 1024,
4037
+ params: {
4038
+ distortionOctaves: 6,
4039
+ displacementScale: 150,
4040
+ blurAmount: 15,
4041
+ saturation: 100,
4042
+ aberrationIntensity: 1,
4043
+ animationSpeed: 1,
4044
+ chromaticIntensity: 1,
4045
+ distortionLacunarity: 2.5,
4046
+ distortionGain: .6
4047
+ }
4048
+ },
4049
+ /** Laptop - High quality */
4050
+ laptop: {
4051
+ minWidth: 768,
4052
+ params: {
4053
+ ...QUALITY_PRESET,
4054
+ distortionOctaves: 5,
4055
+ displacementScale: 120
4056
+ }
4057
+ },
4058
+ /** Tablet - Balanced quality */
4059
+ tablet: {
4060
+ minWidth: 640,
4061
+ params: {
4062
+ ...BALANCED_PRESET,
4063
+ distortionOctaves: 4,
4064
+ displacementScale: 90
4065
+ }
4066
+ },
4067
+ /** Mobile - Performance optimized */
4068
+ mobile: {
4069
+ maxWidth: 639,
4070
+ params: {
4071
+ ...PERFORMANCE_PRESET,
4072
+ distortionOctaves: 3,
4073
+ displacementScale: 75,
4074
+ blurAmount: 6
4075
+ }
4076
+ },
4077
+ /** Small mobile - Maximum performance */
4078
+ mobileSmall: {
4079
+ maxWidth: 375,
4080
+ params: {
4081
+ ...PERFORMANCE_PRESET,
4082
+ distortionOctaves: 2,
4083
+ displacementScale: 50,
4084
+ blurAmount: 4,
4085
+ saturation: 70
4086
+ }
4087
+ }
4088
+ };
4089
+
4090
+ /**
4091
+ * Get mobile-optimized parameters for current viewport
4092
+ * Can be used standalone or with useResponsiveGlass hook
4093
+ */ function getMobileOptimizedParams(viewportWidth) {
4094
+ return viewportWidth >= 1024 ? MOBILE_OPTIMIZED_BREAKPOINTS.desktop?.params || BALANCED_PRESET : viewportWidth >= 768 ? MOBILE_OPTIMIZED_BREAKPOINTS.laptop?.params || BALANCED_PRESET : viewportWidth >= 640 ? MOBILE_OPTIMIZED_BREAKPOINTS.tablet?.params || BALANCED_PRESET : viewportWidth >= 375 ? MOBILE_OPTIMIZED_BREAKPOINTS.mobile?.params || PERFORMANCE_PRESET : MOBILE_OPTIMIZED_BREAKPOINTS.mobileSmall?.params || PERFORMANCE_PRESET;
4095
+ }
4096
+
4097
+ /**
4098
+ * Device detection utilities
4099
+ */ const DeviceDetector = {
4100
+ /** Check if device is mobile */
4101
+ isMobile: () => "undefined" != typeof window && /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
4102
+ /** Check if device is tablet */
4103
+ isTablet() {
4104
+ if ("undefined" == typeof window) return !1;
4105
+ const width = window.innerWidth;
4106
+ return width >= 640 && width < 1024 && this.isMobile();
4107
+ },
4108
+ /** Get recommended preset based on device type */
4109
+ getRecommendedPreset() {
4110
+ return this.isMobile() ? this.isTablet() ? "balanced" : "performance" : "quality";
4111
+ },
4112
+ /** Get device pixel ratio */
4113
+ getPixelRatio: () => "undefined" == typeof window ? 1 : window.devicePixelRatio || 1,
4114
+ /** Check if device has touch support */
4115
+ hasTouchSupport: () => "undefined" != typeof window && ("ontouchstart" in window || navigator.maxTouchPoints > 0)
4116
+ };
4117
+
3059
4118
  /**
3060
4119
  * AtomixGlass - A high-performance glass morphism component with liquid distortion effects
3061
4120
  *
@@ -3070,6 +4129,8 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
3070
4129
  * - Focus ring support for keyboard navigation
3071
4130
  * - Responsive breakpoints for mobile optimization
3072
4131
  * - Enhanced ARIA attributes for screen readers
4132
+ * - Time-based animation system with FBM distortion
4133
+ * - Device preset optimization for performance/quality balance
3073
4134
  *
3074
4135
  * Design System Compliance:
3075
4136
  * - Uses design tokens for opacity, spacing, and colors
@@ -3126,8 +4187,14 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
3126
4187
  * <AtomixGlass overLight="auto" debugOverLight={true}>
3127
4188
  * <div>Content with debug logging enabled</div>
3128
4189
  * </AtomixGlass>
3129
- */ 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, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, height: height, width: width, ...rest}) {
3130
- 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, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
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({
3131
4198
  glassRef: glassRef,
3132
4199
  contentRef: contentRef,
3133
4200
  borderRadius: borderRadius,
@@ -3140,7 +4207,6 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
3140
4207
  withoutEffects: withoutEffects,
3141
4208
  elasticity: elasticity,
3142
4209
  onClick: onClick,
3143
- debugBorderRadius: debugBorderRadius,
3144
4210
  debugOverLight: debugOverLight,
3145
4211
  debugPerformance: debugPerformance,
3146
4212
  children: children,
@@ -3149,8 +4215,48 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
3149
4215
  withLiquidBlur: withLiquidBlur,
3150
4216
  padding: padding,
3151
4217
  style: style,
3152
- isFixedOrSticky: isFixedOrSticky
3153
- }), isOverLight = React.useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, rootLayoutStyle = React.useMemo((() => {
4218
+ isFixedOrSticky: isFixedOrSticky,
4219
+ // Phase 1: Animation System props
4220
+ withTimeAnimation: withTimeAnimation,
4221
+ animationSpeed: animationSpeed,
4222
+ withMultiLayerDistortion: withMultiLayerDistortion,
4223
+ distortionOctaves: distortionOctaves,
4224
+ distortionLacunarity: distortionLacunarity,
4225
+ distortionGain: distortionGain,
4226
+ distortionQuality: distortionQuality
4227
+ });
4228
+ // Re-calculate only when devicePreset changes
4229
+ // Responsive breakpoint system - automatically adjusts parameters based on viewport
4230
+ useResponsiveGlass({
4231
+ baseParams: {
4232
+ ...React.useMemo((() => getDevicePreset(devicePreset)), [ devicePreset ]),
4233
+ distortionOctaves: Math.round((displacementScale || ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE) / 25),
4234
+ displacementScale: displacementScale || ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE,
4235
+ blurAmount: blurAmount || ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT,
4236
+ saturation: saturation || ATOMIX_GLASS.DEFAULTS.SATURATION,
4237
+ aberrationIntensity: aberrationIntensity || ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY,
4238
+ animationSpeed: 1,
4239
+ chromaticIntensity: aberrationIntensity || ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY
4240
+ },
4241
+ breakpoints: MOBILE_OPTIMIZED_BREAKPOINTS,
4242
+ enabled: !disableResponsiveBreakpoints && "undefined" != typeof window,
4243
+ // Enable unless disabled
4244
+ debug: !1
4245
+ });
4246
+ // 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
4250
+ debug: !1,
4251
+ showOverlay: !1
4252
+ });
4253
+ // Auto-start performance monitoring if enabled (only in development)
4254
+ React__default.default.useEffect((() => {
4255
+ "development" === process.env.NODE_ENV && window?.enablePerformanceMonitoring && toggleMonitoring();
4256
+ // eslint-disable-next-line react-hooks/exhaustive-deps
4257
+ }), []);
4258
+ // Only run once on mount
4259
+ const isOverLight = React.useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, rootLayoutStyle = React.useMemo((() => {
3154
4260
  if (!isFixedOrSticky) return {};
3155
4261
  const {position: p, top: t, left: l, right: r, bottom: b} = restStyle;
3156
4262
  return {
@@ -3336,6 +4442,15 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
3336
4442
  effectiveReducedMotion: effectiveReducedMotion,
3337
4443
  shaderVariant: shaderVariant,
3338
4444
  withLiquidBlur: withLiquidBlur,
4445
+ // Phase 1: Animation System props
4446
+ shaderTime: getShaderTime(),
4447
+ withTimeAnimation: withTimeAnimation,
4448
+ animationSpeed: animationSpeed,
4449
+ withMultiLayerDistortion: withMultiLayerDistortion,
4450
+ distortionOctaves: distortionOctaves,
4451
+ distortionLacunarity: distortionLacunarity,
4452
+ distortionGain: distortionGain,
4453
+ distortionQuality: distortionQuality,
3339
4454
  children: children
3340
4455
  }), Boolean(onClick) && jsxRuntime.jsxs(jsxRuntime.Fragment, {
3341
4456
  children: [ jsxRuntime.jsx("div", {
@@ -3359,6 +4474,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
3359
4474
  }), jsxRuntime.jsx("span", {
3360
4475
  className: ATOMIX_GLASS.BORDER_2_CLASS
3361
4476
  }) ]
4477
+ }), debugPerformance && performanceMetrics && jsxRuntime.jsx(PerformanceDashboard, {
4478
+ metrics: performanceMetrics,
4479
+ isVisible: !0,
4480
+ onClose: () => {}
3362
4481
  }) ]
3363
4482
  });
3364
4483
  }
@@ -3425,16 +4544,14 @@ const AccordionBody = React.forwardRef((({children: children, className: classN
3425
4544
 
3426
4545
  AccordionBody.displayName = "AccordionBody";
3427
4546
 
3428
- const AccordionImpl = React.memo((({title: title, children: children, defaultOpen: defaultOpen = !1, isOpen: controlledOpen, onOpenChange: onOpenChange, onOpen: onOpen, onClose: onClose, disabled: disabled = !1, iconPosition: iconPosition = "right", icon: icon, className: className = "", style: style, glass: glass}) => {
4547
+ const AccordionImpl = React.memo((({title: title, children: children, defaultOpen: defaultOpen = !1, isOpen: controlledOpen, onOpenChange: onOpenChange, disabled: disabled = !1, iconPosition: iconPosition = "right", icon: icon, className: className = "", style: style, glass: glass}) => {
3429
4548
  // Generate unique IDs for accessibility
3430
4549
  const instanceId = React.useId(), buttonId = `accordion-header-${instanceId}`, panelId = `accordion-panel-${instanceId}`, {state: state, toggle: toggle, updatePanelHeight: updatePanelHeight, panelRef: panelRef, contentRef: contentRef, generateClassNames: generateClassNames, generateHeaderClassNames: generateHeaderClassNames} = useAccordion({
3431
4550
  defaultOpen: defaultOpen,
3432
4551
  disabled: disabled,
3433
4552
  iconPosition: iconPosition,
3434
4553
  isOpen: controlledOpen,
3435
- onOpenChange: onOpenChange,
3436
- onOpen: onOpen,
3437
- onClose: onClose
4554
+ onOpenChange: onOpenChange
3438
4555
  }), headerClassNames = generateHeaderClassNames(), panelClassNames = ACCORDION.SELECTORS.PANEL.replace(".", ""), hasCompoundComponents = React__default.default.Children.toArray(children).some((child => {
3439
4556
  var _context;
3440
4557
 
@@ -3817,7 +4934,9 @@ var shaderUtils = Object.freeze({
3817
4934
  return this.canvasDPI;
3818
4935
  }
3819
4936
  },
3820
- fragmentShaders: fragmentShaders
4937
+ createFBMEngine: createFBMEngine,
4938
+ fragmentShaders: fragmentShaders,
4939
+ liquidGlassWithTime: liquidGlassWithTime
3821
4940
  });
3822
4941
 
3823
4942
  // Map string sizes to pixel values
@@ -3852,7 +4971,7 @@ const sizeMap = {
3852
4971
  * Icon component that displays a Phosphor icon
3853
4972
  */ Icon.displayName = "Icon";
3854
4973
 
3855
- const Avatar = React.memo((({src: src, alt: alt = "Avatar", initials: initials, icon: icon, size: size = "md", circle: circle = !1, className: className = "", disabled: disabled = !1, onClick: onClick, style: style, glass: glass}) => {
4974
+ const Avatar = React.memo((({src: src, alt: alt = "User avatar", initials: initials, icon: icon, size: size = "md", circle: circle = !1, className: className = "", disabled: disabled = !1, onClick: onClick, style: style, glass: glass}) => {
3856
4975
  const [imageError, setImageError] = React.useState(!1), avatarClasses = [ AVATAR.CLASSES.BASE, "md" !== size && `c-avatar--${size}`, circle && AVATAR.CLASSES.CIRCLE, disabled && "is-disabled", className ].filter(Boolean).join(" ");
3857
4976
  return jsxRuntime.jsx("div", {
3858
4977
  className: avatarClasses,
@@ -4325,7 +5444,7 @@ class ThemeNaming {
4325
5444
  ThemeNaming.prefix = "atomix";
4326
5445
 
4327
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) => {
4328
- const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement = iconName ? jsxRuntime.jsx(Icon, {
5447
+ const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href), iconElement = iconName ? jsxRuntime.jsx(Icon, {
4329
5448
  name: iconName,
4330
5449
  size: iconSize
4331
5450
  }) : icon, buttonClass = [ BUTTON.BASE_CLASS, ThemeNaming.variantClass(THEME_NAMING.BUTTON_PREFIX, variant), "md" !== size ? ThemeNaming.sizeClass(THEME_NAMING.BUTTON_PREFIX, size) : "", iconOnly ? ThemeNaming.stateClass(THEME_NAMING.BUTTON_PREFIX, THEME_NAMING.ICON_ELEMENT) : "", rounded ? ThemeNaming.stateClass(THEME_NAMING.BUTTON_PREFIX, "rounded") : "", isDisabled ? ThemeNaming.stateClass(THEME_NAMING.BUTTON_PREFIX, "disabled") : "", glass ? ThemeNaming.stateClass(THEME_NAMING.BUTTON_PREFIX, "glass") : "", loading ? BUTTON.CLASSES.LOADING : "", fullWidth ? BUTTON.CLASSES.FULL_WIDTH : "", block ? BUTTON.CLASSES.BLOCK : "", active ? BUTTON.CLASSES.ACTIVE : "", selected ? BUTTON.CLASSES.SELECTED : "", className ].filter(Boolean).join(" "), handleClickEvent = React.useCallback((event => {
@@ -4381,8 +5500,8 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
4381
5500
  ...buttonProps,
4382
5501
  ref: ref,
4383
5502
  // linkComponent usually forwards ref to anchor
4384
- href: href,
4385
- to: href,
5503
+ href: isDisabled ? void 0 : href,
5504
+ to: isDisabled ? void 0 : href,
4386
5505
  target: target,
4387
5506
  rel: "_blank" === target ? "noopener noreferrer" : void 0
4388
5507
  };
@@ -4395,7 +5514,7 @@ const Button = React__default.default.memo( React.forwardRef((({label: label, c
4395
5514
  content = jsxRuntime.jsx("a", {
4396
5515
  ...buttonProps,
4397
5516
  ref: ref,
4398
- href: href,
5517
+ href: isDisabled ? void 0 : href,
4399
5518
  target: target,
4400
5519
  rel: "_blank" === target ? "noopener noreferrer" : void 0,
4401
5520
  children: buttonContent
@@ -4674,7 +5793,7 @@ row: row = !1, flat: flat = !1,
4674
5793
  // States
4675
5794
  active: active = !1, disabled: disabled = !1, loading: loading = !1, selected: selected = !1, interactive: interactive = !1,
4676
5795
  // Content
4677
- header: header, image: image, imageAlt: imageAlt = "", title: title, text: text, actions: actions, icon: icon, footer: footer, children: children,
5796
+ header: header, image: image, imageAlt: imageAlt = "Card image", title: title, text: text, actions: actions, icon: icon, footer: footer, children: children,
4678
5797
  // Interaction
4679
5798
  onClick: onClick, onHover: onHover, onFocus: onFocus, href: href, target: target,
4680
5799
  // Custom Link
@@ -4877,50 +5996,50 @@ Card.Header = CardHeader, Card.Body = CardBody, Card.Footer = CardFooter;
4877
5996
  * @param options - Configuration options for the card
4878
5997
  * @returns Card state and handlers
4879
5998
  */
4880
- const useCard = (options = {}) => {
4881
- const {elevationEffect: elevationEffect = !1, elevationClass: elevationClass = CARD.CLASSES.ACTIVE, flipEffect: flipEffect = !1, flipTrigger: flipTrigger = "click", focusEffect: focusEffect = !1, clickable: clickable = !1, onClick: onClick} = options, cardRef = React.useRef(null), frontRef = React.useRef(null), backRef = React.useRef(null), [isFlipped, setIsFlipped] = React.useState(!1), [isElevated, setIsElevated] = React.useState(!1), [isFocused, setIsFocused] = React.useState(!1), [isHovered, setIsHovered] = React.useState(!1), handleClick = React.useCallback((event => {
4882
- flipEffect && "click" === flipTrigger && setIsFlipped((prev => !prev)), onClick && onClick(event);
4883
- }), [ flipEffect, flipTrigger, onClick ]), handleKeyDown = React.useCallback((event => {
4884
- "Enter" !== event.key && " " !== event.key || (event.preventDefault(), flipEffect && "click" === flipTrigger && setIsFlipped((prev => !prev)),
4885
- onClick && onClick(event));
4886
- }), [ flipEffect, flipTrigger, onClick ]), handleMouseEnter = React.useCallback((() => {
4887
- setIsHovered(!0), elevationEffect && setIsElevated(!0), flipEffect && "hover" === flipTrigger && setIsFlipped(!0);
4888
- }), [ elevationEffect, flipEffect, flipTrigger ]), handleMouseLeave = React.useCallback((() => {
4889
- setIsHovered(!1), elevationEffect && setIsElevated(!1), flipEffect && "hover" === flipTrigger && setIsFlipped(!1);
4890
- }), [ elevationEffect, flipEffect, flipTrigger ]), handleFocus = React.useCallback((() => {
4891
- setIsFocused(!0);
4892
- }), []), handleBlur = React.useCallback((() => {
4893
- setIsFocused(!1);
4894
- }), []), getCardProps = React.useCallback((() => ({
4895
- className: [ CARD.CLASSES.BASE, isElevated ? elevationClass : "", isFlipped ? CARD.CLASSES.FLIPPED : "", isFocused && focusEffect ? CARD.CLASSES.FOCUSED : "", clickable ? CARD.CLASSES.CLICKABLE : "" ].filter(Boolean).join(" "),
4896
- ref: cardRef,
4897
- tabxwIndex: clickable || flipEffect ? 0 : -1,
4898
- role: clickable ? "button" : void 0,
4899
- onMouseEnter: handleMouseEnter,
4900
- onMouseLeave: handleMouseLeave,
4901
- onFocus: handleFocus,
4902
- onBlur: handleBlur,
4903
- onClick: handleClick,
4904
- onKeyDown: handleKeyDown
4905
- })), [ isElevated, isFlipped, isFocused, elevationClass, focusEffect, clickable, handleMouseEnter, handleMouseLeave, handleFocus, handleBlur, handleClick, handleKeyDown, flipEffect ]);
4906
- return {
4907
- cardRef: cardRef,
4908
- frontRef: frontRef,
4909
- backRef: backRef,
4910
- isFlipped: isFlipped,
4911
- isElevated: isElevated,
4912
- isFocused: isFocused,
4913
- isHovered: isHovered,
4914
- handleClick: handleClick,
4915
- handleKeyDown: handleKeyDown,
4916
- handleMouseEnter: handleMouseEnter,
4917
- handleMouseLeave: handleMouseLeave,
4918
- handleFocus: handleFocus,
4919
- handleBlur: handleBlur,
4920
- getCardProps: getCardProps
4921
- };
4922
- }, ElevationCard = ({elevationClass: elevationClass = "is-elevated", className: className = "", style: style, children: children, onClick: onClick, ...props}) => {
4923
- const {getCardProps: getCardProps} = useCard({
5999
+ const ElevationCard = ({elevationClass: elevationClass = "is-elevated", className: className = "", style: style, children: children, onClick: onClick, ...props}) => {
6000
+ const {getCardProps: getCardProps} = ((options = {}) => {
6001
+ const {elevationEffect: elevationEffect = !1, elevationClass: elevationClass = CARD.CLASSES.ACTIVE, flipEffect: flipEffect = !1, flipTrigger: flipTrigger = "click", focusEffect: focusEffect = !1, clickable: clickable = !1, onClick: onClick} = options, cardRef = React.useRef(null), frontRef = React.useRef(null), backRef = React.useRef(null), [isFlipped, setIsFlipped] = React.useState(!1), [isElevated, setIsElevated] = React.useState(!1), [isFocused, setIsFocused] = React.useState(!1), [isHovered, setIsHovered] = React.useState(!1), handleClick = React.useCallback((event => {
6002
+ flipEffect && "click" === flipTrigger && setIsFlipped((prev => !prev)), onClick && onClick(event);
6003
+ }), [ flipEffect, flipTrigger, onClick ]), handleKeyDown = React.useCallback((event => {
6004
+ "Enter" !== event.key && " " !== event.key || (event.preventDefault(), flipEffect && "click" === flipTrigger && setIsFlipped((prev => !prev)),
6005
+ onClick && onClick(event));
6006
+ }), [ flipEffect, flipTrigger, onClick ]), handleMouseEnter = React.useCallback((() => {
6007
+ setIsHovered(!0), elevationEffect && setIsElevated(!0), flipEffect && "hover" === flipTrigger && setIsFlipped(!0);
6008
+ }), [ elevationEffect, flipEffect, flipTrigger ]), handleMouseLeave = React.useCallback((() => {
6009
+ setIsHovered(!1), elevationEffect && setIsElevated(!1), flipEffect && "hover" === flipTrigger && setIsFlipped(!1);
6010
+ }), [ elevationEffect, flipEffect, flipTrigger ]), handleFocus = React.useCallback((() => {
6011
+ setIsFocused(!0);
6012
+ }), []), handleBlur = React.useCallback((() => {
6013
+ setIsFocused(!1);
6014
+ }), []), getCardProps = React.useCallback((() => ({
6015
+ className: [ CARD.CLASSES.BASE, isElevated ? elevationClass : "", isFlipped ? CARD.CLASSES.FLIPPED : "", isFocused && focusEffect ? CARD.CLASSES.FOCUSED : "", clickable ? CARD.CLASSES.CLICKABLE : "" ].filter(Boolean).join(" "),
6016
+ ref: cardRef,
6017
+ tabxwIndex: clickable || flipEffect ? 0 : -1,
6018
+ role: clickable ? "button" : void 0,
6019
+ onMouseEnter: handleMouseEnter,
6020
+ onMouseLeave: handleMouseLeave,
6021
+ onFocus: handleFocus,
6022
+ onBlur: handleBlur,
6023
+ onClick: handleClick,
6024
+ onKeyDown: handleKeyDown
6025
+ })), [ isElevated, isFlipped, isFocused, elevationClass, focusEffect, clickable, handleMouseEnter, handleMouseLeave, handleFocus, handleBlur, handleClick, handleKeyDown, flipEffect ]);
6026
+ return {
6027
+ cardRef: cardRef,
6028
+ frontRef: frontRef,
6029
+ backRef: backRef,
6030
+ isFlipped: isFlipped,
6031
+ isElevated: isElevated,
6032
+ isFocused: isFocused,
6033
+ isHovered: isHovered,
6034
+ handleClick: handleClick,
6035
+ handleKeyDown: handleKeyDown,
6036
+ handleMouseEnter: handleMouseEnter,
6037
+ handleMouseLeave: handleMouseLeave,
6038
+ handleFocus: handleFocus,
6039
+ handleBlur: handleBlur,
6040
+ getCardProps: getCardProps
6041
+ };
6042
+ })({
4924
6043
  elevationEffect: !0,
4925
6044
  elevationClass: elevationClass,
4926
6045
  clickable: Boolean(onClick),
@@ -9304,216 +10423,13 @@ function getRowId$1(row, rowKey) {
9304
10423
 
9305
10424
  /**
9306
10425
  * Hook for managing DataTable state and behavior
9307
- */ function useDataTable({data: data = [], columns: columns = [], sortable: sortable = !1, paginated: paginated = !1, pageSize: pageSize = 10, onSort: onSort, initialSortConfig: initialSortConfig, selectionMode: selectionMode = "none", selectedRowIds: controlledSelectedRowIds, onSelectionChange: onSelectionChange, rowKey: rowKey, columnFilters: columnFilters = !1, reorderable: reorderable = !1, onColumnReorder: onColumnReorder, onColumnVisibilityChange: onColumnVisibilityChange}) {
9308
- // Sort state
9309
- const [sortConfig, setSortConfig] = React.useState(initialSortConfig || null), [currentPage, setCurrentPage] = React.useState(1), [searchQuery, setSearchQuery] = React.useState(""), [internalSelectedRowIds, setInternalSelectedRowIds] = React.useState([]), selectedRowIds = controlledSelectedRowIds ?? internalSelectedRowIds, [columnOrder, setColumnOrder] = React.useState((() => columns.map((col => col.key)))), [columnVisibility, setColumnVisibility] = React.useState((() => {
9310
- const visibility = {};
9311
- return columns.forEach((col => {
9312
- visibility[col.key] = !1 !== col.visible;
9313
- })), visibility;
9314
- })), [columnFilterValues, setColumnFilterValues] = React.useState({});
9315
- // Pagination state
9316
- // Update column order when columns prop changes
9317
- React.useEffect((() => {
9318
- const newOrder = columns.map((col => col.key)), currentOrderSet = new Set(columnOrder), newOrderSet = new Set(newOrder);
9319
- // Only update if there are actual differences
9320
- newOrder.length === columnOrder.length && newOrder.every((key => currentOrderSet.has(key))) && columnOrder.every((key => newOrderSet.has(key))) || setColumnOrder(newOrder);
9321
- }), [ columns ]),
9322
- // Update column visibility when columns prop changes
9323
- React.useEffect((() => {
9324
- setColumnVisibility((prev => {
9325
- const updated = {
9326
- ...prev
9327
- };
9328
- return columns.forEach((col => {
9329
- col.key in updated || (updated[col.key] = !1 !== col.visible);
9330
- })), updated;
9331
- }));
9332
- }), [ columns ]);
9333
- // Visible columns based on order and visibility
9334
- const visibleColumns = React.useMemo((() => columnOrder.map((key => columns.find((col => col.key === key)))).filter((col => void 0 !== col && !1 !== columnVisibility[col.key]))), [ columns, columnOrder, columnVisibility ]), handleSort = React.useCallback((key => {
9335
- if (!sortable) return;
9336
- let direction = "asc";
9337
- sortConfig && sortConfig.key === key && "asc" === sortConfig.direction && (direction = "desc");
9338
- const newSortConfig = {
9339
- key: key,
9340
- direction: direction
9341
- };
9342
- setSortConfig(newSortConfig), onSort && onSort(newSortConfig);
9343
- }), [ sortable, sortConfig, onSort ]), handlePageChange = React.useCallback((page => {
9344
- page < 1 || setCurrentPage(page);
9345
- }), []), handleSearch = React.useCallback((query => {
9346
- setSearchQuery(query), setCurrentPage(1);
9347
- } // Reset to first page when searching
9348
- ), []), handleColumnFilterChange = React.useCallback(((columnKey, value) => {
9349
- setColumnFilterValues((prev => ({
9350
- ...prev,
9351
- [columnKey]: value
9352
- }))), setCurrentPage(1);
9353
- } // Reset to first page when filtering
9354
- ), []), clearColumnFilters = React.useCallback((() => {
9355
- setColumnFilterValues({}), setCurrentPage(1);
9356
- }), []), activeColumnFilters = React.useMemo((() => columnFilters ? Object.entries(columnFilterValues).filter((([, value]) => null != value && "" !== value)).map((([columnKey, value]) => {
9357
- const column = columns.find((col => col.key === columnKey));
9358
- return column && column.filterable ? {
9359
- key: columnKey,
9360
- value: value,
9361
- lowercaseValue: "string" == typeof value ? value.toLowerCase() : String(value).toLowerCase(),
9362
- column: column
9363
- } : null;
9364
- })).filter((f => null !== f)) : []), [ columnFilters, columnFilterValues, columns ]), filteredData = React.useMemo((() => {
9365
- if (!searchQuery && 0 === activeColumnFilters.length) return data;
9366
- const lowercaseQuery = searchQuery ? searchQuery.toLowerCase() : "";
9367
- return data.filter((row => {
9368
- // Apply global search
9369
- if (searchQuery && !visibleColumns.some((column => {
9370
- var _context;
9371
- const value = row[column.key];
9372
- return null != value && _includesInstanceProperty(_context = String(value).toLowerCase()).call(_context, lowercaseQuery);
9373
- }))) return !1;
9374
- // Apply column-specific filters
9375
- for (let i = 0; i < activeColumnFilters.length; i++) {
9376
- const filter = activeColumnFilters[i];
9377
- if (!filter) continue;
9378
- const {key: key, value: value, lowercaseValue: lowercaseValue, column: column} = filter, cellValue = row[key];
9379
- if (null == cellValue) return !1;
9380
- // Use custom filter function if provided
9381
- var _context2;
9382
- // Default text filter
9383
- if (column.filterFunction) {
9384
- if (!column.filterFunction(cellValue, value)) return !1;
9385
- } else if (!_includesInstanceProperty(_context2 = String(cellValue).toLowerCase()).call(_context2, lowercaseValue)) return !1;
9386
- }
9387
- return !0;
9388
- }));
9389
- }), [ data, visibleColumns, searchQuery, activeColumnFilters ]), sortedData = React.useMemo((() => sortConfig && sortable ? [ ...filteredData ].sort(((a, b) => {
9390
- const aValue = a[sortConfig.key], bValue = b[sortConfig.key];
9391
- return null == aValue ? "asc" === sortConfig.direction ? -1 : 1 : null == bValue ? "asc" === sortConfig.direction ? 1 : -1 : "string" == typeof aValue && "string" == typeof bValue ? "asc" === sortConfig.direction ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue) : "asc" === sortConfig.direction ? aValue > bValue ? 1 : -1 : aValue > bValue ? -1 : 1;
9392
- })) : filteredData), [ filteredData, sortConfig, sortable ]), paginatedData = React.useMemo((() => {
9393
- if (!paginated) return sortedData;
9394
- const startIndex = (currentPage - 1) * pageSize;
9395
- return sortedData.slice(startIndex, startIndex + pageSize);
9396
- }), [ sortedData, paginated, currentPage, pageSize ]), totalPages = React.useMemo((() => paginated ? Math.max(1, Math.ceil(sortedData.length / pageSize)) : 1), [ sortedData.length, paginated, pageSize ]), selectedRows = React.useMemo((() => "none" === selectionMode || 0 === selectedRowIds.length ? [] : sortedData.filter((row => _includesInstanceProperty(selectedRowIds).call(selectedRowIds, getRowId$1(row, rowKey))))), [ sortedData, selectedRowIds, selectionMode, rowKey ]), handleRowSelect = React.useCallback(((rowId, selected) => {
9397
- if ("none" === selectionMode) return;
9398
- let newSelectedIds;
9399
- if (newSelectedIds = "single" === selectionMode ? selected ? [ rowId ] : [] :
9400
- // multiple
9401
- selected ? [ ...selectedRowIds, rowId ] : selectedRowIds.filter((id => id !== rowId)),
9402
- controlledSelectedRowIds || setInternalSelectedRowIds(newSelectedIds), onSelectionChange) {
9403
- const selectedRowsData = sortedData.filter((row => _includesInstanceProperty(newSelectedIds).call(newSelectedIds, getRowId$1(row, rowKey))));
9404
- onSelectionChange(selectedRowsData, newSelectedIds);
9405
- }
9406
- }), [ selectionMode, selectedRowIds, controlledSelectedRowIds, onSelectionChange, sortedData, rowKey ]), handleSelectAll = React.useCallback((selected => {
9407
- if ("multiple" !== selectionMode) return;
9408
- const newSelectedIds = selected ? paginatedData.map((row => getRowId$1(row, rowKey))) : [];
9409
- if (controlledSelectedRowIds || setInternalSelectedRowIds(newSelectedIds), onSelectionChange) {
9410
- const selectedRowsData = sortedData.filter((row => _includesInstanceProperty(newSelectedIds).call(newSelectedIds, getRowId$1(row, rowKey))));
9411
- onSelectionChange(selectedRowsData, newSelectedIds);
9412
- }
9413
- }), [ selectionMode, paginatedData, sortedData, controlledSelectedRowIds, onSelectionChange, rowKey ]), isAllSelected = React.useMemo((() => "multiple" === selectionMode && 0 !== paginatedData.length && paginatedData.every((row => _includesInstanceProperty(selectedRowIds).call(selectedRowIds, getRowId$1(row, rowKey))))), [ selectionMode, paginatedData, selectedRowIds, rowKey ]), isIndeterminate = React.useMemo((() => {
9414
- if ("multiple" !== selectionMode || 0 === paginatedData.length) return !1;
9415
- const selectedCount = paginatedData.filter((row => _includesInstanceProperty(selectedRowIds).call(selectedRowIds, getRowId$1(row, rowKey)))).length;
9416
- return selectedCount > 0 && selectedCount < paginatedData.length;
9417
- }), [ selectionMode, paginatedData, selectedRowIds, rowKey ]), handleColumnVisibilityToggle = React.useCallback((columnKey => {
9418
- setColumnVisibility((prev => {
9419
- const updated = {
9420
- ...prev,
9421
- [columnKey]: !prev[columnKey]
9422
- };
9423
- if (onColumnVisibilityChange) {
9424
- const visibleKeys = Object.entries(updated).filter((([, visible]) => visible)).map((([key]) => key));
9425
- onColumnVisibilityChange(visibleKeys);
9426
- }
9427
- return updated;
9428
- }));
9429
- }), [ onColumnVisibilityChange ]);
9430
- // Handle sorting
9431
- // Handle column reorder
9432
- return React.useCallback(((fromIndex, toIndex) => {
9433
- const newOrder = [ ...columnOrder ], [removed] = newOrder.splice(fromIndex, 1);
9434
- removed && (newOrder.splice(toIndex, 0, removed), setColumnOrder(newOrder), onColumnReorder && onColumnReorder(newOrder));
9435
- }), [ columnOrder, onColumnReorder ]),
9436
- // Reset to first page when data changes
9437
- React.useEffect((() => {
9438
- setCurrentPage(1);
9439
- }), [ data ]),
9440
- // Reset current page if it's out of bounds
9441
- React.useEffect((() => {
9442
- currentPage > totalPages && totalPages > 0 && setCurrentPage(Math.max(1, totalPages));
9443
- }), [ currentPage, totalPages ]), {
9444
- displayData: paginatedData,
9445
- sortConfig: sortConfig,
9446
- currentPage: currentPage,
9447
- totalPages: totalPages,
9448
- handleSort: handleSort,
9449
- handlePageChange: handlePageChange,
9450
- handleSearch: handleSearch,
9451
- selectedRowIds: selectedRowIds,
9452
- selectedRows: selectedRows,
9453
- handleRowSelect: handleRowSelect,
9454
- handleSelectAll: handleSelectAll,
9455
- isAllSelected: isAllSelected,
9456
- isIndeterminate: isIndeterminate,
9457
- columnOrder: columnOrder,
9458
- visibleColumns: visibleColumns,
9459
- columnVisibility: columnVisibility,
9460
- handleColumnVisibilityToggle: handleColumnVisibilityToggle,
9461
- columnFilterValues: columnFilterValues,
9462
- handleColumnFilterChange: handleColumnFilterChange,
9463
- clearColumnFilters: clearColumnFilters
9464
- };
9465
- }
9466
-
9467
- Countdown.displayName = "Countdown";
10426
+ */ Countdown.displayName = "Countdown";
9468
10427
 
9469
10428
  const range = (start, end) => {
9470
10429
  const length = end - start + 1;
9471
10430
  return Array.from({
9472
10431
  length: length
9473
10432
  }, ((_, idx) => idx + start));
9474
- }, usePagination = ({currentPage: currentPage, totalPages: totalPages, siblingCount: siblingCount = 1, onPageChange: onPageChange}) => {
9475
- const paginationRange = React.useMemo((() => {
9476
- // siblingCount + firstPage + lastPage + currentPage + 2*DOTS
9477
- /*
9478
- Case 1: If the number of pages is less than the page numbers we want to show in our
9479
- paginationComponent, we return the range [1..totalPages]
9480
- */
9481
- if (siblingCount + 5 >= totalPages) return range(1, totalPages);
9482
- const leftSiblingIndex = Math.max(currentPage - siblingCount, 1), rightSiblingIndex = Math.min(currentPage + siblingCount, totalPages), shouldShowLeftDots = leftSiblingIndex > 2, shouldShowRightDots = rightSiblingIndex < totalPages - 2, lastPageIndex = totalPages;
9483
- /*
9484
- Case 2: No left dots to show, but rights dots to be shown
9485
- */
9486
- return !shouldShowLeftDots && shouldShowRightDots ? [ ...range(1, 3 + 2 * siblingCount), "...", totalPages ] :
9487
- /*
9488
- Case 3: No right dots to show, but left dots to be shown
9489
- */
9490
- shouldShowLeftDots && !shouldShowRightDots ? [ 1, "...", ...range(totalPages - (3 + 2 * siblingCount) + 1, totalPages) ] :
9491
- /*
9492
- Case 4: Both left and right dots to be shown
9493
- */
9494
- shouldShowLeftDots && shouldShowRightDots ? [ 1, "...", ...range(leftSiblingIndex, rightSiblingIndex), "...", lastPageIndex ] : [];
9495
- }), [ totalPages, siblingCount, currentPage ]), goToPage = page => {
9496
- page >= 1 && page <= totalPages && page !== currentPage && onPageChange(page);
9497
- };
9498
- return {
9499
- paginationRange: paginationRange,
9500
- currentPage: currentPage,
9501
- totalPages: totalPages,
9502
- goToPage: goToPage,
9503
- nextPage: () => {
9504
- goToPage(currentPage + 1);
9505
- },
9506
- prevPage: () => {
9507
- goToPage(currentPage - 1);
9508
- },
9509
- firstPage: () => {
9510
- goToPage(1);
9511
- },
9512
- lastPage: () => {
9513
- goToPage(totalPages);
9514
- },
9515
- DOTS: "..."
9516
- };
9517
10433
  }, PaginationNavButton = React.memo((({type: type, onClick: onClick, disabled: disabled, label: label, iconName: iconName}) => jsxRuntime.jsx("li", {
9518
10434
  className: `c-pagination__item c-pagination__item--${type} ${disabled ? "is-disabled" : ""}`,
9519
10435
  "aria-disabled": disabled,
@@ -9530,7 +10446,50 @@ const range = (start, end) => {
9530
10446
  })
9531
10447
  })
9532
10448
  }))), Pagination = React.memo((({currentPage: currentPage = PAGINATION_DEFAULTS.currentPage, totalPages: totalPages = PAGINATION_DEFAULTS.totalPages, onPageChange: onPageChange, siblingCount: siblingCount = PAGINATION_DEFAULTS.siblingCount, showFirstLastButtons: showFirstLastButtons = PAGINATION_DEFAULTS.showFirstLastButtons, showPrevNextButtons: showPrevNextButtons = PAGINATION_DEFAULTS.showPrevNextButtons, showSearch: showSearch = !1, searchPlaceholder: searchPlaceholder = "Go to page", size: size = PAGINATION_DEFAULTS.size, className: className = "", style: style, "aria-label": ariaLabel = "Pagination", glass: glass}) => {
9533
- const {paginationRange: paginationRange, goToPage: goToPage, nextPage: nextPage, prevPage: prevPage, firstPage: firstPage, lastPage: lastPage} = usePagination({
10449
+ const {paginationRange: paginationRange, goToPage: goToPage, nextPage: nextPage, prevPage: prevPage, firstPage: firstPage, lastPage: lastPage} = (({currentPage: currentPage, totalPages: totalPages, siblingCount: siblingCount = 1, onPageChange: onPageChange}) => {
10450
+ const paginationRange = React.useMemo((() => {
10451
+ // siblingCount + firstPage + lastPage + currentPage + 2*DOTS
10452
+ /*
10453
+ Case 1: If the number of pages is less than the page numbers we want to show in our
10454
+ paginationComponent, we return the range [1..totalPages]
10455
+ */
10456
+ if (siblingCount + 5 >= totalPages) return range(1, totalPages);
10457
+ const leftSiblingIndex = Math.max(currentPage - siblingCount, 1), rightSiblingIndex = Math.min(currentPage + siblingCount, totalPages), shouldShowLeftDots = leftSiblingIndex > 2, shouldShowRightDots = rightSiblingIndex < totalPages - 2, lastPageIndex = totalPages;
10458
+ /*
10459
+ Case 2: No left dots to show, but rights dots to be shown
10460
+ */
10461
+ return !shouldShowLeftDots && shouldShowRightDots ? [ ...range(1, 3 + 2 * siblingCount), "...", totalPages ] :
10462
+ /*
10463
+ Case 3: No right dots to show, but left dots to be shown
10464
+ */
10465
+ shouldShowLeftDots && !shouldShowRightDots ? [ 1, "...", ...range(totalPages - (3 + 2 * siblingCount) + 1, totalPages) ] :
10466
+ /*
10467
+ Case 4: Both left and right dots to be shown
10468
+ */
10469
+ shouldShowLeftDots && shouldShowRightDots ? [ 1, "...", ...range(leftSiblingIndex, rightSiblingIndex), "...", lastPageIndex ] : [];
10470
+ }), [ totalPages, siblingCount, currentPage ]), goToPage = page => {
10471
+ page >= 1 && page <= totalPages && page !== currentPage && onPageChange(page);
10472
+ };
10473
+ return {
10474
+ paginationRange: paginationRange,
10475
+ currentPage: currentPage,
10476
+ totalPages: totalPages,
10477
+ goToPage: goToPage,
10478
+ nextPage: () => {
10479
+ goToPage(currentPage + 1);
10480
+ },
10481
+ prevPage: () => {
10482
+ goToPage(currentPage - 1);
10483
+ },
10484
+ firstPage: () => {
10485
+ goToPage(1);
10486
+ },
10487
+ lastPage: () => {
10488
+ goToPage(totalPages);
10489
+ },
10490
+ DOTS: "..."
10491
+ };
10492
+ })({
9534
10493
  currentPage: currentPage,
9535
10494
  totalPages: totalPages,
9536
10495
  siblingCount: siblingCount,
@@ -9742,14 +10701,13 @@ const DropdownContext = React.createContext({
9742
10701
  id: "",
9743
10702
  trigger: "click"
9744
10703
  }), DropdownMenu = React.forwardRef((({children: children, className: className = "", ...props}, ref) => {
9745
- const {glass: glass} = React.useContext(DropdownStyleContext);
9746
- // We need to access glass prop here?
9747
- // Wait, the original code wrapped <ul> in Context Provider.
9748
- // And applied glass wrapper around <ul>.
9749
- // If we use Compound Component, DropdownMenu should be the list.
9750
- return jsxRuntime.jsx("ul", {
10704
+ const {glass: glass} = React.useContext(DropdownStyleContext), {id: id} = React.useContext(DropdownContext);
10705
+ return jsxRuntime.jsx("ul", {
9751
10706
  ref: ref,
10707
+ id: `${id}-menu`,
9752
10708
  className: `c-dropdown__menu ${glass ? "c-dropdown__menu--glass" : ""} ${className}`.trim(),
10709
+ role: "menu",
10710
+ "aria-labelledby": `${id}-trigger`,
9753
10711
  ...props,
9754
10712
  children: children
9755
10713
  });
@@ -9758,14 +10716,23 @@ const DropdownContext = React.createContext({
9758
10716
  // Compound Components
9759
10717
  DropdownMenu.displayName = "DropdownMenu";
9760
10718
 
9761
- const DropdownTrigger = React.forwardRef((({children: children, className: className = "", onClick: onClick, onKeyDown: onKeyDown, ...props}, ref) => jsxRuntime.jsx("div", {
9762
- ref: ref,
9763
- className: `c-dropdown__toggle ${className}`.trim(),
9764
- onClick: onClick,
9765
- onKeyDown: onKeyDown,
9766
- ...props,
9767
- children: children
9768
- })));
10719
+ const DropdownTrigger = React.forwardRef((({children: children, className: className = "", onClick: onClick, onKeyDown: onKeyDown, ...props}, ref) => {
10720
+ const {isOpen: isOpen, id: id} = React.useContext(DropdownContext);
10721
+ return jsxRuntime.jsx("div", {
10722
+ ref: ref,
10723
+ id: `${id}-trigger`,
10724
+ className: `c-dropdown__toggle ${className}`.trim(),
10725
+ onClick: onClick,
10726
+ onKeyDown: onKeyDown,
10727
+ "aria-haspopup": "true",
10728
+ "aria-expanded": isOpen,
10729
+ "aria-controls": `${id}-menu`,
10730
+ tabIndex: 0,
10731
+ role: "button",
10732
+ ...props,
10733
+ children: children
10734
+ });
10735
+ }));
9769
10736
 
9770
10737
  DropdownTrigger.displayName = "DropdownTrigger";
9771
10738
 
@@ -10014,7 +10981,165 @@ Dropdown.Item = DropdownItem, Dropdown.Divider = DropdownDivider, Dropdown.Heade
10014
10981
  * ```
10015
10982
  */
10016
10983
  const DataTable = React.memo((({data: data, columns: columns, className: className, style: style, sortable: sortable = !1, filterable: filterable = !1, paginated: paginated = !1, pageSize: pageSize = 10, striped: striped = !1, bordered: bordered = !1, dense: dense = !1, loading: loading = !1, emptyMessage: emptyMessage = "No data available", onRowClick: onRowClick, onSort: onSort, selectionMode: selectionMode = "none", selectedRowIds: controlledSelectedRowIds, onSelectionChange: onSelectionChange, rowKey: rowKey, resizable: resizable = !1, reorderable: reorderable = !1, onColumnReorder: onColumnReorder, showColumnVisibility: showColumnVisibility = !1, onColumnVisibilityChange: onColumnVisibilityChange, stickyHeader: stickyHeader = !1, stickyHeaderOffset: stickyHeaderOffset = "0px", virtualScrolling: virtualScrolling = !1, estimatedRowHeight: estimatedRowHeight = 50, overscan: overscan = 5, exportable: exportable = !1, exportFormats: exportFormats = [ "csv", "excel", "json" ], exportFilename: exportFilename = "data-table", onExport: onExport, columnFilters: columnFilters = !1, ...props}) => {
10017
- const tableRef = React.useRef(null), headerRef = React.useRef(null), [resizingColumn, setResizingColumn] = React.useState(null), [columnWidths, setColumnWidths] = React.useState({}), [dragStartIndex, setDragStartIndex] = React.useState(null), [dragOverIndex, setDragOverIndex] = React.useState(null), {displayData: displayData, sortConfig: sortConfig, currentPage: currentPage, totalPages: totalPages, handleSort: handleSort, handlePageChange: handlePageChange, handleSearch: handleSearch, selectedRowIds: selectedRowIds, selectedRows: selectedRows, handleRowSelect: handleRowSelect, handleSelectAll: handleSelectAll, isAllSelected: isAllSelected, isIndeterminate: isIndeterminate, visibleColumns: visibleColumns, columnVisibility: columnVisibility, handleColumnVisibilityToggle: handleColumnVisibilityToggle, columnFilterValues: columnFilterValues, handleColumnFilterChange: handleColumnFilterChange, clearColumnFilters: clearColumnFilters} = useDataTable({
10984
+ const tableRef = React.useRef(null), headerRef = React.useRef(null), [resizingColumn, setResizingColumn] = React.useState(null), [columnWidths, setColumnWidths] = React.useState({}), [dragStartIndex, setDragStartIndex] = React.useState(null), [dragOverIndex, setDragOverIndex] = React.useState(null), {displayData: displayData, sortConfig: sortConfig, currentPage: currentPage, totalPages: totalPages, handleSort: handleSort, handlePageChange: handlePageChange, handleSearch: handleSearch, selectedRowIds: selectedRowIds, selectedRows: selectedRows, handleRowSelect: handleRowSelect, handleSelectAll: handleSelectAll, isAllSelected: isAllSelected, isIndeterminate: isIndeterminate, visibleColumns: visibleColumns, columnVisibility: columnVisibility, handleColumnVisibilityToggle: handleColumnVisibilityToggle, columnFilterValues: columnFilterValues, handleColumnFilterChange: handleColumnFilterChange, clearColumnFilters: clearColumnFilters} = function({data: data = [], columns: columns = [], sortable: sortable = !1, paginated: paginated = !1, pageSize: pageSize = 10, onSort: onSort, initialSortConfig: initialSortConfig, selectionMode: selectionMode = "none", selectedRowIds: controlledSelectedRowIds, onSelectionChange: onSelectionChange, rowKey: rowKey, columnFilters: columnFilters = !1, reorderable: reorderable = !1, onColumnReorder: onColumnReorder, onColumnVisibilityChange: onColumnVisibilityChange}) {
10985
+ // Sort state
10986
+ const [sortConfig, setSortConfig] = React.useState(initialSortConfig || null), [currentPage, setCurrentPage] = React.useState(1), [searchQuery, setSearchQuery] = React.useState(""), [internalSelectedRowIds, setInternalSelectedRowIds] = React.useState([]), selectedRowIds = controlledSelectedRowIds ?? internalSelectedRowIds, [columnOrder, setColumnOrder] = React.useState((() => columns.map((col => col.key)))), [columnVisibility, setColumnVisibility] = React.useState((() => {
10987
+ const visibility = {};
10988
+ return columns.forEach((col => {
10989
+ visibility[col.key] = !1 !== col.visible;
10990
+ })), visibility;
10991
+ })), [columnFilterValues, setColumnFilterValues] = React.useState({});
10992
+ // Pagination state
10993
+ // Update column order when columns prop changes
10994
+ React.useEffect((() => {
10995
+ const newOrder = columns.map((col => col.key)), currentOrderSet = new Set(columnOrder), newOrderSet = new Set(newOrder);
10996
+ // Only update if there are actual differences
10997
+ newOrder.length === columnOrder.length && newOrder.every((key => currentOrderSet.has(key))) && columnOrder.every((key => newOrderSet.has(key))) || setColumnOrder(newOrder);
10998
+ }), [ columns ]),
10999
+ // Update column visibility when columns prop changes
11000
+ React.useEffect((() => {
11001
+ setColumnVisibility((prev => {
11002
+ const updated = {
11003
+ ...prev
11004
+ };
11005
+ return columns.forEach((col => {
11006
+ col.key in updated || (updated[col.key] = !1 !== col.visible);
11007
+ })), updated;
11008
+ }));
11009
+ }), [ columns ]);
11010
+ // Visible columns based on order and visibility
11011
+ const visibleColumns = React.useMemo((() => columnOrder.map((key => columns.find((col => col.key === key)))).filter((col => void 0 !== col && !1 !== columnVisibility[col.key]))), [ columns, columnOrder, columnVisibility ]), handleSort = React.useCallback((key => {
11012
+ if (!sortable) return;
11013
+ let direction = "asc";
11014
+ sortConfig && sortConfig.key === key && "asc" === sortConfig.direction && (direction = "desc");
11015
+ const newSortConfig = {
11016
+ key: key,
11017
+ direction: direction
11018
+ };
11019
+ setSortConfig(newSortConfig), onSort && onSort(newSortConfig);
11020
+ }), [ sortable, sortConfig, onSort ]), handlePageChange = React.useCallback((page => {
11021
+ page < 1 || setCurrentPage(page);
11022
+ }), []), handleSearch = React.useCallback((query => {
11023
+ setSearchQuery(query), setCurrentPage(1);
11024
+ } // Reset to first page when searching
11025
+ ), []), handleColumnFilterChange = React.useCallback(((columnKey, value) => {
11026
+ setColumnFilterValues((prev => ({
11027
+ ...prev,
11028
+ [columnKey]: value
11029
+ }))), setCurrentPage(1);
11030
+ } // Reset to first page when filtering
11031
+ ), []), clearColumnFilters = React.useCallback((() => {
11032
+ setColumnFilterValues({}), setCurrentPage(1);
11033
+ }), []), activeColumnFilters = React.useMemo((() => columnFilters ? Object.entries(columnFilterValues).filter((([, value]) => null != value && "" !== value)).map((([columnKey, value]) => {
11034
+ const column = columns.find((col => col.key === columnKey));
11035
+ return column && column.filterable ? {
11036
+ key: columnKey,
11037
+ value: value,
11038
+ lowercaseValue: "string" == typeof value ? value.toLowerCase() : String(value).toLowerCase(),
11039
+ column: column
11040
+ } : null;
11041
+ })).filter((f => null !== f)) : []), [ columnFilters, columnFilterValues, columns ]), filteredData = React.useMemo((() => {
11042
+ if (!searchQuery && 0 === activeColumnFilters.length) return data;
11043
+ const lowercaseQuery = searchQuery ? searchQuery.toLowerCase() : "";
11044
+ return data.filter((row => {
11045
+ // Apply global search
11046
+ if (searchQuery && !visibleColumns.some((column => {
11047
+ var _context;
11048
+ const value = row[column.key];
11049
+ return null != value && _includesInstanceProperty(_context = String(value).toLowerCase()).call(_context, lowercaseQuery);
11050
+ }))) return !1;
11051
+ // Apply column-specific filters
11052
+ for (let i = 0; i < activeColumnFilters.length; i++) {
11053
+ const filter = activeColumnFilters[i];
11054
+ if (!filter) continue;
11055
+ const {key: key, value: value, lowercaseValue: lowercaseValue, column: column} = filter, cellValue = row[key];
11056
+ if (null == cellValue) return !1;
11057
+ // Use custom filter function if provided
11058
+ var _context2;
11059
+ // Default text filter
11060
+ if (column.filterFunction) {
11061
+ if (!column.filterFunction(cellValue, value)) return !1;
11062
+ } else if (!_includesInstanceProperty(_context2 = String(cellValue).toLowerCase()).call(_context2, lowercaseValue)) return !1;
11063
+ }
11064
+ return !0;
11065
+ }));
11066
+ }), [ data, visibleColumns, searchQuery, activeColumnFilters ]), sortedData = React.useMemo((() => sortConfig && sortable ? [ ...filteredData ].sort(((a, b) => {
11067
+ const aValue = a[sortConfig.key], bValue = b[sortConfig.key];
11068
+ return null == aValue ? "asc" === sortConfig.direction ? -1 : 1 : null == bValue ? "asc" === sortConfig.direction ? 1 : -1 : "string" == typeof aValue && "string" == typeof bValue ? "asc" === sortConfig.direction ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue) : "asc" === sortConfig.direction ? aValue > bValue ? 1 : -1 : aValue > bValue ? -1 : 1;
11069
+ })) : filteredData), [ filteredData, sortConfig, sortable ]), paginatedData = React.useMemo((() => {
11070
+ if (!paginated) return sortedData;
11071
+ const startIndex = (currentPage - 1) * pageSize;
11072
+ return sortedData.slice(startIndex, startIndex + pageSize);
11073
+ }), [ sortedData, paginated, currentPage, pageSize ]), totalPages = React.useMemo((() => paginated ? Math.max(1, Math.ceil(sortedData.length / pageSize)) : 1), [ sortedData.length, paginated, pageSize ]), selectedRows = React.useMemo((() => "none" === selectionMode || 0 === selectedRowIds.length ? [] : sortedData.filter((row => _includesInstanceProperty(selectedRowIds).call(selectedRowIds, getRowId$1(row, rowKey))))), [ sortedData, selectedRowIds, selectionMode, rowKey ]), handleRowSelect = React.useCallback(((rowId, selected) => {
11074
+ if ("none" === selectionMode) return;
11075
+ let newSelectedIds;
11076
+ if (newSelectedIds = "single" === selectionMode ? selected ? [ rowId ] : [] :
11077
+ // multiple
11078
+ selected ? [ ...selectedRowIds, rowId ] : selectedRowIds.filter((id => id !== rowId)),
11079
+ controlledSelectedRowIds || setInternalSelectedRowIds(newSelectedIds), onSelectionChange) {
11080
+ const selectedRowsData = sortedData.filter((row => _includesInstanceProperty(newSelectedIds).call(newSelectedIds, getRowId$1(row, rowKey))));
11081
+ onSelectionChange(selectedRowsData, newSelectedIds);
11082
+ }
11083
+ }), [ selectionMode, selectedRowIds, controlledSelectedRowIds, onSelectionChange, sortedData, rowKey ]), handleSelectAll = React.useCallback((selected => {
11084
+ if ("multiple" !== selectionMode) return;
11085
+ const newSelectedIds = selected ? paginatedData.map((row => getRowId$1(row, rowKey))) : [];
11086
+ if (controlledSelectedRowIds || setInternalSelectedRowIds(newSelectedIds), onSelectionChange) {
11087
+ const selectedRowsData = sortedData.filter((row => _includesInstanceProperty(newSelectedIds).call(newSelectedIds, getRowId$1(row, rowKey))));
11088
+ onSelectionChange(selectedRowsData, newSelectedIds);
11089
+ }
11090
+ }), [ selectionMode, paginatedData, sortedData, controlledSelectedRowIds, onSelectionChange, rowKey ]), isAllSelected = React.useMemo((() => "multiple" === selectionMode && 0 !== paginatedData.length && paginatedData.every((row => _includesInstanceProperty(selectedRowIds).call(selectedRowIds, getRowId$1(row, rowKey))))), [ selectionMode, paginatedData, selectedRowIds, rowKey ]), isIndeterminate = React.useMemo((() => {
11091
+ if ("multiple" !== selectionMode || 0 === paginatedData.length) return !1;
11092
+ const selectedCount = paginatedData.filter((row => _includesInstanceProperty(selectedRowIds).call(selectedRowIds, getRowId$1(row, rowKey)))).length;
11093
+ return selectedCount > 0 && selectedCount < paginatedData.length;
11094
+ }), [ selectionMode, paginatedData, selectedRowIds, rowKey ]), handleColumnVisibilityToggle = React.useCallback((columnKey => {
11095
+ setColumnVisibility((prev => {
11096
+ const updated = {
11097
+ ...prev,
11098
+ [columnKey]: !prev[columnKey]
11099
+ };
11100
+ if (onColumnVisibilityChange) {
11101
+ const visibleKeys = Object.entries(updated).filter((([, visible]) => visible)).map((([key]) => key));
11102
+ onColumnVisibilityChange(visibleKeys);
11103
+ }
11104
+ return updated;
11105
+ }));
11106
+ }), [ onColumnVisibilityChange ]);
11107
+ // Handle sorting
11108
+ // Handle column reorder
11109
+ return React.useCallback(((fromIndex, toIndex) => {
11110
+ const newOrder = [ ...columnOrder ], [removed] = newOrder.splice(fromIndex, 1);
11111
+ removed && (newOrder.splice(toIndex, 0, removed), setColumnOrder(newOrder), onColumnReorder && onColumnReorder(newOrder));
11112
+ }), [ columnOrder, onColumnReorder ]),
11113
+ // Reset to first page when data changes
11114
+ React.useEffect((() => {
11115
+ setCurrentPage(1);
11116
+ }), [ data ]),
11117
+ // Reset current page if it's out of bounds
11118
+ React.useEffect((() => {
11119
+ currentPage > totalPages && totalPages > 0 && setCurrentPage(Math.max(1, totalPages));
11120
+ }), [ currentPage, totalPages ]), {
11121
+ displayData: paginatedData,
11122
+ sortConfig: sortConfig,
11123
+ currentPage: currentPage,
11124
+ totalPages: totalPages,
11125
+ handleSort: handleSort,
11126
+ handlePageChange: handlePageChange,
11127
+ handleSearch: handleSearch,
11128
+ selectedRowIds: selectedRowIds,
11129
+ selectedRows: selectedRows,
11130
+ handleRowSelect: handleRowSelect,
11131
+ handleSelectAll: handleSelectAll,
11132
+ isAllSelected: isAllSelected,
11133
+ isIndeterminate: isIndeterminate,
11134
+ columnOrder: columnOrder,
11135
+ visibleColumns: visibleColumns,
11136
+ columnVisibility: columnVisibility,
11137
+ handleColumnVisibilityToggle: handleColumnVisibilityToggle,
11138
+ columnFilterValues: columnFilterValues,
11139
+ handleColumnFilterChange: handleColumnFilterChange,
11140
+ clearColumnFilters: clearColumnFilters
11141
+ };
11142
+ }({
10018
11143
  data: data,
10019
11144
  columns: columns,
10020
11145
  sortable: sortable,
@@ -12366,297 +13491,6 @@ const DEFAULT_ATOMIX_FONTS = [ {
12366
13491
  };
12367
13492
  }
12368
13493
 
12369
- /**
12370
- * Breadcrumb state and functionality
12371
- * @param initialOptions - Initial breadcrumb options
12372
- * @returns Breadcrumb state and methods
12373
- */ function useBreadcrumb(initialOptions) {
12374
- return {
12375
- defaultOptions: {
12376
- items: [],
12377
- divider: BREADCRUMB.DEFAULTS.DIVIDER,
12378
- className: "",
12379
- "aria-label": "Breadcrumb",
12380
- ...initialOptions
12381
- },
12382
- generateBreadcrumbClass: options => {
12383
- const {className: className = ""} = options;
12384
- return [ BREADCRUMB.CLASSES.BASE, className ].filter(Boolean).join(" ").trim();
12385
- },
12386
- generateItemClass: (item, isLast) => [ BREADCRUMB.CLASSES.ITEM, item.active || isLast ? BREADCRUMB.CLASSES.ACTIVE : "" ].filter(Boolean).join(" ").trim(),
12387
- isItemLink: (item, isLast) => Boolean(item.href && !item.active && !isLast),
12388
- parseItemsFromJson: jsonString => {
12389
- try {
12390
- return JSON.parse(jsonString);
12391
- } catch (error) {
12392
- return console.error("Error parsing breadcrumb items:", error), [];
12393
- }
12394
- }
12395
- };
12396
- }
12397
-
12398
- /**
12399
- * Hook for managing modal state
12400
- */ function useModal$1({isOpen: isOpenProp, onOpenChange: onOpenChange, onOpen: onOpen, onClose: onClose} = {}) {
12401
- // For uncontrolled usage
12402
- const [isOpenState, setIsOpenState] = React.useState(!1), isControlled = void 0 !== isOpenProp, isOpen = isControlled ? !!isOpenProp : isOpenState;
12403
- // Determine if we're in controlled or uncontrolled mode
12404
- // Update internal state when prop changes (for controlled mode)
12405
- React.useEffect((() => {
12406
- isControlled && setIsOpenState(!!isOpenProp);
12407
- }), [ isOpenProp, isControlled ]);
12408
- const updateOpen = React.useCallback((nextIsOpen => {
12409
- // For uncontrolled mode, update internal state
12410
- isControlled || setIsOpenState(nextIsOpen),
12411
- // Call the change handler in either mode
12412
- onOpenChange && onOpenChange(nextIsOpen),
12413
- // Call the specific handler
12414
- nextIsOpen && onOpen ? onOpen() : !nextIsOpen && onClose && onClose();
12415
- }), [ isControlled, onOpenChange, onOpen, onClose ]), open = React.useCallback((() => {
12416
- updateOpen(!0);
12417
- }), [ updateOpen ]), close = React.useCallback((() => {
12418
- updateOpen(!1);
12419
- }), [ updateOpen ]), toggle = React.useCallback((() => {
12420
- updateOpen(!isOpen);
12421
- }), [ isOpen, updateOpen ]);
12422
- return {
12423
- isOpen: isOpen,
12424
- open: open,
12425
- close: close,
12426
- toggle: toggle
12427
- };
12428
- }
12429
-
12430
- function useSlider(options) {
12431
- 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({
12432
- isTransitioning: !1,
12433
- loop: loop,
12434
- slides: slides,
12435
- slidesToShow: slidesToShow,
12436
- speed: speed,
12437
- onSlideChange: onSlideChange
12438
- }), [realIndex, setRealIndex] = React.useState(initialSlide), [internalIndex, setInternalIndex] = React.useState(0), [isTransitioning, setIsTransitioning] = React.useState(!1), [containerSize, setContainerSize] = React.useState(0), [touching, setTouching] = React.useState(!1), [touchStart, setTouchStart] = React.useState(0), [dragOffset, setDragOffset] = React.useState(0), slideWidth = React.useMemo((() => 0 === containerSize ? 0 : (containerSize - spaceBetween * (slidesToShow - 1)) / slidesToShow), [ containerSize, spaceBetween, slidesToShow ]), allSlides = React.useMemo((() => loop && 0 !== slides.length ? [ ...slides.map(((slide, i) => ({
12439
- ...slide,
12440
- id: `set1-${slide.id || i}`
12441
- }))), ...slides.map(((slide, i) => ({
12442
- ...slide,
12443
- id: `set2-${slide.id || i}`
12444
- }))), ...slides.map(((slide, i) => ({
12445
- ...slide,
12446
- id: `set3-${slide.id || i}`
12447
- }))) ] : slides), [ slides, loop ]), loopedSlides = slides.length, translateValue = React.useMemo((() => 0 === slideWidth ? 0 : -internalIndex * slideWidth + dragOffset), [ slideWidth, internalIndex, dragOffset ]);
12448
- // Update the ref whenever the relevant state/props change
12449
- React.useEffect((() => {
12450
- sliderStateRef.current = {
12451
- isTransitioning: isTransitioning,
12452
- loop: loop,
12453
- slides: slides,
12454
- slidesToShow: slidesToShow,
12455
- speed: speed,
12456
- onSlideChange: onSlideChange
12457
- };
12458
- }), [ isTransitioning, loop, slides, slidesToShow, speed, onSlideChange ]),
12459
- // Autoplay effect
12460
- React.useEffect((() => {
12461
- if (!autoplay) return autoplayRef.current && (clearInterval(autoplayRef.current),
12462
- autoplayRef.current = null), void setAutoplayRunning(!1);
12463
- const autoplayParams = "boolean" == typeof autoplay ? {
12464
- delay: 3e3
12465
- } : autoplay, {delay: delay = 3e3, pauseOnMouseEnter: pauseOnMouseEnter = !1, disableOnInteraction: disableOnInteraction = !1, reverseDirection: reverseDirection = !1} = autoplayParams;
12466
- // Clear any existing interval
12467
- autoplayRef.current && clearInterval(autoplayRef.current),
12468
- // Create new interval
12469
- autoplayRef.current = setInterval((() => {
12470
- // Use ref to get the latest state without resetting the interval
12471
- const {isTransitioning: currentIsTransitioning, loop: currentLoop, slides: currentSlides, slidesToShow: currentSlidesToShow, speed: currentSpeed, onSlideChange: currentOnSlideChange} = sliderStateRef.current;
12472
- // We need to use a functional update to get the latest values
12473
- setRealIndex((prevRealIndex => {
12474
- if (currentIsTransitioning) return prevRealIndex;
12475
- // Stop autoplay on interaction if disableOnInteraction is true
12476
- let nextIndex;
12477
- // Trigger the slide change
12478
- if (disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
12479
- autoplayRef.current = null, setAutoplayRunning(!1)), nextIndex = currentLoop ? (prevRealIndex + 1) % currentSlides.length : Math.min(prevRealIndex + 1, currentSlides.length - currentSlidesToShow),
12480
- reverseDirection) {
12481
- // For reverse direction, we would go to previous slide
12482
- const prevIndex = currentLoop ? 0 === prevRealIndex ? currentSlides.length - 1 : prevRealIndex - 1 : Math.max(prevRealIndex - 1, 0);
12483
- return setInternalIndex(currentLoop ? currentSlides.length + prevIndex : prevIndex),
12484
- setIsTransitioning(!0), setDragOffset(0), setTimeout((() => {
12485
- setIsTransitioning(!1), currentOnSlideChange?.(prevIndex);
12486
- }), currentSpeed), prevIndex;
12487
- }
12488
- // Normal direction
12489
- return setInternalIndex(currentLoop ? currentSlides.length + nextIndex : nextIndex),
12490
- setIsTransitioning(!0), setDragOffset(0), setTimeout((() => {
12491
- setIsTransitioning(!1), currentOnSlideChange?.(nextIndex),
12492
- // Reposition after transition ends for looped sliders
12493
- currentLoop && nextIndex >= 2 * currentSlides.length && (repositioningRef.current = !0,
12494
- setInternalIndex(currentSlides.length + nextIndex), setTimeout((() => {
12495
- repositioningRef.current = !1;
12496
- }), 0));
12497
- }), currentSpeed), nextIndex;
12498
- }));
12499
- }), delay), setAutoplayRunning(!0);
12500
- // Handle pause on mouse enter/leave if enabled
12501
- let containerElement = null;
12502
- const handleMouseEnter = () => {
12503
- autoplayRef.current && (clearInterval(autoplayRef.current), autoplayRef.current = null,
12504
- setAutoplayRunning(!1));
12505
- }, handleMouseLeave = () => {
12506
- // Restart autoplay
12507
- autoplayRef.current && clearInterval(autoplayRef.current), autoplayRef.current = setInterval((() => {
12508
- const {isTransitioning: currentIsTransitioning, loop: currentLoop, slides: currentSlides, slidesToShow: currentSlidesToShow, speed: currentSpeed, onSlideChange: currentOnSlideChange} = sliderStateRef.current;
12509
- setRealIndex((prevRealIndex => {
12510
- if (currentIsTransitioning) return prevRealIndex;
12511
- let nextIndex;
12512
- return nextIndex = currentLoop ? (prevRealIndex + 1) % currentSlides.length : Math.min(prevRealIndex + 1, currentSlides.length - currentSlidesToShow),
12513
- setInternalIndex(currentLoop ? currentSlides.length + nextIndex : nextIndex), setIsTransitioning(!0),
12514
- setDragOffset(0), setTimeout((() => {
12515
- setIsTransitioning(!1), currentOnSlideChange?.(nextIndex), currentLoop && nextIndex >= 2 * currentSlides.length && (repositioningRef.current = !0,
12516
- setInternalIndex(currentSlides.length + nextIndex), setTimeout((() => {
12517
- repositioningRef.current = !1;
12518
- }), 0));
12519
- }), currentSpeed), nextIndex;
12520
- }));
12521
- }), delay), setAutoplayRunning(!0);
12522
- };
12523
- // Cleanup
12524
- return pauseOnMouseEnter && containerRef.current && (containerElement = containerRef.current,
12525
- containerElement.addEventListener("mouseenter", handleMouseEnter), containerElement.addEventListener("mouseleave", handleMouseLeave)),
12526
- () => {
12527
- autoplayRef.current && (clearInterval(autoplayRef.current), autoplayRef.current = null),
12528
- containerElement && (containerElement.removeEventListener("mouseenter", handleMouseEnter),
12529
- containerElement.removeEventListener("mouseleave", handleMouseLeave)), setAutoplayRunning(!1);
12530
- };
12531
- }), [ autoplay, repositioningRef ]),
12532
- // Initialize
12533
- React.useEffect((() => {
12534
- setInternalIndex(loop ? slides.length + initialSlide : initialSlide);
12535
- }), [ loop, slides.length, initialSlide ]), React.useEffect((() => {
12536
- const updateSize = () => {
12537
- if (containerRef.current) {
12538
- const size = "horizontal" === direction ? containerRef.current.offsetWidth : containerRef.current.offsetHeight;
12539
- setContainerSize(size);
12540
- }
12541
- };
12542
- return updateSize(), window.addEventListener("resize", updateSize), () => window.removeEventListener("resize", updateSize);
12543
- }), [ direction ]);
12544
- const slideNext = React.useCallback((() => {
12545
- if (!isTransitioning) if (
12546
- // Stop autoplay on interaction if disableOnInteraction is true
12547
- autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
12548
- autoplayRef.current = null, setAutoplayRunning(!1)), loop) {
12549
- const nextRealIndex = (realIndex + 1) % slides.length, nextInternalIndex = internalIndex + 1;
12550
- setRealIndex(nextRealIndex), setInternalIndex(nextInternalIndex), setIsTransitioning(!0),
12551
- setDragOffset(0), setTimeout((() => {
12552
- setIsTransitioning(!1), onSlideChange?.(nextRealIndex),
12553
- // Reposition after transition ends
12554
- nextInternalIndex >= 2 * slides.length && (repositioningRef.current = !0, setInternalIndex(slides.length + nextRealIndex),
12555
- setTimeout((() => {
12556
- repositioningRef.current = !1;
12557
- }), 0));
12558
- }), speed);
12559
- } else {
12560
- const nextIndex = Math.min(realIndex + 1, slides.length - slidesToShow);
12561
- setRealIndex(nextIndex), setInternalIndex(nextIndex), setIsTransitioning(!0), setDragOffset(0),
12562
- setTimeout((() => {
12563
- setIsTransitioning(!1), onSlideChange?.(nextIndex);
12564
- }), speed);
12565
- }
12566
- }), [ realIndex, internalIndex, slides.length, slidesToShow, loop, isTransitioning, speed, onSlideChange, allSlides.length, loopedSlides, autoplay ]), slidePrev = React.useCallback((() => {
12567
- if (!isTransitioning) if (
12568
- // Stop autoplay on interaction if disableOnInteraction is true
12569
- autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
12570
- autoplayRef.current = null, setAutoplayRunning(!1)), loop) {
12571
- const prevRealIndex = 0 === realIndex ? slides.length - 1 : realIndex - 1, prevInternalIndex = internalIndex - 1;
12572
- setRealIndex(prevRealIndex), setInternalIndex(prevInternalIndex), setIsTransitioning(!0),
12573
- setDragOffset(0), setTimeout((() => {
12574
- setIsTransitioning(!1), onSlideChange?.(prevRealIndex),
12575
- // Reposition after transition ends
12576
- prevInternalIndex < slides.length && (repositioningRef.current = !0, setInternalIndex(slides.length + prevRealIndex),
12577
- setTimeout((() => {
12578
- repositioningRef.current = !1;
12579
- }), 0));
12580
- }), speed);
12581
- } else {
12582
- const prevIndex = Math.max(realIndex - 1, 0);
12583
- setRealIndex(prevIndex), setInternalIndex(prevIndex), setIsTransitioning(!0), setDragOffset(0),
12584
- setTimeout((() => {
12585
- setIsTransitioning(!1), onSlideChange?.(prevIndex);
12586
- }), speed);
12587
- }
12588
- }), [ realIndex, internalIndex, slides.length, loop, isTransitioning, speed, onSlideChange, allSlides.length, loopedSlides, autoplay ]), goToSlide = React.useCallback((index => {
12589
- isTransitioning || index === realIndex || (
12590
- // Stop autoplay on interaction if disableOnInteraction is true
12591
- autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
12592
- autoplayRef.current = null, setAutoplayRunning(!1)), setIsTransitioning(!0), setDragOffset(0),
12593
- setRealIndex(index), setInternalIndex(loop ? slides.length + index : index), setTimeout((() => {
12594
- setIsTransitioning(!1), onSlideChange?.(index);
12595
- }), speed));
12596
- }), [ realIndex, isTransitioning, speed, onSlideChange, loop, loopedSlides, autoplay ]), handleTouchStart = React.useCallback((e => {
12597
- if (!allowTouchMove) return;
12598
- // Stop autoplay on interaction if disableOnInteraction is true
12599
- autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
12600
- autoplayRef.current = null, setAutoplayRunning(!1));
12601
- const client = "horizontal" === direction ? "touches" in e ? e.touches[0]?.clientX || 0 : e.clientX : "touches" in e ? e.touches[0]?.clientY || 0 : e.clientY;
12602
- setTouchStart(client), setTouching(!0), setDragOffset(0);
12603
- }), [ allowTouchMove, direction, autoplay ]), handleTouchMove = React.useCallback((e => {
12604
- if (!touching || !allowTouchMove) return;
12605
- const client = "horizontal" === direction ? "touches" in e ? e.touches[0]?.clientX || 0 : e.clientX : "touches" in e ? e.touches[0]?.clientY || 0 : e.clientY, diff = touchStart - client;
12606
- Math.abs(diff) > 10 && (e.preventDefault(), setDragOffset(.5 * -diff));
12607
- }), [ touching, touchStart, allowTouchMove, direction ]), handleTouchEnd = React.useCallback((e => {
12608
- if (!touching || !allowTouchMove) return;
12609
- const client = "horizontal" === direction ? "changedTouches" in e ? e.changedTouches[0]?.clientX || 0 : e.clientX : "changedTouches" in e ? e.changedTouches[0]?.clientY || 0 : e.clientY, diff = touchStart - client;
12610
- setTouching(!1), setDragOffset(0), Math.abs(diff) > threshold && (diff > 0 ? slideNext() : slidePrev());
12611
- }), [ touching, touchStart, threshold, slideNext, slidePrev, allowTouchMove, direction ]), canSlideNext = loop || realIndex < slides.length - slidesToShow, canSlidePrev = loop || realIndex > 0;
12612
- return {
12613
- activeIndex: realIndex,
12614
- realIndex: realIndex,
12615
- previousIndex: realIndex,
12616
- isBeginning: !loop && 0 === realIndex,
12617
- isEnd: !loop && realIndex >= slides.length - slidesToShow,
12618
- progress: slides.length > 0 ? realIndex / (slides.length - 1) : 0,
12619
- autoplayRunning: autoplayRunning,
12620
- transitioning: isTransitioning,
12621
- touching: touching,
12622
- translate: translateValue,
12623
- slidesPerView: slidesToShow,
12624
- slidesCount: slides.length,
12625
- isLocked: !1,
12626
- destroyed: !1,
12627
- size: containerSize,
12628
- touches: {
12629
- startX: 0,
12630
- startY: 0,
12631
- currentX: 0,
12632
- currentY: 0,
12633
- diff: 0
12634
- },
12635
- allowSlideNext: canSlideNext,
12636
- allowSlidePrev: canSlidePrev,
12637
- allowTouchMove: allowTouchMove,
12638
- animating: isTransitioning,
12639
- enabled: !0,
12640
- initialized: !0,
12641
- slideNext: slideNext,
12642
- slidePrev: slidePrev,
12643
- goToSlide: goToSlide,
12644
- canSlideNext: canSlideNext,
12645
- canSlidePrev: canSlidePrev,
12646
- containerRef: containerRef,
12647
- wrapperRef: wrapperRef,
12648
- handleTouchStart: handleTouchStart,
12649
- handleTouchMove: handleTouchMove,
12650
- handleTouchEnd: handleTouchEnd,
12651
- allSlides: allSlides,
12652
- translateValue: translateValue,
12653
- slideWidth: slideWidth,
12654
- currentSlidesToShow: slidesToShow,
12655
- loopedSlides: loopedSlides,
12656
- repositioningRef: repositioningRef
12657
- };
12658
- }
12659
-
12660
13494
  /**
12661
13495
  * Simplified hook for chart data processing
12662
13496
  */ function useChartData(data) {
@@ -12757,37 +13591,44 @@ function useSlider(options) {
12757
13591
  // Accordion composables
12758
13592
  var composablesImport = Object.freeze({
12759
13593
  __proto__: null,
12760
- DOTS: "...",
13594
+ BALANCED_PRESET: BALANCED_PRESET,
13595
+ DEFAULT_BREAKPOINTS: DEFAULT_BREAKPOINTS,
13596
+ DeviceDetector: DeviceDetector,
13597
+ MOBILE_OPTIMIZED_BREAKPOINTS: MOBILE_OPTIMIZED_BREAKPOINTS,
13598
+ PERFORMANCE_PRESET: PERFORMANCE_PRESET,
13599
+ PerformanceOverlay: PerformanceOverlay,
13600
+ QUALITY_PRESET: QUALITY_PRESET,
13601
+ createBreakpoints: createBreakpoints$1,
13602
+ getDefaultBreakpoints: getDefaultBreakpoints,
13603
+ getDevicePreset: getDevicePreset,
13604
+ getMobileOptimizedParams: getMobileOptimizedParams,
13605
+ getQualityMultipliers: getQualityMultipliers,
12761
13606
  useAccordion: useAccordion,
12762
13607
  useAtomixGlass: useAtomixGlass,
12763
13608
  useBadge: useBadge,
12764
13609
  useBarChart: useBarChart,
12765
13610
  useBlock: useBlock,
12766
- useBreadcrumb: useBreadcrumb,
12767
- useCard: useCard,
12768
13611
  useChartData: useChartData,
12769
13612
  useChartInteraction: useChartInteraction,
12770
13613
  useChartScale: useChartScale,
12771
- useDataTable: useDataTable,
12772
13614
  useEdgePanel: useEdgePanel,
12773
13615
  useForm: useForm,
12774
13616
  useFormGroup: useFormGroup,
12775
13617
  useHero: useHero,
12776
13618
  useInput: useInput,
12777
13619
  useLineChart: useLineChart,
12778
- useModal: useModal$1,
12779
13620
  useNav: useNav,
12780
13621
  useNavDropdown: useNavDropdown,
12781
13622
  useNavItem: useNavItem,
12782
13623
  useNavbar: useNavbar,
12783
- usePagination: usePagination,
13624
+ usePerformanceMonitor: usePerformanceMonitor,
12784
13625
  usePieChart: usePieChart,
12785
13626
  useRadio: useRadio,
13627
+ useResponsiveGlass: useResponsiveGlass,
12786
13628
  useRiver: useRiver,
12787
13629
  useSelect: useSelect,
12788
13630
  useSideMenu: useSideMenu,
12789
13631
  useSideMenuItem: useSideMenuItem,
12790
- useSlider: useSlider,
12791
13632
  useSpinner: useSpinner,
12792
13633
  useTextarea: useTextarea,
12793
13634
  useTodo: useTodo
@@ -12878,7 +13719,10 @@ const Select = React.memo((({options: options, value: value, onChange: onChange
12878
13719
  };
12879
13720
  }), []);
12880
13721
  // Toggle dropdown
12881
- const handleItemClick = React.useCallback((option => {
13722
+ const handleToggle = () => {
13723
+ disabled || (!isOpen && bodyRef.current && panelRef.current ? bodyRef.current.style.height = `${panelRef.current.clientHeight}px` : bodyRef.current && (bodyRef.current.style.height = "0px"),
13724
+ setIsOpen(!isOpen));
13725
+ }, handleItemClick = React.useCallback((option => {
12882
13726
  if (setSelectedLabel(option.label), setIsOpen(!1), bodyRef.current && (bodyRef.current.style.height = "0px"),
12883
13727
  nativeSelectRef.current && (nativeSelectRef.current.value = option.value), onChange) {
12884
13728
  // Create a synthetic event
@@ -12922,7 +13766,15 @@ const Select = React.memo((({options: options, value: value, onChange: onChange
12922
13766
  "aria-describedby": ariaDescribedBy,
12923
13767
  "aria-invalid": invalid,
12924
13768
  style: {
12925
- display: "none"
13769
+ position: "absolute",
13770
+ width: "1px",
13771
+ height: "1px",
13772
+ padding: "0",
13773
+ margin: "-1px",
13774
+ overflow: "hidden",
13775
+ clip: "rect(0, 0, 0, 0)",
13776
+ whiteSpace: "nowrap",
13777
+ border: "0"
12926
13778
  },
12927
13779
  children: [ placeholder && jsxRuntime.jsx("option", {
12928
13780
  value: "",
@@ -12935,11 +13787,29 @@ const Select = React.memo((({options: options, value: value, onChange: onChange
12935
13787
  }, option.value))) ]
12936
13788
  }), jsxRuntime.jsx("div", {
12937
13789
  className: SELECT.CLASSES.SELECTED,
12938
- onClick: () => {
12939
- disabled || (!isOpen && bodyRef.current && panelRef.current ? bodyRef.current.style.height = `${panelRef.current.clientHeight}px` : bodyRef.current && (bodyRef.current.style.height = "0px"),
12940
- setIsOpen(!isOpen));
13790
+ onClick: handleToggle,
13791
+ onKeyDown: event => {
13792
+ if (!disabled) switch (event.key) {
13793
+ case "Enter":
13794
+ case " ":
13795
+ event.preventDefault(), handleToggle();
13796
+ break;
13797
+
13798
+ case "Escape":
13799
+ isOpen && (event.preventDefault(), setIsOpen(!1), bodyRef.current && (bodyRef.current.style.height = "0px"));
13800
+ break;
13801
+
13802
+ case "ArrowDown":
13803
+ case "ArrowUp":
13804
+ isOpen || (event.preventDefault(), handleToggle());
13805
+ }
12941
13806
  },
12942
13807
  "aria-disabled": disabled,
13808
+ tabIndex: disabled ? -1 : 0,
13809
+ role: "combobox",
13810
+ "aria-haspopup": "listbox",
13811
+ "aria-expanded": isOpen,
13812
+ "aria-controls": id ? `${id}-listbox` : void 0,
12943
13813
  children: selectedLabel
12944
13814
  }), jsxRuntime.jsx("i", {
12945
13815
  className: `${SELECT.CLASSES.ICON_CARET} ${SELECT.CLASSES.TOGGLE_ICON}`
@@ -12954,10 +13824,16 @@ const Select = React.memo((({options: options, value: value, onChange: onChange
12954
13824
  ref: panelRef,
12955
13825
  children: jsxRuntime.jsx("ul", {
12956
13826
  className: SELECT.CLASSES.SELECT_ITEMS,
13827
+ role: "listbox",
13828
+ id: id ? `${id}-listbox` : void 0,
13829
+ "aria-labelledby": id,
12957
13830
  children: hasOptionsProp ? options.map(((option, index) => jsxRuntime.jsx("li", {
12958
13831
  className: SELECT.CLASSES.SELECT_ITEM,
12959
13832
  "data-value": option.value,
12960
13833
  onClick: () => !option.disabled && handleItemClick(option),
13834
+ role: "option",
13835
+ "aria-selected": value === option.value,
13836
+ "aria-disabled": option.disabled,
12961
13837
  children: jsxRuntime.jsxs("label", {
12962
13838
  htmlFor: `SelectItem${index}`,
12963
13839
  className: "c-checkbox",
@@ -14500,7 +15376,45 @@ const ModalImpl = React.memo((({children: children, isOpen: isOpen = !1, onOpen
14500
15376
  onOpenChange: onOpenChange,
14501
15377
  onClose: onClose,
14502
15378
  onOpen: onOpen
14503
- });
15379
+ }), contentRef =
15380
+ /**
15381
+ * Hook to trap focus within an element
15382
+ */
15383
+ function(isOpen) {
15384
+ const containerRef = React.useRef(null), previouslyFocusedElement = React.useRef(null), getFocusableElements = React.useCallback((() => containerRef.current ? Array.from(containerRef.current.querySelectorAll('a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])')).filter((el => {
15385
+ // Check if visible
15386
+ const style = window.getComputedStyle(el);
15387
+ return "none" !== style.display && "hidden" !== style.visibility;
15388
+ })) : []), []), handleKeyDown = React.useCallback((event => {
15389
+ if ("Tab" !== event.key) return;
15390
+ const focusableElements = getFocusableElements();
15391
+ if (0 === focusableElements.length) return;
15392
+ const firstElement = focusableElements[0], lastElement = focusableElements[focusableElements.length - 1];
15393
+ event.shiftKey ?
15394
+ // Shift + Tab
15395
+ document.activeElement === firstElement && (event.preventDefault(), lastElement.focus()) :
15396
+ // Tab
15397
+ document.activeElement === lastElement && (event.preventDefault(), firstElement.focus());
15398
+ }), [ getFocusableElements ]);
15399
+ return React.useEffect((() => {
15400
+ if (isOpen) {
15401
+ previouslyFocusedElement.current = document.activeElement;
15402
+ const focusableElements = getFocusableElements();
15403
+ if (focusableElements.length > 0 && focusableElements[0]) {
15404
+ // Delay focus slightly to ensure element is rendered
15405
+ const firstEl = focusableElements[0];
15406
+ setTimeout((() => {
15407
+ firstEl.focus();
15408
+ }), 0);
15409
+ }
15410
+ document.addEventListener("keydown", handleKeyDown);
15411
+ } else previouslyFocusedElement.current && previouslyFocusedElement.current.focus(),
15412
+ document.removeEventListener("keydown", handleKeyDown);
15413
+ return () => {
15414
+ document.removeEventListener("keydown", handleKeyDown);
15415
+ };
15416
+ }), [ isOpen, getFocusableElements, handleKeyDown ]), containerRef;
15417
+ }(isOpenState), instanceId = React.useId(), titleId = `modal-title-${instanceId}`, descId = `modal-desc-${instanceId}`;
14504
15418
  // Handle keyboard events for Escape key
14505
15419
  React.useEffect((() => {
14506
15420
  if (!keyboard) return;
@@ -14518,15 +15432,19 @@ const ModalImpl = React.memo((({children: children, isOpen: isOpen = !1, onOpen
14518
15432
  return React__default.default.isValidElement(child) && _includesInstanceProperty(_context = [ "ModalHeader", "ModalBody", "ModalFooter" ]).call(_context, child.type.displayName);
14519
15433
  })), modalContent = jsxRuntime.jsx("div", {
14520
15434
  className: "c-modal__content",
15435
+ ref: contentRef,
14521
15436
  children: hasCompoundComponents ? React__default.default.Children.map(children, (child => React__default.default.isValidElement(child) && "ModalHeader" === child.type.displayName ? React__default.default.cloneElement(child, {
14522
- onClose: child.props.onClose || close
15437
+ onClose: child.props.onClose || close,
15438
+ id: titleId
14523
15439
  }) : child)) : jsxRuntime.jsxs(jsxRuntime.Fragment, {
14524
15440
  children: [ (title || closeButton) && jsxRuntime.jsx(ModalHeader, {
15441
+ id: titleId,
14525
15442
  title: title,
14526
15443
  subtitle: subtitle,
14527
15444
  closeButton: closeButton,
14528
15445
  onClose: close
14529
15446
  }), jsxRuntime.jsx(ModalBody, {
15447
+ id: descId,
14530
15448
  children: children
14531
15449
  }), footer && jsxRuntime.jsx(ModalFooter, {
14532
15450
  children: footer
@@ -14544,6 +15462,8 @@ const ModalImpl = React.memo((({children: children, isOpen: isOpen = !1, onOpen
14544
15462
  role: "dialog",
14545
15463
  "aria-modal": "true",
14546
15464
  "aria-hidden": !isOpenState,
15465
+ "aria-labelledby": titleId,
15466
+ "aria-describedby": descId,
14547
15467
  ...props,
14548
15468
  children: [ jsxRuntime.jsx("div", {
14549
15469
  ref: backdropRef,
@@ -14796,7 +15716,27 @@ const Navbar = React.forwardRef((({brand: brand, children: children, variant: v
14796
15716
  return window.addEventListener("resize", handleResize), () => {
14797
15717
  window.removeEventListener("resize", handleResize);
14798
15718
  };
14799
- }), [ collapsible, expanded, onToggle ]);
15719
+ }), [ collapsible, expanded, onToggle ]),
15720
+ // Handle Escape key to close mobile menu
15721
+ React.useEffect((() => {
15722
+ if (!navbarExpanded || !closeOnEscape) return;
15723
+ const handleEscapeKey = event => {
15724
+ "Escape" === event.key && ("function" == typeof onToggle ? onToggle(!1) : setNavbarExpanded(!1));
15725
+ };
15726
+ return document.addEventListener("keydown", handleEscapeKey), () => {
15727
+ document.removeEventListener("keydown", handleEscapeKey);
15728
+ };
15729
+ }), [ navbarExpanded, closeOnEscape, onToggle ]),
15730
+ // Handle outside click to close mobile menu
15731
+ React.useEffect((() => {
15732
+ if (!navbarExpanded || !closeOnOutsideClick) return;
15733
+ const handleClickOutside = event => {
15734
+ !collapseRef.current || collapseRef.current.contains(event.target) || event.target.closest(".c-navbar__toggler") || ("function" == typeof onToggle ? onToggle(!1) : setNavbarExpanded(!1));
15735
+ };
15736
+ return document.addEventListener("mousedown", handleClickOutside), () => {
15737
+ document.removeEventListener("mousedown", handleClickOutside);
15738
+ };
15739
+ }), [ navbarExpanded, closeOnOutsideClick, onToggle ]);
14800
15740
  // Generate the navbar class
14801
15741
  const navbarClass = generateNavbarClass({
14802
15742
  position: position,
@@ -17404,7 +18344,235 @@ const SectionIntro = ({title: title, label: label, text: text, actions: actions,
17404
18344
  SectionIntro.displayName = "SectionIntro";
17405
18345
 
17406
18346
  const Slider = React.forwardRef(((props, ref) => {
17407
- 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 = useSlider({
18347
+ 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({
18349
+ isTransitioning: !1,
18350
+ loop: loop,
18351
+ slides: slides,
18352
+ slidesToShow: slidesToShow,
18353
+ speed: speed,
18354
+ onSlideChange: onSlideChange
18355
+ }), [realIndex, setRealIndex] = React.useState(initialSlide), [internalIndex, setInternalIndex] = React.useState(0), [isTransitioning, setIsTransitioning] = React.useState(!1), [containerSize, setContainerSize] = React.useState(0), [touching, setTouching] = React.useState(!1), [touchStart, setTouchStart] = React.useState(0), [dragOffset, setDragOffset] = React.useState(0), slideWidth = React.useMemo((() => 0 === containerSize ? 0 : (containerSize - spaceBetween * (slidesToShow - 1)) / slidesToShow), [ containerSize, spaceBetween, slidesToShow ]), allSlides = React.useMemo((() => loop && 0 !== slides.length ? [ ...slides.map(((slide, i) => ({
18356
+ ...slide,
18357
+ id: `set1-${slide.id || i}`
18358
+ }))), ...slides.map(((slide, i) => ({
18359
+ ...slide,
18360
+ id: `set2-${slide.id || i}`
18361
+ }))), ...slides.map(((slide, i) => ({
18362
+ ...slide,
18363
+ id: `set3-${slide.id || i}`
18364
+ }))) ] : slides), [ slides, loop ]), loopedSlides = slides.length, translateValue = React.useMemo((() => 0 === slideWidth ? 0 : -internalIndex * slideWidth + dragOffset), [ slideWidth, internalIndex, dragOffset ]);
18365
+ // Update the ref whenever the relevant state/props change
18366
+ React.useEffect((() => {
18367
+ sliderStateRef.current = {
18368
+ isTransitioning: isTransitioning,
18369
+ loop: loop,
18370
+ slides: slides,
18371
+ slidesToShow: slidesToShow,
18372
+ speed: speed,
18373
+ onSlideChange: onSlideChange
18374
+ };
18375
+ }), [ isTransitioning, loop, slides, slidesToShow, speed, onSlideChange ]),
18376
+ // Autoplay effect
18377
+ React.useEffect((() => {
18378
+ if (!autoplay) return autoplayRef.current && (clearInterval(autoplayRef.current),
18379
+ autoplayRef.current = null), void setAutoplayRunning(!1);
18380
+ const autoplayParams = "boolean" == typeof autoplay ? {
18381
+ delay: 3e3
18382
+ } : autoplay, {delay: delay = 3e3, pauseOnMouseEnter: pauseOnMouseEnter = !1, disableOnInteraction: disableOnInteraction = !1, reverseDirection: reverseDirection = !1} = autoplayParams;
18383
+ // Clear any existing interval
18384
+ autoplayRef.current && clearInterval(autoplayRef.current),
18385
+ // Create new interval
18386
+ autoplayRef.current = setInterval((() => {
18387
+ // Use ref to get the latest state without resetting the interval
18388
+ const {isTransitioning: currentIsTransitioning, loop: currentLoop, slides: currentSlides, slidesToShow: currentSlidesToShow, speed: currentSpeed, onSlideChange: currentOnSlideChange} = sliderStateRef.current;
18389
+ // We need to use a functional update to get the latest values
18390
+ setRealIndex((prevRealIndex => {
18391
+ if (currentIsTransitioning) return prevRealIndex;
18392
+ // Stop autoplay on interaction if disableOnInteraction is true
18393
+ let nextIndex;
18394
+ // Trigger the slide change
18395
+ if (disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
18396
+ autoplayRef.current = null, setAutoplayRunning(!1)), nextIndex = currentLoop ? (prevRealIndex + 1) % currentSlides.length : Math.min(prevRealIndex + 1, currentSlides.length - currentSlidesToShow),
18397
+ reverseDirection) {
18398
+ // For reverse direction, we would go to previous slide
18399
+ const prevIndex = currentLoop ? 0 === prevRealIndex ? currentSlides.length - 1 : prevRealIndex - 1 : Math.max(prevRealIndex - 1, 0);
18400
+ return setInternalIndex(currentLoop ? currentSlides.length + prevIndex : prevIndex),
18401
+ setIsTransitioning(!0), setDragOffset(0), setTimeout((() => {
18402
+ setIsTransitioning(!1), currentOnSlideChange?.(prevIndex);
18403
+ }), currentSpeed), prevIndex;
18404
+ }
18405
+ // Normal direction
18406
+ return setInternalIndex(currentLoop ? currentSlides.length + nextIndex : nextIndex),
18407
+ setIsTransitioning(!0), setDragOffset(0), setTimeout((() => {
18408
+ setIsTransitioning(!1), currentOnSlideChange?.(nextIndex),
18409
+ // Reposition after transition ends for looped sliders
18410
+ currentLoop && nextIndex >= 2 * currentSlides.length && (repositioningRef.current = !0,
18411
+ setInternalIndex(currentSlides.length + nextIndex), setTimeout((() => {
18412
+ repositioningRef.current = !1;
18413
+ }), 0));
18414
+ }), currentSpeed), nextIndex;
18415
+ }));
18416
+ }), delay), setAutoplayRunning(!0);
18417
+ // Handle pause on mouse enter/leave if enabled
18418
+ let containerElement = null;
18419
+ const handleMouseEnter = () => {
18420
+ autoplayRef.current && (clearInterval(autoplayRef.current), autoplayRef.current = null,
18421
+ setAutoplayRunning(!1));
18422
+ }, handleMouseLeave = () => {
18423
+ // Restart autoplay
18424
+ autoplayRef.current && clearInterval(autoplayRef.current), autoplayRef.current = setInterval((() => {
18425
+ const {isTransitioning: currentIsTransitioning, loop: currentLoop, slides: currentSlides, slidesToShow: currentSlidesToShow, speed: currentSpeed, onSlideChange: currentOnSlideChange} = sliderStateRef.current;
18426
+ setRealIndex((prevRealIndex => {
18427
+ if (currentIsTransitioning) return prevRealIndex;
18428
+ let nextIndex;
18429
+ return nextIndex = currentLoop ? (prevRealIndex + 1) % currentSlides.length : Math.min(prevRealIndex + 1, currentSlides.length - currentSlidesToShow),
18430
+ setInternalIndex(currentLoop ? currentSlides.length + nextIndex : nextIndex), setIsTransitioning(!0),
18431
+ setDragOffset(0), setTimeout((() => {
18432
+ setIsTransitioning(!1), currentOnSlideChange?.(nextIndex), currentLoop && nextIndex >= 2 * currentSlides.length && (repositioningRef.current = !0,
18433
+ setInternalIndex(currentSlides.length + nextIndex), setTimeout((() => {
18434
+ repositioningRef.current = !1;
18435
+ }), 0));
18436
+ }), currentSpeed), nextIndex;
18437
+ }));
18438
+ }), delay), setAutoplayRunning(!0);
18439
+ };
18440
+ // Cleanup
18441
+ return pauseOnMouseEnter && containerRef.current && (containerElement = containerRef.current,
18442
+ containerElement.addEventListener("mouseenter", handleMouseEnter), containerElement.addEventListener("mouseleave", handleMouseLeave)),
18443
+ () => {
18444
+ autoplayRef.current && (clearInterval(autoplayRef.current), autoplayRef.current = null),
18445
+ containerElement && (containerElement.removeEventListener("mouseenter", handleMouseEnter),
18446
+ containerElement.removeEventListener("mouseleave", handleMouseLeave)), setAutoplayRunning(!1);
18447
+ };
18448
+ }), [ autoplay, repositioningRef ]),
18449
+ // Initialize
18450
+ React.useEffect((() => {
18451
+ setInternalIndex(loop ? slides.length + initialSlide : initialSlide);
18452
+ }), [ loop, slides.length, initialSlide ]), React.useEffect((() => {
18453
+ const updateSize = () => {
18454
+ if (containerRef.current) {
18455
+ const size = "horizontal" === direction ? containerRef.current.offsetWidth : containerRef.current.offsetHeight;
18456
+ setContainerSize(size);
18457
+ }
18458
+ };
18459
+ return updateSize(), window.addEventListener("resize", updateSize), () => window.removeEventListener("resize", updateSize);
18460
+ }), [ direction ]);
18461
+ const slideNext = React.useCallback((() => {
18462
+ if (!isTransitioning) if (
18463
+ // Stop autoplay on interaction if disableOnInteraction is true
18464
+ autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
18465
+ autoplayRef.current = null, setAutoplayRunning(!1)), loop) {
18466
+ const nextRealIndex = (realIndex + 1) % slides.length, nextInternalIndex = internalIndex + 1;
18467
+ setRealIndex(nextRealIndex), setInternalIndex(nextInternalIndex), setIsTransitioning(!0),
18468
+ setDragOffset(0), setTimeout((() => {
18469
+ setIsTransitioning(!1), onSlideChange?.(nextRealIndex),
18470
+ // Reposition after transition ends
18471
+ nextInternalIndex >= 2 * slides.length && (repositioningRef.current = !0, setInternalIndex(slides.length + nextRealIndex),
18472
+ setTimeout((() => {
18473
+ repositioningRef.current = !1;
18474
+ }), 0));
18475
+ }), speed);
18476
+ } else {
18477
+ const nextIndex = Math.min(realIndex + 1, slides.length - slidesToShow);
18478
+ setRealIndex(nextIndex), setInternalIndex(nextIndex), setIsTransitioning(!0), setDragOffset(0),
18479
+ setTimeout((() => {
18480
+ setIsTransitioning(!1), onSlideChange?.(nextIndex);
18481
+ }), speed);
18482
+ }
18483
+ }), [ realIndex, internalIndex, slides.length, slidesToShow, loop, isTransitioning, speed, onSlideChange, allSlides.length, loopedSlides, autoplay ]), slidePrev = React.useCallback((() => {
18484
+ if (!isTransitioning) if (
18485
+ // Stop autoplay on interaction if disableOnInteraction is true
18486
+ autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
18487
+ autoplayRef.current = null, setAutoplayRunning(!1)), loop) {
18488
+ const prevRealIndex = 0 === realIndex ? slides.length - 1 : realIndex - 1, prevInternalIndex = internalIndex - 1;
18489
+ setRealIndex(prevRealIndex), setInternalIndex(prevInternalIndex), setIsTransitioning(!0),
18490
+ setDragOffset(0), setTimeout((() => {
18491
+ setIsTransitioning(!1), onSlideChange?.(prevRealIndex),
18492
+ // Reposition after transition ends
18493
+ prevInternalIndex < slides.length && (repositioningRef.current = !0, setInternalIndex(slides.length + prevRealIndex),
18494
+ setTimeout((() => {
18495
+ repositioningRef.current = !1;
18496
+ }), 0));
18497
+ }), speed);
18498
+ } else {
18499
+ const prevIndex = Math.max(realIndex - 1, 0);
18500
+ setRealIndex(prevIndex), setInternalIndex(prevIndex), setIsTransitioning(!0), setDragOffset(0),
18501
+ setTimeout((() => {
18502
+ setIsTransitioning(!1), onSlideChange?.(prevIndex);
18503
+ }), speed);
18504
+ }
18505
+ }), [ realIndex, internalIndex, slides.length, loop, isTransitioning, speed, onSlideChange, allSlides.length, loopedSlides, autoplay ]), goToSlide = React.useCallback((index => {
18506
+ isTransitioning || index === realIndex || (
18507
+ // Stop autoplay on interaction if disableOnInteraction is true
18508
+ autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
18509
+ autoplayRef.current = null, setAutoplayRunning(!1)), setIsTransitioning(!0), setDragOffset(0),
18510
+ setRealIndex(index), setInternalIndex(loop ? slides.length + index : index), setTimeout((() => {
18511
+ setIsTransitioning(!1), onSlideChange?.(index);
18512
+ }), speed));
18513
+ }), [ realIndex, isTransitioning, speed, onSlideChange, loop, loopedSlides, autoplay ]), handleTouchStart = React.useCallback((e => {
18514
+ if (!allowTouchMove) return;
18515
+ // Stop autoplay on interaction if disableOnInteraction is true
18516
+ autoplay && "object" == typeof autoplay && autoplay.disableOnInteraction && autoplayRef.current && (clearInterval(autoplayRef.current),
18517
+ autoplayRef.current = null, setAutoplayRunning(!1));
18518
+ const client = "horizontal" === direction ? "touches" in e ? e.touches[0]?.clientX || 0 : e.clientX : "touches" in e ? e.touches[0]?.clientY || 0 : e.clientY;
18519
+ setTouchStart(client), setTouching(!0), setDragOffset(0);
18520
+ }), [ allowTouchMove, direction, autoplay ]), handleTouchMove = React.useCallback((e => {
18521
+ if (!touching || !allowTouchMove) return;
18522
+ const client = "horizontal" === direction ? "touches" in e ? e.touches[0]?.clientX || 0 : e.clientX : "touches" in e ? e.touches[0]?.clientY || 0 : e.clientY, diff = touchStart - client;
18523
+ Math.abs(diff) > 10 && (e.preventDefault(), setDragOffset(.5 * -diff));
18524
+ }), [ touching, touchStart, allowTouchMove, direction ]), handleTouchEnd = React.useCallback((e => {
18525
+ if (!touching || !allowTouchMove) return;
18526
+ const client = "horizontal" === direction ? "changedTouches" in e ? e.changedTouches[0]?.clientX || 0 : e.clientX : "changedTouches" in e ? e.changedTouches[0]?.clientY || 0 : e.clientY, diff = touchStart - client;
18527
+ setTouching(!1), setDragOffset(0), Math.abs(diff) > threshold && (diff > 0 ? slideNext() : slidePrev());
18528
+ }), [ touching, touchStart, threshold, slideNext, slidePrev, allowTouchMove, direction ]), canSlideNext = loop || realIndex < slides.length - slidesToShow, canSlidePrev = loop || realIndex > 0;
18529
+ return {
18530
+ activeIndex: realIndex,
18531
+ realIndex: realIndex,
18532
+ previousIndex: realIndex,
18533
+ isBeginning: !loop && 0 === realIndex,
18534
+ isEnd: !loop && realIndex >= slides.length - slidesToShow,
18535
+ progress: slides.length > 0 ? realIndex / (slides.length - 1) : 0,
18536
+ autoplayRunning: autoplayRunning,
18537
+ transitioning: isTransitioning,
18538
+ touching: touching,
18539
+ translate: translateValue,
18540
+ slidesPerView: slidesToShow,
18541
+ slidesCount: slides.length,
18542
+ isLocked: !1,
18543
+ destroyed: !1,
18544
+ size: containerSize,
18545
+ touches: {
18546
+ startX: 0,
18547
+ startY: 0,
18548
+ currentX: 0,
18549
+ currentY: 0,
18550
+ diff: 0
18551
+ },
18552
+ allowSlideNext: canSlideNext,
18553
+ allowSlidePrev: canSlidePrev,
18554
+ allowTouchMove: allowTouchMove,
18555
+ animating: isTransitioning,
18556
+ enabled: !0,
18557
+ initialized: !0,
18558
+ slideNext: slideNext,
18559
+ slidePrev: slidePrev,
18560
+ goToSlide: goToSlide,
18561
+ canSlideNext: canSlideNext,
18562
+ canSlidePrev: canSlidePrev,
18563
+ containerRef: containerRef,
18564
+ wrapperRef: wrapperRef,
18565
+ handleTouchStart: handleTouchStart,
18566
+ handleTouchMove: handleTouchMove,
18567
+ handleTouchEnd: handleTouchEnd,
18568
+ allSlides: allSlides,
18569
+ translateValue: translateValue,
18570
+ slideWidth: slideWidth,
18571
+ currentSlidesToShow: slidesToShow,
18572
+ loopedSlides: loopedSlides,
18573
+ repositioningRef: repositioningRef
18574
+ };
18575
+ }({
17408
18576
  slides: validSlides,
17409
18577
  slidesToShow: slidesToShow,
17410
18578
  spaceBetween: spaceBetween,
@@ -17431,7 +18599,8 @@ const Slider = React.forwardRef(((props, ref) => {
17431
18599
  })
17432
18600
  });
17433
18601
  const containerClasses = [ "c-slider", "vertical" === direction && "c-slider--vertical", grabCursor && "c-slider--grab-cursor", touching && "c-slider--grabbing", loop && "c-slider--loop", className ].filter(Boolean).join(" ");
17434
- return jsxRuntime.jsxs("div", {
18602
+ // Keyboard navigation
18603
+ return jsxRuntime.jsxs("div", {
17435
18604
  ref: ref || containerRef,
17436
18605
  className: containerClasses,
17437
18606
  style: {
@@ -17449,9 +18618,32 @@ const Slider = React.forwardRef(((props, ref) => {
17449
18618
  onMouseMove: handleTouchMove,
17450
18619
  onMouseUp: handleTouchEnd,
17451
18620
  onMouseLeave: handleTouchEnd,
18621
+ onKeyDown: event => {
18622
+ switch (event.key) {
18623
+ case "ArrowLeft":
18624
+ "horizontal" === direction && (event.preventDefault(), slidePrev());
18625
+ break;
18626
+
18627
+ case "ArrowRight":
18628
+ "horizontal" === direction && (event.preventDefault(), slideNext());
18629
+ break;
18630
+
18631
+ case "ArrowUp":
18632
+ "vertical" === direction && (event.preventDefault(), slidePrev());
18633
+ break;
18634
+
18635
+ case "ArrowDown":
18636
+ "vertical" === direction && (event.preventDefault(), slideNext());
18637
+ }
18638
+ },
18639
+ role: "region",
18640
+ "aria-roledescription": "carousel",
18641
+ "aria-label": rest["aria-label"] || "Image slider",
18642
+ tabIndex: 0,
17452
18643
  children: [ jsxRuntime.jsx("div", {
17453
18644
  ref: wrapperRef,
17454
18645
  className: "c-slider__wrapper",
18646
+ "aria-live": autoplay ? "off" : "polite",
17455
18647
  style: {
17456
18648
  display: "flex",
17457
18649
  flexDirection: "vertical" === direction ? "column" : "row",
@@ -17629,15 +18821,24 @@ Steps.displayName = "Steps", Steps.Item = StepsItem, Steps.Step = StepsItem;
17629
18821
  // Context for compound usage
17630
18822
  const TabsContext = React.createContext({
17631
18823
  currentTab: 0,
17632
- handleTabClick: () => {}
17633
- }), TabsList = React.forwardRef((({children: children, className: className = "", ...props}, ref) => jsxRuntime.jsx("ul", {
17634
- ref: ref,
17635
- className: `c-tabs__nav ${className}`.trim(),
17636
- ...props,
17637
- children: React__default.default.Children.map(children, ((child, index) => React__default.default.isValidElement(child) ? React__default.default.cloneElement(child, {
17638
- index: index
17639
- }) : child))
17640
- })));
18824
+ handleTabClick: () => {},
18825
+ handleKeyDown: () => {},
18826
+ totalTabs: 0
18827
+ }), TabsList = React.forwardRef((({children: children, className: className = "", onKeyDown: onKeyDown, ...props}, ref) => {
18828
+ const {handleKeyDown: contextHandleKeyDown} = React.useContext(TabsContext), totalTabs = React__default.default.Children.count(children);
18829
+ return jsxRuntime.jsx("ul", {
18830
+ ref: ref,
18831
+ className: `c-tabs__nav ${className}`.trim(),
18832
+ role: "tablist",
18833
+ onKeyDown: e => {
18834
+ contextHandleKeyDown(e, totalTabs), onKeyDown?.(e);
18835
+ },
18836
+ ...props,
18837
+ children: React__default.default.Children.map(children, ((child, index) => React__default.default.isValidElement(child) ? React__default.default.cloneElement(child, {
18838
+ index: index
18839
+ }) : child))
18840
+ });
18841
+ }));
17641
18842
 
17642
18843
  // Compound components
17643
18844
  TabsList.displayName = "TabsList";
@@ -17649,8 +18850,10 @@ const TabsTrigger = React.forwardRef((({children: children, className: classNam
17649
18850
  const isActive = void 0 !== index && currentTab === index;
17650
18851
  return jsxRuntime.jsx("li", {
17651
18852
  className: "c-tabs__nav-item",
18853
+ role: "presentation",
17652
18854
  children: jsxRuntime.jsx("button", {
17653
18855
  ref: ref,
18856
+ id: `tab-nav-${index}`,
17654
18857
  className: `c-tabs__nav-btn ${isActive ? TAB.CLASSES.ACTIVE : ""} ${className}`.trim(),
17655
18858
  onClick: e => {
17656
18859
  void 0 !== index && handleTabClick(index), onClick?.(e);
@@ -17659,6 +18862,7 @@ const TabsTrigger = React.forwardRef((({children: children, className: classNam
17659
18862
  role: "tab",
17660
18863
  "aria-selected": isActive,
17661
18864
  "aria-controls": `tab-panel-${index}`,
18865
+ tabIndex: isActive ? 0 : -1,
17662
18866
  type: "button",
17663
18867
  ...props,
17664
18868
  children: children
@@ -17708,24 +18912,59 @@ TabsPanel.displayName = "TabsPanel";
17708
18912
  const Tabs = React.memo((({items: items, activeIndex: activeIndex = TAB.DEFAULTS.ACTIVE_INDEX, onTabChange: onTabChange, className: className = "", style: style, glass: glass, children: children}) => {
17709
18913
  const [currentTab, setCurrentTab] = React.useState(activeIndex), handleTabClick = index => {
17710
18914
  setCurrentTab(index), onTabChange && onTabChange(index);
18915
+ }, handleKeyDown = (event, totalTabs) => {
18916
+ let newIndex = currentTab;
18917
+ switch (event.key) {
18918
+ case "ArrowRight":
18919
+ newIndex = (currentTab + 1) % totalTabs;
18920
+ break;
18921
+
18922
+ case "ArrowLeft":
18923
+ newIndex = (currentTab - 1 + totalTabs) % totalTabs;
18924
+ break;
18925
+
18926
+ case "Home":
18927
+ newIndex = 0;
18928
+ break;
18929
+
18930
+ case "End":
18931
+ newIndex = totalTabs - 1;
18932
+ break;
18933
+
18934
+ default:
18935
+ return;
18936
+ }
18937
+ event.preventDefault(), handleTabClick(newIndex),
18938
+ // Focus the newly active tab after it renders
18939
+ setTimeout((() => {
18940
+ const tabElement = document.getElementById(`tab-nav-${newIndex}`);
18941
+ tabElement && tabElement.focus();
18942
+ }), 0);
17711
18943
  };
17712
18944
  // Handle tab change
17713
18945
  // Determine content based on mode (legacy items vs compound children)
17714
18946
  let content;
17715
18947
  // Use items prop if provided
17716
- // Legacy mode
17717
- content = items && items.length > 0 ? jsxRuntime.jsxs(jsxRuntime.Fragment, {
18948
+ if (items && items.length > 0)
18949
+ // Legacy mode
18950
+ content = jsxRuntime.jsxs(jsxRuntime.Fragment, {
17718
18951
  children: [ jsxRuntime.jsx("ul", {
17719
18952
  className: "c-tabs__nav",
18953
+ role: "tablist",
18954
+ onKeyDown: e => handleKeyDown(e, items.length),
17720
18955
  children: items.map(((item, index) => jsxRuntime.jsx("li", {
17721
18956
  className: "c-tabs__nav-item",
18957
+ role: "presentation",
17722
18958
  children: jsxRuntime.jsx("button", {
18959
+ id: `tab-nav-${index}`,
17723
18960
  className: `c-tabs__nav-btn ${index === currentTab ? TAB.CLASSES.ACTIVE : ""}`,
17724
18961
  onClick: () => handleTabClick(index),
17725
18962
  "data-tabindex": index,
17726
18963
  role: "tab",
17727
18964
  "aria-selected": index === currentTab,
17728
18965
  "aria-controls": `tab-panel-${index}`,
18966
+ tabIndex: index === currentTab ? 0 : -1,
18967
+ type: "button",
17729
18968
  children: item.label
17730
18969
  })
17731
18970
  }, `tab-nav-${index}`)))
@@ -17749,13 +18988,19 @@ const Tabs = React.memo((({items: items, activeIndex: activeIndex = TAB.DEFAULT
17749
18988
  })
17750
18989
  }, `tab-panel-${index}`)))
17751
18990
  }) ]
17752
- }) : jsxRuntime.jsx(TabsContext.Provider, {
17753
- value: {
17754
- currentTab: currentTab,
17755
- handleTabClick: handleTabClick
17756
- },
17757
- children: children
17758
- });
18991
+ }); else {
18992
+ // Compound mode
18993
+ const tabsList = React__default.default.Children.toArray(children).find((child => React__default.default.isValidElement(child) && "TabsList" === child.type.displayName)), totalTabsCount = tabsList ? React__default.default.Children.count(tabsList.props.children) : 0;
18994
+ content = jsxRuntime.jsx(TabsContext.Provider, {
18995
+ value: {
18996
+ currentTab: currentTab,
18997
+ handleTabClick: handleTabClick,
18998
+ handleKeyDown: handleKeyDown,
18999
+ totalTabs: totalTabsCount
19000
+ },
19001
+ children: children
19002
+ });
19003
+ }
17759
19004
  const wrapper = jsxRuntime.jsx("div", {
17760
19005
  className: `c-tabs js-atomix-tab ${className}`,
17761
19006
  style: style,
@@ -17846,7 +19091,7 @@ const Testimonial = ({quote: quote, author: author, size: size = "", skeleton: s
17846
19091
  className: "c-testimonial__author",
17847
19092
  children: [ author.avatarSrc && jsxRuntime.jsx("img", {
17848
19093
  src: author.avatarSrc,
17849
- alt: author.avatarAlt || "",
19094
+ alt: author.avatarAlt || `${author.name}'s avatar`,
17850
19095
  className: "c-testimonial__author-avatar c-avatar c-avatar--xxl c-avatar--circle"
17851
19096
  }), jsxRuntime.jsxs("div", {
17852
19097
  className: "c-testimonial__info",
@@ -18122,7 +19367,17 @@ const Tooltip = React.memo((({content: content, children: children, position: p
18122
19367
  cancelAnimationFrame(rafId), window.removeEventListener("resize", handleUpdate),
18123
19368
  window.removeEventListener("scroll", handleUpdate, !0);
18124
19369
  };
18125
- }), [ isVisible, updatePosition ]);
19370
+ }), [ isVisible, updatePosition ]),
19371
+ // Handle Escape key to close tooltip
19372
+ React.useEffect((() => {
19373
+ if (!isVisible) return;
19374
+ const handleKeyDown = event => {
19375
+ "Escape" === event.key && hideTooltip();
19376
+ };
19377
+ return document.addEventListener("keydown", handleKeyDown), () => {
19378
+ document.removeEventListener("keydown", handleKeyDown);
19379
+ };
19380
+ }), [ isVisible, hideTooltip ]);
18126
19381
  // Setup trigger props
18127
19382
  const triggerProps = {
18128
19383
  "aria-describedby": isVisible ? tooltipId : void 0
@@ -18811,9 +20066,15 @@ const VideoPlayer = React.forwardRef((({src: src, type: type = "video", youtube
18811
20066
  const rect = e.currentTarget.getBoundingClientRect(), percent = (e.clientX - rect.left) / rect.width;
18812
20067
  setVolume(percent);
18813
20068
  }), [ setVolume ]), handleDownload = React.useCallback((() => {
18814
- if (src) {
18815
- const a = document.createElement("a");
18816
- a.href = src, a.download = "video", a.click();
20069
+ if (src) try {
20070
+ var _context;
20071
+ const url = new URL(src, window.location.origin);
20072
+ if (_includesInstanceProperty(_context = [ "http:", "https:", "blob:", "data:" ]).call(_context, url.protocol)) {
20073
+ const a = document.createElement("a");
20074
+ a.href = url.href, a.download = "video", a.click();
20075
+ }
20076
+ } catch (e) {
20077
+ // Ignore invalid URLs
18817
20078
  }
18818
20079
  }), [ src ]), handleShare = React.useCallback((async () => {
18819
20080
  if (navigator.share) try {
@@ -19392,6 +20653,7 @@ var components = Object.freeze({
19392
20653
  TODO: TODO,
19393
20654
  TOGGLE: TOGGLE,
19394
20655
  TOOLTIP: TOOLTIP,
20656
+ TYPEDBUTTON: TYPEDBUTTON,
19395
20657
  UPLOAD: UPLOAD,
19396
20658
  VIDEO_PLAYER: VIDEO_PLAYER,
19397
20659
  sliderConstants: sliderConstants
@@ -25038,8 +26300,8 @@ exports.ACCORDION = ACCORDION, exports.ATOMIX_GLASS = ATOMIX_GLASS, exports.AVAT
25038
26300
  exports.AVATAR_GROUP = AVATAR_GROUP, exports.Accordion = Accordion, exports.AreaChart = AreaChart,
25039
26301
  exports.AtomixGlass = AtomixGlass, exports.AtomixLogo = AtomixLogo, exports.Avatar = Avatar,
25040
26302
  exports.AvatarGroup = AvatarGroup, exports.BADGE = BADGE, exports.BADGE_CSS_VARS = BADGE_CSS_VARS,
25041
- exports.BLOCK = BLOCK, exports.BREADCRUMB = BREADCRUMB, exports.BUTTON = BUTTON,
25042
- exports.BUTTON_CSS_VARS = BUTTON_CSS_VARS, exports.BUTTON_GROUP = BUTTON_GROUP,
26303
+ exports.BALANCED_PRESET = BALANCED_PRESET, exports.BLOCK = BLOCK, exports.BREADCRUMB = BREADCRUMB,
26304
+ exports.BUTTON = BUTTON, exports.BUTTON_CSS_VARS = BUTTON_CSS_VARS, exports.BUTTON_GROUP = BUTTON_GROUP,
25043
26305
  exports.Badge = Badge, exports.BarChart = BarChart, exports.Block = Block, exports.Breadcrumb = Breadcrumb,
25044
26306
  exports.BubbleChart = BubbleChart, exports.Button = Button, exports.ButtonGroup = ButtonGroup,
25045
26307
  exports.CALLOUT = CALLOUT, exports.CARD = CARD, exports.CARD_CSS_VARS = CARD_CSS_VARS,
@@ -25050,29 +26312,31 @@ exports.Card = Card, exports.Chart = Chart, exports.ChartRenderer = ChartRendere
25050
26312
  exports.Checkbox = Checkbox, exports.ColorModeToggle = ColorModeToggle, exports.Container = Container,
25051
26313
  exports.Countdown = Countdown, exports.DATA_TABLE_CLASSES = DATA_TABLE_CLASSES,
25052
26314
  exports.DATA_TABLE_SELECTORS = DATA_TABLE_SELECTORS, exports.DATEPICKER = DATEPICKER,
25053
- exports.DEFAULT_ATOMIX_FONTS = DEFAULT_ATOMIX_FONTS, exports.DOTS = "...", exports.DROPDOWN = DROPDOWN,
25054
- exports.DROPDOWN_CSS_VARS = DROPDOWN_CSS_VARS, exports.DataTable = DataTable, exports.DatePicker = DatePicker,
25055
- exports.DesignTokensCustomizer = DesignTokensCustomizer, exports.DonutChart = DonutChart,
25056
- exports.Dropdown = Dropdown, exports.EDGE_PANEL = EDGE_PANEL, exports.EdgePanel = EdgePanel,
25057
- exports.ElevationCard = ElevationCard, exports.FOOTER = FOOTER, exports.FORM = FORM,
25058
- exports.FORM_GROUP = FORM_GROUP, exports.Footer = Footer, exports.FooterLink = FooterLink,
25059
- exports.FooterSection = FooterSection, exports.FooterSocialLink = FooterSocialLink,
26315
+ exports.DEFAULT_ATOMIX_FONTS = DEFAULT_ATOMIX_FONTS, exports.DEFAULT_BREAKPOINTS = DEFAULT_BREAKPOINTS,
26316
+ exports.DROPDOWN = DROPDOWN, exports.DROPDOWN_CSS_VARS = DROPDOWN_CSS_VARS, exports.DataTable = DataTable,
26317
+ exports.DatePicker = DatePicker, exports.DesignTokensCustomizer = DesignTokensCustomizer,
26318
+ exports.DeviceDetector = DeviceDetector, exports.DonutChart = DonutChart, exports.Dropdown = Dropdown,
26319
+ exports.EDGE_PANEL = EDGE_PANEL, exports.EdgePanel = EdgePanel, exports.ElevationCard = ElevationCard,
26320
+ exports.FOOTER = FOOTER, exports.FORM = FORM, exports.FORM_GROUP = FORM_GROUP, exports.Footer = Footer,
26321
+ exports.FooterLink = FooterLink, exports.FooterSection = FooterSection, exports.FooterSocialLink = FooterSocialLink,
25060
26322
  exports.Form = Form, exports.FormGroup = FormGroup, exports.FunnelChart = FunnelChart,
25061
26323
  exports.GaugeChart = GaugeChart, exports.Grid = Grid, exports.GridCol = GridCol,
25062
26324
  exports.HERO = HERO, exports.HeatmapChart = HeatmapChart, exports.Hero = Hero, exports.INPUT = INPUT,
25063
26325
  exports.INPUT_CSS_VARS = INPUT_CSS_VARS, exports.Icon = Icon, exports.Input = Input,
25064
26326
  exports.LIST = LIST, exports.LIST_GROUP = LIST_GROUP, exports.LineChart = LineChart,
25065
26327
  exports.List = List, exports.ListGroup = ListGroup, exports.MESSAGES = MESSAGES,
25066
- exports.MODAL = MODAL, exports.MODAL_CSS_VARS = MODAL_CSS_VARS, exports.MasonryGrid = MasonryGrid,
25067
- exports.MasonryGridItem = MasonryGridItem, exports.MegaMenu = MegaMenu, exports.MegaMenuColumn = MegaMenuColumn,
25068
- exports.MegaMenuLink = MegaMenuLink, exports.Menu = Menu, exports.MenuDivider = MenuDivider,
25069
- exports.MenuItem = MenuItem, exports.Messages = Messages, exports.Modal = Modal,
25070
- exports.MultiAxisChart = MultiAxisChart, exports.NAV = NAV, exports.NAVBAR = NAVBAR,
25071
- exports.Nav = Nav, exports.NavDropdown = NavDropdown, exports.NavItem = NavItem,
25072
- exports.Navbar = Navbar, exports.PAGINATION_DEFAULTS = PAGINATION_DEFAULTS, exports.PHOTOVIEWER = PHOTOVIEWER,
26328
+ exports.MOBILE_OPTIMIZED_BREAKPOINTS = MOBILE_OPTIMIZED_BREAKPOINTS, exports.MODAL = MODAL,
26329
+ exports.MODAL_CSS_VARS = MODAL_CSS_VARS, exports.MasonryGrid = MasonryGrid, exports.MasonryGridItem = MasonryGridItem,
26330
+ exports.MegaMenu = MegaMenu, exports.MegaMenuColumn = MegaMenuColumn, exports.MegaMenuLink = MegaMenuLink,
26331
+ exports.Menu = Menu, exports.MenuDivider = MenuDivider, exports.MenuItem = MenuItem,
26332
+ exports.Messages = Messages, exports.Modal = Modal, exports.MultiAxisChart = MultiAxisChart,
26333
+ exports.NAV = NAV, exports.NAVBAR = NAVBAR, exports.Nav = Nav, exports.NavDropdown = NavDropdown,
26334
+ exports.NavItem = NavItem, exports.Navbar = Navbar, exports.PAGINATION_DEFAULTS = PAGINATION_DEFAULTS,
26335
+ exports.PERFORMANCE_PRESET = PERFORMANCE_PRESET, exports.PHOTOVIEWER = PHOTOVIEWER,
25073
26336
  exports.POPOVER = POPOVER, exports.PROGRESS = PROGRESS, exports.PROGRESS_CSS_VARS = PROGRESS_CSS_VARS,
25074
- exports.Pagination = Pagination, exports.PhotoViewer = PhotoViewer, exports.PieChart = PieChart,
25075
- exports.Popover = Popover, exports.ProductReview = ProductReview, exports.Progress = Progress,
26337
+ exports.Pagination = Pagination, exports.PerformanceOverlay = PerformanceOverlay,
26338
+ exports.PhotoViewer = PhotoViewer, exports.PieChart = PieChart, exports.Popover = Popover,
26339
+ exports.ProductReview = ProductReview, exports.Progress = Progress, exports.QUALITY_PRESET = QUALITY_PRESET,
25076
26340
  exports.RADIO = RADIO, exports.RADIO_CSS_VARS = RADIO_CSS_VARS, exports.RATING = RATING,
25077
26341
  exports.RIVER = RIVER, exports.RTLManager = RTLManager, exports.RadarChart = RadarChart,
25078
26342
  exports.Radio = Radio, exports.Rating = Rating, exports.River = River, exports.Row = Row,
@@ -25084,8 +26348,8 @@ exports.Slider = Slider, exports.Spinner = Spinner, exports.Steps = Steps, expor
25084
26348
  exports.TABS_CSS_VARS = TABS_CSS_VARS, exports.TESTIMONIAL = TESTIMONIAL, exports.TEXTAREA = TEXTAREA,
25085
26349
  exports.THEME_COLORS = THEME_COLORS, exports.THEME_NAMING = THEME_NAMING, exports.TODO = TODO,
25086
26350
  exports.TOGGLE = TOGGLE, exports.TOOLTIP = TOOLTIP, exports.TOOLTIP_CSS_VARS = TOOLTIP_CSS_VARS,
25087
- exports.Tabs = Tabs, exports.Testimonial = Testimonial, exports.Textarea = Textarea,
25088
- exports.ThemeApplicator = ThemeApplicator, exports.ThemeComparator = ThemeComparator,
26351
+ exports.TYPEDBUTTON = TYPEDBUTTON, exports.Tabs = Tabs, exports.Testimonial = Testimonial,
26352
+ exports.Textarea = Textarea, exports.ThemeApplicator = ThemeApplicator, exports.ThemeComparator = ThemeComparator,
25089
26353
  exports.ThemeContext = ThemeContext, exports.ThemeErrorBoundary = ThemeErrorBoundary,
25090
26354
  exports.ThemeInspector = ThemeInspector, exports.ThemeLiveEditor = ThemeLiveEditor,
25091
26355
  exports.ThemePreview = ThemePreview, exports.ThemeProvider = ThemeProvider, exports.ThemeValidator = ThemeValidator,
@@ -25158,8 +26422,8 @@ function(cssVars, baseStyle) {
25158
26422
  * ```
25159
26423
  */ , exports.applyComponentTheme = applyComponentTheme, exports.applyPartStyles = applyPartStyles,
25160
26424
  exports.applyTheme = applyTheme, exports.camelToKebab = camelToKebab, exports.clearThemes = clearThemes,
25161
- exports.composables = composables, exports.constants = constants, exports.createCSSVarStyle = createCSSVarStyle,
25162
- exports.createDarkVariant =
26425
+ exports.composables = composables, exports.constants = constants, exports.createBreakpoints = createBreakpoints$1,
26426
+ exports.createCSSVarStyle = createCSSVarStyle, exports.createDarkVariant =
25163
26427
  /**
25164
26428
  * Create a dark theme variant from a light theme
25165
26429
  */
@@ -25277,7 +26541,9 @@ exports.getAllThemes = getAllThemes, exports.getCSSVariable = getCSSVariable, ex
25277
26541
  */
25278
26542
  function(component) {
25279
26543
  return COMPONENT_CSS_VARS[component];
25280
- }, exports.getComponentThemeValue = getComponentThemeValue, exports.getPartStyles = getPartStyles,
26544
+ }, exports.getComponentThemeValue = getComponentThemeValue, exports.getDefaultBreakpoints = getDefaultBreakpoints,
26545
+ exports.getDevicePreset = getDevicePreset, exports.getMobileOptimizedParams = getMobileOptimizedParams,
26546
+ exports.getPartStyles = getPartStyles, exports.getQualityMultipliers = getQualityMultipliers,
25281
26547
  exports.getTheme = getTheme, exports.getThemeApplicator = getThemeApplicator, exports.getThemeCount = getThemeCount,
25282
26548
  exports.getThemeIds = getThemeIds, exports.getThemeMetadata =
25283
26549
  /**
@@ -25359,8 +26625,7 @@ function(theme, selector = ":root") {
25359
26625
  });
25360
26626
  }, exports.types = types, exports.unregisterTheme = unregisterTheme, exports.useAccordion = useAccordion,
25361
26627
  exports.useAtomixGlass = useAtomixGlass, exports.useBadge = useBadge, exports.useBarChart = useBarChart,
25362
- exports.useBlock = useBlock, exports.useBreadcrumb = useBreadcrumb, exports.useCard = useCard,
25363
- exports.useChartData = useChartData, exports.useChartInteraction = useChartInteraction,
26628
+ exports.useBlock = useBlock, exports.useChartData = useChartData, exports.useChartInteraction = useChartInteraction,
25364
26629
  exports.useChartScale = useChartScale, exports.useComponentCustomization =
25365
26630
  /**
25366
26631
  * Hook to merge theme overrides with component props
@@ -25409,19 +26674,19 @@ function(component, props) {
25409
26674
  }
25410
26675
  /**
25411
26676
  * Hook to merge default props with provided props
25412
- */ , exports.useComponentTheme = useComponentTheme, exports.useDataTable = useDataTable,
25413
- exports.useEdgePanel = useEdgePanel, exports.useForm = useForm, exports.useFormGroup = useFormGroup,
25414
- exports.useHero = useHero, exports.useHistory = useHistory, exports.useInput = useInput,
25415
- exports.useLineChart = useLineChart, exports.useMergedProps = function(defaultProps, props) {
26677
+ */ , exports.useComponentTheme = useComponentTheme, exports.useEdgePanel = useEdgePanel,
26678
+ exports.useForm = useForm, exports.useFormGroup = useFormGroup, exports.useHero = useHero,
26679
+ exports.useHistory = useHistory, exports.useInput = useInput, exports.useLineChart = useLineChart,
26680
+ exports.useMergedProps = function(defaultProps, props) {
25416
26681
  return React.useMemo((() => ({
25417
26682
  ...defaultProps,
25418
26683
  ...props
25419
26684
  })), [ defaultProps, props ]);
25420
- }, exports.useModal = useModal$1, exports.useNav = useNav, exports.useNavDropdown = useNavDropdown,
25421
- exports.useNavItem = useNavItem, exports.useNavbar = useNavbar, exports.usePagination = usePagination,
25422
- exports.usePieChart = usePieChart, exports.useRadio = useRadio, exports.useRiver = useRiver,
25423
- exports.useSelect = useSelect, exports.useSideMenu = useSideMenu, exports.useSideMenuItem = useSideMenuItem,
25424
- exports.useSlider = useSlider, exports.useSlot = function(slot, props, fallback) {
26685
+ }, exports.useNav = useNav, exports.useNavDropdown = useNavDropdown, exports.useNavItem = useNavItem,
26686
+ exports.useNavbar = useNavbar, exports.usePerformanceMonitor = usePerformanceMonitor,
26687
+ exports.usePieChart = usePieChart, exports.useRadio = useRadio, exports.useResponsiveGlass = useResponsiveGlass,
26688
+ exports.useRiver = useRiver, exports.useSelect = useSelect, exports.useSideMenu = useSideMenu,
26689
+ exports.useSideMenuItem = useSideMenuItem, exports.useSlot = function(slot, props, fallback) {
25425
26690
  return React__default.default.useMemo((() => renderSlot(slot, props, fallback)), [ slot, props, fallback ]);
25426
26691
  }, exports.useSpinner = useSpinner, exports.useTextarea = useTextarea, exports.useTheme = useTheme,
25427
26692
  exports.useThemeTokens = useThemeTokens, exports.useTodo = useTodo, exports.utils = utils,