@shohojdhara/atomix 0.4.5 → 0.4.7

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 (54) hide show
  1. package/dist/atomix.css +70 -33
  2. package/dist/atomix.css.map +1 -1
  3. package/dist/atomix.min.css +2 -2
  4. package/dist/atomix.min.css.map +1 -1
  5. package/dist/charts.d.ts +93 -109
  6. package/dist/charts.js +273 -371
  7. package/dist/charts.js.map +1 -1
  8. package/dist/core.js +183 -184
  9. package/dist/core.js.map +1 -1
  10. package/dist/forms.js +183 -184
  11. package/dist/forms.js.map +1 -1
  12. package/dist/heavy.js +183 -184
  13. package/dist/heavy.js.map +1 -1
  14. package/dist/index.d.ts +7 -51
  15. package/dist/index.esm.js +281 -470
  16. package/dist/index.esm.js.map +1 -1
  17. package/dist/index.js +287 -476
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.min.js +1 -1
  20. package/dist/index.min.js.map +1 -1
  21. package/package.json +1 -1
  22. package/src/components/AtomixGlass/AtomixGlass.tsx +60 -38
  23. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +6 -35
  24. package/src/components/AtomixGlass/glass-utils.ts +27 -14
  25. package/src/components/AtomixGlass/stories/Overview.stories.tsx +19 -21
  26. package/src/components/AtomixGlass/stories/Playground.stories.tsx +1162 -515
  27. package/src/components/AtomixGlass/stories/shared-components.tsx +11 -3
  28. package/src/components/Chart/BubbleChart.tsx +6 -2
  29. package/src/components/Chart/Chart.stories.tsx +108 -96
  30. package/src/components/Chart/ChartToolbar.tsx +6 -4
  31. package/src/components/Chart/ChartTooltip.tsx +5 -4
  32. package/src/components/Chart/GaugeChart.tsx +20 -12
  33. package/src/components/Chart/HeatmapChart.tsx +53 -23
  34. package/src/components/Chart/TreemapChart.tsx +44 -15
  35. package/src/components/Chart/index.ts +0 -2
  36. package/src/components/Chart/types.ts +4 -4
  37. package/src/components/Navigation/Navbar/Navbar.tsx +13 -5
  38. package/src/components/index.ts +0 -1
  39. package/src/lib/composables/index.ts +1 -2
  40. package/src/lib/composables/useAtomixGlass.ts +246 -222
  41. package/src/lib/composables/useAtomixGlassStyles.ts +46 -23
  42. package/src/lib/constants/components.ts +3 -1
  43. package/src/styles/01-settings/_settings.chart.scss +13 -13
  44. package/src/styles/06-components/_components.atomix-glass.scss +45 -20
  45. package/src/styles/06-components/_components.chart.scss +23 -5
  46. package/src/components/Chart/AnimatedChart.tsx +0 -230
  47. package/src/lib/composables/atomix-glass/useGlassBackgroundDetection.ts +0 -329
  48. package/src/lib/composables/atomix-glass/useGlassCornerRadius.ts +0 -82
  49. package/src/lib/composables/atomix-glass/useGlassMouseTracking.ts +0 -153
  50. package/src/lib/composables/atomix-glass/useGlassOverLight.ts +0 -198
  51. package/src/lib/composables/atomix-glass/useGlassState.ts +0 -112
  52. package/src/lib/composables/atomix-glass/useGlassTransforms.ts +0 -160
  53. package/src/lib/composables/glass-styles.ts +0 -302
  54. package/src/lib/composables/useGlassContainer.ts +0 -177
package/dist/charts.js CHANGED
@@ -510,7 +510,9 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
510
510
  ENABLE_OVER_LIGHT_LAYERS: !0
511
511
  },
512
512
  CONSTANTS: {
513
- ACTIVATION_ZONE: 200,
513
+ ACTIVATION_ZONE: 350,
514
+ LERP_FACTOR: .08,
515
+ SMOOTHSTEP_POWER: 2.5,
514
516
  MIN_BLUR: .1,
515
517
  MOUSE_INFLUENCE_DIVISOR: 100,
516
518
  EDGE_FADE_PIXELS: 2,
@@ -1146,7 +1148,7 @@ const ChartToolbar = memo( forwardRef((({chartType: chartType = "line", groups:
1146
1148
  pan: !0,
1147
1149
  reset: !0
1148
1150
  }, exportFormats: exportFormats = [ "png", "svg", "csv" ], size: size = "md", position: position = "top", onRefresh: onRefresh, onExport: onExport, onFullscreen: onFullscreen, onSettings: onSettings, onZoomIn: onZoomIn, onZoomOut: onZoomOut, onZoomReset: onZoomReset, onPanToggle: onPanToggle, onReset: onReset, onGridToggle: onGridToggle, onLegendToggle: onLegendToggle, onTooltipsToggle: onTooltipsToggle, onAnimationsToggle: onAnimationsToggle, state: state = {}, className: className = "", ...props}, ref) => {
1149
- const [showExportMenu, setShowExportMenu] = useState(!1), [showSettingsMenu, setShowSettingsMenu] = useState(!1), exportMenuRef = useRef(null), settingsMenuRef = useRef(null), exportButtonRef = useRef(null), settingsButtonRef = useRef(null), effectiveDefaults = groups && groups.length > 0 ? {
1151
+ const [showExportMenu, setShowExportMenu] = useState(!1), [showSettingsMenu, setShowSettingsMenu] = useState(!1), exportMenuRef = useRef(null), settingsMenuRef = useRef(null), exportButtonRef = useRef(null), settingsButtonRef = useRef(null), effectiveDefaults = useMemo((() => groups && groups.length > 0 ? {
1150
1152
  refresh: defaults.refresh ?? !0,
1151
1153
  export: defaults.export ?? !0,
1152
1154
  fullscreen: defaults.fullscreen ?? !0,
@@ -1158,7 +1160,7 @@ const ChartToolbar = memo( forwardRef((({chartType: chartType = "line", groups:
1158
1160
  legend: defaults.legend ?? !0,
1159
1161
  tooltips: defaults.tooltips ?? !0,
1160
1162
  animations: defaults.animations ?? !0
1161
- } : defaults;
1163
+ } : defaults), [ groups, defaults ]);
1162
1164
  // Close menus when clicking outside
1163
1165
  useEffect((() => {
1164
1166
  const handleClickOutside = event => {
@@ -1600,7 +1602,7 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateDistance = (pos1, pos2)
1600
1602
  // Silently handle errors
1601
1603
  }
1602
1604
  return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
1603
- }, getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
1605
+ }, 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) => {
1604
1606
  switch (mode) {
1605
1607
  case "standard":
1606
1608
  return displacementMap;
@@ -1958,20 +1960,12 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
1958
1960
  onClick: onClick,
1959
1961
  children: jsxs("div", {
1960
1962
  className: ATOMIX_GLASS.INNER_CLASS,
1961
- style: {
1962
- padding: "var(--atomix-glass-container-padding)",
1963
- boxShadow: "var(--atomix-glass-container-box-shadow)"
1964
- },
1965
1963
  onMouseEnter: onMouseEnter,
1966
1964
  onMouseLeave: onMouseLeave,
1967
1965
  onMouseDown: onMouseDown,
1968
1966
  onMouseUp: onMouseUp,
1969
1967
  children: [ jsxs("div", {
1970
1968
  className: ATOMIX_GLASS.FILTER_CLASS,
1971
- style: {
1972
- position: "absolute",
1973
- inset: 0
1974
- },
1975
1969
  children: [ jsx(GlassFilter, {
1976
1970
  blurAmount: blurAmount,
1977
1971
  mode: mode,
@@ -1986,26 +1980,14 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
1986
1980
  },
1987
1981
  className: ATOMIX_GLASS.FILTER_OVERLAY_CLASS,
1988
1982
  style: {
1989
- filter: `url(#${filterId})`,
1990
- backdropFilter: "var(--atomix-glass-container-backdrop)",
1991
- borderRadius: "var(--atomix-glass-container-radius)"
1983
+ filter: `url(#${filterId})`
1992
1984
  }
1993
1985
  }), jsx("div", {
1994
- className: ATOMIX_GLASS.FILTER_SHADOW_CLASS,
1995
- style: {
1996
- boxShadow: "var(--atomix-glass-container-shadow)",
1997
- opacity: "var(--atomix-glass-container-shadow-opacity)",
1998
- background: "var(--atomix-glass-container-bg)",
1999
- borderRadius: "var(--atomix-glass-container-radius)"
2000
- }
1986
+ className: ATOMIX_GLASS.FILTER_SHADOW_CLASS
2001
1987
  }) ]
2002
1988
  }), jsx("div", {
2003
1989
  ref: contentRef,
2004
1990
  className: ATOMIX_GLASS.CONTENT_CLASS,
2005
- style: {
2006
- position: "relative",
2007
- textShadow: "var(--atomix-glass-container-text-shadow)"
2008
- },
2009
1991
  children: children
2010
1992
  }) ]
2011
1993
  })
@@ -2109,31 +2091,39 @@ class {
2109
2091
  saturationBoost: baseOverLightConfig.saturationBoost
2110
2092
  };
2111
2093
  // Calculate mouse influence
2112
- // Calculate elastic translation
2113
- let elasticTranslation = {
2094
+ let computedDirectionalScale = directionalScale, elasticTranslation = {
2114
2095
  x: 0,
2115
2096
  y: 0
2116
2097
  };
2117
- if (!effectiveWithoutEffects && wrapperElement) {
2098
+ // Calculate elastic translation and directional scale
2099
+ if (!effectiveWithoutEffects && wrapperElement) {
2118
2100
  const rect = wrapperElement.getBoundingClientRect(), center = calculateElementCenter(rect);
2119
- // Calculate fade in factor
2120
- let fadeInFactor = 0;
2101
+ // Mouse presence and edge distance logic
2121
2102
  if (globalMousePosition.x && globalMousePosition.y && validateGlassSize(glassSize)) {
2122
- const edgeDistanceX = Math.max(0, Math.abs(globalMousePosition.x - center.x) - glassSize.width / 2), edgeDistanceY = Math.max(0, Math.abs(globalMousePosition.y - center.y) - glassSize.height / 2), edgeDistance = calculateDistance({
2103
+ const deltaX = globalMousePosition.x - center.x, deltaY = globalMousePosition.y - center.y, edgeDistanceX = Math.max(0, Math.abs(deltaX) - glassSize.width / 2), edgeDistanceY = Math.max(0, Math.abs(deltaY) - glassSize.height / 2), edgeDistance = calculateDistance({
2123
2104
  x: edgeDistanceX,
2124
2105
  y: edgeDistanceY
2125
2106
  }, {
2126
2107
  x: 0,
2127
2108
  y: 0
2128
- });
2129
- fadeInFactor = edgeDistance > ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE ? 0 : 1 - edgeDistance / ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE;
2109
+ }), rawT = edgeDistance > ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE ? 0 : 1 - edgeDistance / ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE, fadeInFactor = (t => {
2110
+ const clamped = Math.max(0, Math.min(1, t));
2111
+ return clamped * clamped * (3 - 2 * clamped);
2112
+ })(rawT);
2113
+ // Directional scale
2114
+ if (elasticTranslation = {
2115
+ x: deltaX * elasticity * .1 * fadeInFactor,
2116
+ y: deltaY * elasticity * .1 * fadeInFactor
2117
+ }, !isOverLight && edgeDistance <= ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE) {
2118
+ const centerDistance = calculateDistance(globalMousePosition, center);
2119
+ if (centerDistance > 0) {
2120
+ const normalizedX = deltaX / centerDistance, normalizedY = deltaY / centerDistance, stretchIntensity = Math.min(centerDistance / 300, 1) * elasticity * rawT, scaleX = 1 + Math.abs(normalizedX) * stretchIntensity * .3 - Math.abs(normalizedY) * stretchIntensity * .15, scaleY = 1 + Math.abs(normalizedY) * stretchIntensity * .3 - Math.abs(normalizedX) * stretchIntensity * .15, softScaleX = 1 - softClamp(Math.max(0, 1 - scaleX), .2), softScaleY = 1 - softClamp(Math.max(0, 1 - scaleY), .2);
2121
+ computedDirectionalScale = `scaleX(${Math.max(.85, softScaleX)}) scaleY(${Math.max(.85, softScaleY)})`;
2122
+ }
2123
+ }
2130
2124
  }
2131
- elasticTranslation = {
2132
- x: (globalMousePosition.x - center.x) * elasticity * .1 * fadeInFactor,
2133
- y: (globalMousePosition.y - center.y) * elasticity * .1 * fadeInFactor
2134
- };
2135
2125
  }
2136
- const transformStyle = effectiveWithoutEffects ? isActive && Boolean(onClick) ? "scale(0.98)" : "scale(1)" : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) ${isActive && Boolean(onClick) ? "scale(0.96)" : directionalScale}`;
2126
+ const transformStyle = effectiveWithoutEffects ? isActive && Boolean(onClick) ? "scale(0.98)" : "scale(1)" : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) ${isActive && Boolean(onClick) ? "scale(0.96)" : computedDirectionalScale}`;
2137
2127
  // Update Wrapper Styles (glassVars)
2138
2128
  if (wrapperElement) {
2139
2129
  const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, borderGradientAngle = GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER, borderStop1 = Math.max(GRADIENT.BORDER_STOP_1.MIN, GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER), borderStop2 = Math.min(GRADIENT.BORDER_STOP_2.MAX, GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER), borderOpacities = [ GRADIENT.BORDER_OPACITY.BASE_1 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, GRADIENT.BORDER_OPACITY.BASE_2 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH, GRADIENT.BORDER_OPACITY.BASE_3 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, GRADIENT.BORDER_OPACITY.BASE_4 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH ], configBorderOpacity = overLightConfig.borderOpacity, whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, hoverPositions = {
@@ -2240,7 +2230,13 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2240
2230
  }), internalMouseOffsetRef = useRef({
2241
2231
  x: 0,
2242
2232
  y: 0
2243
- }), [dynamicBorderRadius, setDynamicCornerRadius] = useState(CONSTANTS.DEFAULT_CORNER_RADIUS), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1), effectiveBorderRadius = useMemo((() => void 0 !== borderRadius ? Math.max(0, borderRadius) : Math.max(0, dynamicBorderRadius)), [ borderRadius, dynamicBorderRadius ]), {glassSize: glassSize} = function({glassRef: glassRef, effectiveBorderRadius: effectiveBorderRadius, cachedRectRef: cachedRectRef}) {
2233
+ }), targetMouseOffsetRef = useRef({
2234
+ x: 0,
2235
+ y: 0
2236
+ }), targetGlobalMousePositionRef = useRef({
2237
+ x: 0,
2238
+ y: 0
2239
+ }), lerpRafRef = useRef(null), lerpActiveRef = useRef(!1), [dynamicBorderRadius, setDynamicCornerRadius] = useState(CONSTANTS.DEFAULT_CORNER_RADIUS), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1), effectiveBorderRadius = useMemo((() => void 0 !== borderRadius ? Math.max(0, borderRadius) : Math.max(0, dynamicBorderRadius)), [ borderRadius, dynamicBorderRadius ]), {glassSize: glassSize} = function({glassRef: glassRef, effectiveBorderRadius: effectiveBorderRadius, cachedRectRef: cachedRectRef}) {
2244
2240
  const [glassSize, setGlassSize] = useState({
2245
2241
  width: 270,
2246
2242
  height: 69
@@ -2337,7 +2333,23 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2337
2333
  const timeoutId = setTimeout(extractRadius, 100);
2338
2334
  return () => clearTimeout(timeoutId);
2339
2335
  }), [ children, debugBorderRadius, contentRef ]),
2340
- // Media query handlers and background detection
2336
+ // Media query detection for reduced motion and high contrast
2337
+ useEffect((() => {
2338
+ if ("undefined" == typeof window || "function" != typeof window.matchMedia) return;
2339
+ const mediaQueryReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)"), mediaQueryHighContrast = window.matchMedia("(prefers-contrast: high)");
2340
+ setUserPrefersReducedMotion(mediaQueryReducedMotion.matches), setUserPrefersHighContrast(mediaQueryHighContrast.matches);
2341
+ const handleReducedMotionChange = e => {
2342
+ setUserPrefersReducedMotion(e.matches);
2343
+ }, handleHighContrastChange = e => {
2344
+ setUserPrefersHighContrast(e.matches);
2345
+ };
2346
+ return mediaQueryReducedMotion.addEventListener("change", handleReducedMotionChange),
2347
+ mediaQueryHighContrast.addEventListener("change", handleHighContrastChange), () => {
2348
+ mediaQueryReducedMotion.removeEventListener("change", handleReducedMotionChange),
2349
+ mediaQueryHighContrast.removeEventListener("change", handleHighContrastChange);
2350
+ };
2351
+ }), []),
2352
+ // Background detection for overLight auto-detect
2341
2353
  useEffect((() => {
2342
2354
  if (("auto" === overLight || "object" == typeof overLight && null !== overLight) && glassRef.current) {
2343
2355
  const element = glassRef.current, cachedResult = ((parentElement, overLightConfig) => {
@@ -2437,102 +2449,36 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2437
2449
  }), 150);
2438
2450
  return () => clearTimeout(timeoutId);
2439
2451
  }
2440
- if ("boolean" == typeof overLight && setDetectedOverLight(!1), "function" == typeof window.matchMedia) try {
2441
- const mediaQueryReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)"), mediaQueryHighContrast = window.matchMedia("(prefers-contrast: high)");
2442
- setUserPrefersReducedMotion(mediaQueryReducedMotion.matches), setUserPrefersHighContrast(mediaQueryHighContrast.matches);
2443
- const handleReducedMotionChange = e => {
2444
- setUserPrefersReducedMotion(e.matches);
2445
- }, handleHighContrastChange = e => {
2446
- setUserPrefersHighContrast(e.matches);
2447
- };
2448
- return mediaQueryReducedMotion.addEventListener ? (mediaQueryReducedMotion.addEventListener("change", handleReducedMotionChange),
2449
- mediaQueryHighContrast.addEventListener("change", handleHighContrastChange)) : mediaQueryReducedMotion.addListener && (mediaQueryReducedMotion.addListener(handleReducedMotionChange),
2450
- mediaQueryHighContrast.addListener(handleHighContrastChange)), () => {
2451
- // ignore
2452
- };
2453
- } catch (error) {
2454
- return;
2455
- }
2456
- }), [ overLight, glassRef, debugOverLight ]);
2452
+ "boolean" == typeof overLight && setDetectedOverLight(!1);
2453
+ }), [ overLight, glassRef ]);
2457
2454
  /**
2458
2455
  * Get effective overLight value based on configuration
2459
2456
  */
2460
- const getEffectiveOverLight = useCallback((() => "boolean" == typeof overLight ? overLight : ("auto" === overLight || "object" == typeof overLight && null !== overLight) && detectedOverLight), [ overLight, detectedOverLight ]), validateConfigValue = useCallback(((value, min, max, defaultValue) => "number" != typeof value || isNaN(value) || !isFinite(value) ? defaultValue : Math.min(max, Math.max(min, value))), []), baseOverLightConfig = useMemo((() => {
2461
- const isOverLight = getEffectiveOverLight(), baseConfig = {
2457
+ const getEffectiveOverLight = useCallback((() => "boolean" == typeof overLight ? overLight : ("auto" === overLight || "object" == typeof overLight && null !== overLight) && detectedOverLight), [ overLight, detectedOverLight ]), validateConfigValue = useCallback(((value, min, max, defaultValue) => "number" != typeof value || isNaN(value) || !isFinite(value) ? defaultValue : Math.min(max, Math.max(min, value))), []), overLightConfig = useMemo((() => {
2458
+ const isOverLight = getEffectiveOverLight(), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1, baseConfig = {
2462
2459
  isOverLight: isOverLight,
2463
2460
  threshold: .7,
2464
- opacity: isOverLight ? Math.min(.6, Math.max(.2, .5)) : 0,
2465
- contrast: 1,
2466
- // Base contrast
2467
- brightness: 1,
2468
- // Base brightness
2461
+ opacity: isOverLight ? Math.min(.6, Math.max(.2, .5 * hoverIntensity * activeIntensity)) : 0,
2462
+ contrast: 1.4,
2463
+ brightness: .9,
2469
2464
  saturationBoost: 1.3,
2465
+ // Fixed value — dynamic saturation amplifies perceived displacement
2470
2466
  shadowIntensity: .9,
2471
2467
  borderOpacity: .7
2472
2468
  };
2473
2469
  if ("object" == typeof overLight && null !== overLight) {
2474
- const objConfig = overLight, validatedThreshold = validateConfigValue(objConfig.threshold, .1, 1, baseConfig.threshold), validatedOpacity = validateConfigValue(objConfig.opacity, .1, 1, baseConfig.opacity), validatedContrast = validateConfigValue(objConfig.contrast, .5, 2.5, baseConfig.contrast), validatedBrightness = validateConfigValue(objConfig.brightness, .5, 2, baseConfig.brightness), validatedSaturationBoost = validateConfigValue(objConfig.saturationBoost, .5, 3, baseConfig.saturationBoost);
2475
- return {
2470
+ const objConfig = overLight, validatedThreshold = validateConfigValue(objConfig.threshold, .1, 1, baseConfig.threshold), validatedOpacity = validateConfigValue(objConfig.opacity, .1, 1, baseConfig.opacity), validatedContrast = validateConfigValue(objConfig.contrast, .5, 2.5, baseConfig.contrast), validatedBrightness = validateConfigValue(objConfig.brightness, .5, 2, baseConfig.brightness), validatedSaturationBoost = validateConfigValue(objConfig.saturationBoost, .5, 3, baseConfig.saturationBoost), finalConfig = {
2476
2471
  ...baseConfig,
2477
2472
  threshold: validatedThreshold,
2478
- opacity: validatedOpacity,
2473
+ opacity: validatedOpacity * hoverIntensity * activeIntensity,
2479
2474
  contrast: validatedContrast,
2480
2475
  brightness: validatedBrightness,
2481
2476
  saturationBoost: validatedSaturationBoost
2482
2477
  };
2478
+ return "undefined" == typeof process || process.env, finalConfig;
2483
2479
  }
2484
- return baseConfig;
2485
- }), [ overLight, getEffectiveOverLight, validateConfigValue ]), overLightConfig = useMemo((() => {
2486
- const mouseInfluence = calculateMouseInfluence(mouseOffset), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1;
2487
- return {
2488
- isOverLight: baseOverLightConfig.isOverLight,
2489
- threshold: baseOverLightConfig.threshold,
2490
- opacity: baseOverLightConfig.opacity * hoverIntensity * activeIntensity,
2491
- contrast: Math.min(1.6, baseOverLightConfig.contrast + .1 * mouseInfluence),
2492
- brightness: Math.min(1.1, baseOverLightConfig.brightness + .05 * mouseInfluence),
2493
- saturationBoost: baseOverLightConfig.saturationBoost,
2494
- shadowIntensity: Math.min(1.2, Math.max(.5, baseOverLightConfig.shadowIntensity + .2 * mouseInfluence)),
2495
- borderOpacity: Math.min(1, Math.max(.3, baseOverLightConfig.borderOpacity + .1 * mouseInfluence))
2496
- };
2497
- }), [ baseOverLightConfig, mouseOffset, isHovered, isActive ]), updateRectRef = useRef(null), calculateDirectionalScale = useCallback((() => {
2498
- if (baseOverLightConfig.isOverLight) return "scale(1)";
2499
- if (!(globalMousePosition.x && globalMousePosition.y && glassRef.current && validateGlassSize(glassSize))) return "scale(1)";
2500
- const rect = glassRef.current.getBoundingClientRect(), center = calculateElementCenter(rect), deltaX = globalMousePosition.x - center.x, deltaY = globalMousePosition.y - center.y, edgeDistanceX = Math.max(0, Math.abs(deltaX) - glassSize.width / 2), edgeDistanceY = Math.max(0, Math.abs(deltaY) - glassSize.height / 2), edgeDistance = calculateDistance({
2501
- x: edgeDistanceX,
2502
- y: edgeDistanceY
2503
- }, {
2504
- x: 0,
2505
- y: 0
2506
- });
2507
- if (edgeDistance > CONSTANTS.ACTIVATION_ZONE) return "scale(1)";
2508
- const fadeInFactor = 1 - edgeDistance / CONSTANTS.ACTIVATION_ZONE, centerDistance = calculateDistance(globalMousePosition, center);
2509
- if (0 === centerDistance) return "scale(1)";
2510
- const normalizedX = deltaX / centerDistance, normalizedY = deltaY / centerDistance, stretchIntensity = Math.min(centerDistance / 300, 1) * elasticity * fadeInFactor, scaleX = 1 + Math.abs(normalizedX) * stretchIntensity * .3 - Math.abs(normalizedY) * stretchIntensity * .15, scaleY = 1 + Math.abs(normalizedY) * stretchIntensity * .3 - Math.abs(normalizedX) * stretchIntensity * .15;
2511
- return `scaleX(${Math.max(.8, scaleX)}) scaleY(${Math.max(.8, scaleY)})`;
2512
- }), [ globalMousePosition, elasticity, glassSize, glassRef, baseOverLightConfig ]), calculateFadeInFactor = useCallback((() => {
2513
- if (!(globalMousePosition.x && globalMousePosition.y && glassRef.current && validateGlassSize(glassSize))) return 0;
2514
- const rect = glassRef.current.getBoundingClientRect(), center = calculateElementCenter(rect), edgeDistanceX = Math.max(0, Math.abs(globalMousePosition.x - center.x) - glassSize.width / 2), edgeDistanceY = Math.max(0, Math.abs(globalMousePosition.y - center.y) - glassSize.height / 2), edgeDistance = calculateDistance({
2515
- x: edgeDistanceX,
2516
- y: edgeDistanceY
2517
- }, {
2518
- x: 0,
2519
- y: 0
2520
- });
2521
- return edgeDistance > CONSTANTS.ACTIVATION_ZONE ? 0 : 1 - edgeDistance / CONSTANTS.ACTIVATION_ZONE;
2522
- }), [ globalMousePosition, glassSize, glassRef ]), calculateElasticTranslation = useCallback((() => {
2523
- if (!glassRef.current) return {
2524
- x: 0,
2525
- y: 0
2526
- };
2527
- const fadeInFactor = calculateFadeInFactor(), rect = glassRef.current.getBoundingClientRect(), center = calculateElementCenter(rect);
2528
- return {
2529
- x: (globalMousePosition.x - center.x) * elasticity * .1 * fadeInFactor,
2530
- y: (globalMousePosition.y - center.y) * elasticity * .1 * fadeInFactor
2531
- };
2532
- }), [ globalMousePosition, elasticity, calculateFadeInFactor, glassRef ]), elasticTranslation = useMemo((() => effectiveWithoutEffects ? {
2533
- x: 0,
2534
- y: 0
2535
- } : calculateElasticTranslation()), [ calculateElasticTranslation, effectiveWithoutEffects ]), directionalScale = useMemo((() => effectiveWithoutEffects ? "scale(1)" : calculateDirectionalScale()), [ calculateDirectionalScale, effectiveWithoutEffects ]), transformStyle = useMemo((() => effectiveWithoutEffects ? isActive && Boolean(onClick) ? "scale(0.98)" : "scale(1)" : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) ${isActive && Boolean(onClick) ? "scale(0.96)" : directionalScale}`), [ elasticTranslation, isActive, onClick, directionalScale, effectiveWithoutEffects ]), handleGlobalMousePosition = useCallback((globalPos => {
2480
+ return "undefined" == typeof process || process.env, baseConfig;
2481
+ }), [ overLight, getEffectiveOverLight, isHovered, isActive, validateConfigValue, debugOverLight ]), transformStyle = useMemo((() => effectiveWithoutEffects || isActive && Boolean(onClick) ? "scale(0.98)" : "scale(1)"), [ effectiveWithoutEffects, isActive, onClick ]), updateRectRef = useRef(null), handleGlobalMousePosition = useCallback((globalPos => {
2536
2482
  if (externalGlobalMousePosition && externalMouseOffset) return;
2537
2483
  if (effectiveWithoutEffects) return;
2538
2484
  const container = mouseContainer?.current || glassRef.current;
@@ -2541,35 +2487,61 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2541
2487
  let rect = cachedRectRef.current;
2542
2488
  if (rect && 0 !== rect.width && 0 !== rect.height || (rect = container.getBoundingClientRect(),
2543
2489
  cachedRectRef.current = rect), 0 === rect.width || 0 === rect.height) return;
2544
- const center = calculateElementCenter(rect), newOffset = {
2490
+ const center = calculateElementCenter(rect);
2491
+ // Write raw target — the lerp loop will smoothly pursue it
2492
+ targetMouseOffsetRef.current = {
2545
2493
  x: (globalPos.x - center.x) / rect.width * 100,
2546
2494
  y: (globalPos.y - center.y) / rect.height * 100
2495
+ }, targetGlobalMousePositionRef.current = globalPos;
2496
+ }), [ mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects ]), startLerpLoop = useCallback((() => {
2497
+ if (lerpActiveRef.current) return;
2498
+ lerpActiveRef.current = !0;
2499
+ const LERP_T = CONSTANTS.LERP_FACTOR, tick = () => {
2500
+ if (!lerpActiveRef.current) return;
2501
+ const cur = internalMouseOffsetRef.current, tgt = targetMouseOffsetRef.current, dx = tgt.x - cur.x, dy = tgt.y - cur.y;
2502
+ // If we're close enough, snap and park
2503
+ if (Math.abs(dx) < .05 && Math.abs(dy) < .05) internalMouseOffsetRef.current = {
2504
+ ...tgt
2505
+ }, internalGlobalMousePositionRef.current = {
2506
+ ...targetGlobalMousePositionRef.current
2507
+ }; else {
2508
+ internalMouseOffsetRef.current = {
2509
+ x: lerp(cur.x, tgt.x, LERP_T),
2510
+ y: lerp(cur.y, tgt.y, LERP_T)
2511
+ };
2512
+ const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
2513
+ internalGlobalMousePositionRef.current = {
2514
+ x: lerp(curG.x, tgtG.x, LERP_T),
2515
+ y: lerp(curG.y, tgtG.y, LERP_T)
2516
+ };
2517
+ }
2518
+ // Imperative style update with the smoothed values
2519
+ updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
2520
+ mouseOffset: internalMouseOffsetRef.current,
2521
+ globalMousePosition: internalGlobalMousePositionRef.current,
2522
+ glassSize: glassSize,
2523
+ isHovered: isHovered,
2524
+ isActive: isActive,
2525
+ isOverLight: overLightConfig.isOverLight,
2526
+ baseOverLightConfig: overLightConfig,
2527
+ effectiveBorderRadius: effectiveBorderRadius,
2528
+ effectiveWithoutEffects: effectiveWithoutEffects,
2529
+ effectiveReducedMotion: effectiveReducedMotion,
2530
+ elasticity: elasticity,
2531
+ directionalScale: isActive && Boolean(onClick) ? "scale(0.96)" : "scale(1)",
2532
+ onClick: onClick,
2533
+ withLiquidBlur: withLiquidBlur,
2534
+ blurAmount: blurAmount,
2535
+ saturation: saturation,
2536
+ padding: padding
2537
+ }), lerpRafRef.current = requestAnimationFrame(tick);
2547
2538
  };
2548
- // Calculate offset relative to this container
2549
- // Store in refs instead of state
2550
- internalMouseOffsetRef.current = newOffset, internalGlobalMousePositionRef.current = globalPos,
2551
- // Imperative style update
2552
- updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
2553
- mouseOffset: newOffset,
2554
- globalMousePosition: globalPos,
2555
- glassSize: glassSize,
2556
- isHovered: isHovered,
2557
- isActive: isActive,
2558
- isOverLight: baseOverLightConfig.isOverLight,
2559
- baseOverLightConfig: baseOverLightConfig,
2560
- effectiveBorderRadius: effectiveBorderRadius,
2561
- effectiveWithoutEffects: effectiveWithoutEffects,
2562
- effectiveReducedMotion: effectiveReducedMotion,
2563
- elasticity: elasticity,
2564
- directionalScale: isActive && Boolean(onClick) ? "scale(0.96)" : "scale(1)",
2565
- // Simplified directional scale for fast path
2566
- onClick: onClick,
2567
- withLiquidBlur: withLiquidBlur,
2568
- blurAmount: blurAmount,
2569
- saturation: saturation,
2570
- padding: padding
2571
- });
2572
- }), [ mouseContainer, glassRef, wrapperRef, externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects, glassSize, isHovered, isActive, baseOverLightConfig, effectiveBorderRadius, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding ]);
2539
+ // 0.08 lower = more viscous
2540
+ lerpRafRef.current = requestAnimationFrame(tick);
2541
+ }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding ]), stopLerpLoop = useCallback((() => {
2542
+ lerpActiveRef.current = !1, null !== lerpRafRef.current && (cancelAnimationFrame(lerpRafRef.current),
2543
+ lerpRafRef.current = null);
2544
+ }), []);
2573
2545
  /**
2574
2546
  * Validate and clamp a numeric config value
2575
2547
  */
@@ -2577,7 +2549,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2577
2549
  useEffect((() => {
2578
2550
  if (externalGlobalMousePosition && externalMouseOffset) return;
2579
2551
  if (effectiveWithoutEffects) return;
2580
- const unsubscribe = globalMouseTracker.subscribe(handleGlobalMousePosition), container = mouseContainer?.current || glassRef.current;
2552
+ const unsubscribe = globalMouseTracker.subscribe(handleGlobalMousePosition);
2553
+ // Start the lerp loop — it will smoothly chase the target
2554
+ startLerpLoop();
2555
+ const container = mouseContainer?.current || glassRef.current;
2581
2556
  let resizeObserver = null;
2582
2557
  return container && "undefined" != typeof ResizeObserver && (resizeObserver = new ResizeObserver((() => {
2583
2558
  null !== updateRectRef.current && cancelAnimationFrame(updateRectRef.current), updateRectRef.current = requestAnimationFrame((() => {
@@ -2585,10 +2560,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2585
2560
  container && (cachedRectRef.current = container.getBoundingClientRect()), updateRectRef.current = null;
2586
2561
  }));
2587
2562
  })), resizeObserver.observe(container)), () => {
2588
- unsubscribe(), null !== updateRectRef.current && (cancelAnimationFrame(updateRectRef.current),
2563
+ unsubscribe(), stopLerpLoop(), null !== updateRectRef.current && (cancelAnimationFrame(updateRectRef.current),
2589
2564
  updateRectRef.current = null), resizeObserver && resizeObserver.disconnect();
2590
2565
  };
2591
- }), [ handleGlobalMousePosition, mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects ]),
2566
+ }), [ handleGlobalMousePosition, startLerpLoop, stopLerpLoop, mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects ]),
2592
2567
  // Also call updateStyles on other state changes (hover, active, etc)
2593
2568
  useEffect((() => {
2594
2569
  updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
@@ -2597,22 +2572,22 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2597
2572
  glassSize: glassSize,
2598
2573
  isHovered: isHovered,
2599
2574
  isActive: isActive,
2600
- isOverLight: baseOverLightConfig.isOverLight,
2601
- baseOverLightConfig: baseOverLightConfig,
2575
+ isOverLight: overLightConfig.isOverLight,
2576
+ baseOverLightConfig: overLightConfig,
2602
2577
  effectiveBorderRadius: effectiveBorderRadius,
2603
2578
  effectiveWithoutEffects: effectiveWithoutEffects,
2604
2579
  effectiveReducedMotion: effectiveReducedMotion,
2605
2580
  elasticity: elasticity,
2606
- directionalScale: directionalScale,
2581
+ directionalScale: isActive && Boolean(onClick) ? "scale(0.96)" : "scale(1)",
2607
2582
  onClick: onClick,
2608
2583
  withLiquidBlur: withLiquidBlur,
2609
2584
  blurAmount: blurAmount,
2610
2585
  saturation: saturation,
2611
2586
  padding: padding
2612
2587
  });
2613
- }), [ isHovered, isActive, glassSize, baseOverLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, directionalScale, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation, padding, onClick ]);
2588
+ }), [ isHovered, isActive, glassSize, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation, padding, onClick ]);
2614
2589
  // Event handlers
2615
- const handleMouseEnter = useCallback((() => setIsHovered(!0)), []), handleMouseLeave = useCallback((() => setIsHovered(!1)), []), handleMouseDown = useCallback((() => setIsActive(!0)), []), handleMouseUp = useCallback((() => setIsActive(!1)), []), handleMouseMove = useCallback((_e => {}), []), handleKeyDown = useCallback((e => {
2590
+ const handleMouseEnter = useCallback((() => setIsHovered(!0)), []), handleMouseLeave = useCallback((() => setIsHovered(!1)), []), handleMouseDown = useCallback((() => setIsActive(!0)), []), handleMouseUp = useCallback((() => setIsActive(!1)), []), handleKeyDown = useCallback((e => {
2616
2591
  !onClick || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), onClick());
2617
2592
  }), [ onClick ]);
2618
2593
  return {
@@ -2630,14 +2605,11 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2630
2605
  mouseOffset: mouseOffset,
2631
2606
  // This is now static (refs or props) unless prop changes
2632
2607
  overLightConfig: overLightConfig,
2633
- elasticTranslation: elasticTranslation,
2634
- directionalScale: directionalScale,
2635
2608
  transformStyle: transformStyle,
2636
2609
  handleMouseEnter: handleMouseEnter,
2637
2610
  handleMouseLeave: handleMouseLeave,
2638
2611
  handleMouseDown: handleMouseDown,
2639
2612
  handleMouseUp: handleMouseUp,
2640
- handleMouseMove: handleMouseMove,
2641
2613
  handleKeyDown: handleKeyDown
2642
2614
  };
2643
2615
  }
@@ -2735,25 +2707,56 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2735
2707
  withLiquidBlur: withLiquidBlur,
2736
2708
  padding: padding,
2737
2709
  style: style
2738
- }), isOverLight = useMemo((() => overLightConfig?.isOverLight), [ overLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, baseStyle = {
2739
- ...style,
2740
- ...!effectiveWithoutEffects && {
2741
- transform: transformStyle
2710
+ }), isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = "fixed" === restStyle.position || "sticky" === restStyle.position, rootLayoutStyle = useMemo((() => {
2711
+ if (!isFixedOrSticky) return {};
2712
+ const {position: p, top: t, left: l, right: r, bottom: b} = restStyle;
2713
+ return {
2714
+ ...p && {
2715
+ position: p
2716
+ },
2717
+ ...void 0 !== t && {
2718
+ top: t
2719
+ },
2720
+ ...void 0 !== l && {
2721
+ left: l
2722
+ },
2723
+ ...void 0 !== r && {
2724
+ right: r
2725
+ },
2726
+ ...void 0 !== b && {
2727
+ bottom: b
2728
+ }
2729
+ };
2730
+ }), [ isFixedOrSticky, restStyle ]), baseStyle = useMemo((() => {
2731
+ if (isFixedOrSticky) {
2732
+ const {position: _p, top: _t, left: _l, right: _r, bottom: _b, ...visualStyle} = restStyle;
2733
+ return {
2734
+ ...visualStyle,
2735
+ ...!effectiveWithoutEffects && {
2736
+ transform: transformStyle
2737
+ }
2738
+ };
2742
2739
  }
2743
- }, componentClassName = [ ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`, effectiveWithoutEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`, className ].filter(Boolean).join(" "), positionStyles = useMemo((() => ({
2744
- position: style.position || "absolute",
2745
- top: style.top || 0,
2746
- left: style.left || 0
2747
- })), [ style.position, style.top, style.left ]), adjustedSize = useMemo((() => {
2740
+ return {
2741
+ ...restStyle,
2742
+ ...!effectiveWithoutEffects && {
2743
+ transform: transformStyle
2744
+ }
2745
+ };
2746
+ }), [ isFixedOrSticky, restStyle, effectiveWithoutEffects, transformStyle ]), componentClassName = [ ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`, effectiveWithoutEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`, className ].filter(Boolean).join(" "), positionStyles = useMemo((() => ({
2747
+ position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
2748
+ top: isFixedOrSticky ? 0 : restStyle.top || 0,
2749
+ left: isFixedOrSticky ? 0 : restStyle.left || 0
2750
+ })), [ isFixedOrSticky, restStyle.position, restStyle.top, restStyle.left ]), adjustedSize = useMemo((() => {
2748
2751
  const resolveSize = (propValue, styleValue, measuredSize) => {
2749
2752
  const explicitSize = propValue ?? styleValue;
2750
2753
  return void 0 !== explicitSize ? "number" == typeof explicitSize ? `${explicitSize}px` : explicitSize : "fixed" === positionStyles.position ? `${Math.max(measuredSize, 0)}px` : "100%";
2751
2754
  };
2752
2755
  return {
2753
- width: resolveSize(width, style.width, glassSize.width),
2754
- height: resolveSize(height, style.height, glassSize.height)
2756
+ width: resolveSize(width, restStyle.width, glassSize.width),
2757
+ height: resolveSize(height, restStyle.height, glassSize.height)
2755
2758
  };
2756
- }), [ width, height, style.width, style.height, positionStyles.position, glassSize.width, glassSize.height ]), gradientValues = useMemo((() => {
2759
+ }), [ width, height, restStyle.width, restStyle.height, positionStyles.position, glassSize.width, glassSize.height ]), gradientValues = useMemo((() => {
2757
2760
  const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT;
2758
2761
  return {
2759
2762
  borderGradientAngle: GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER,
@@ -2795,6 +2798,9 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2795
2798
  }), [ isHovered, isActive, isOverLight, overLightConfig.opacity ]), glassVars = useMemo((() => {
2796
2799
  const whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, {borderGradientAngle: borderGradientAngle, borderStop1: borderStop1, borderStop2: borderStop2, borderOpacities: borderOpacities, hoverPositions: hoverPositions, basePosition: basePosition, mx: mx, my: my, absMx: absMx, absMy: absMy} = gradientValues, configBorderOpacity = overLightConfig?.borderOpacity ?? 1;
2797
2800
  return {
2801
+ ...void 0 !== customZIndex && {
2802
+ "--atomix-glass-base-z-index": customZIndex
2803
+ },
2798
2804
  "--atomix-glass-radius": `${effectiveBorderRadius}px`,
2799
2805
  "--atomix-glass-transform": transformStyle || "none",
2800
2806
  "--atomix-glass-position": positionStyles.position,
@@ -2815,22 +2821,19 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2815
2821
  "--atomix-glass-base-opacity": opacityValues.base,
2816
2822
  "--atomix-glass-base-gradient": isOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + mx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + my * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + absMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`,
2817
2823
  "--atomix-glass-overlay-opacity": opacityValues.over,
2818
- "--atomix-glass-overlay-gradient": isOverLight ? `radial-gradient(circle at ${basePosition.x}% ${basePosition.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + absMx * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + absMy * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`
2824
+ "--atomix-glass-overlay-gradient": isOverLight ? `radial-gradient(circle at ${basePosition.x}% ${basePosition.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + absMx * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + absMy * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`,
2825
+ "--atomix-glass-overlay-highlight-opacity": opacityValues.over * ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER,
2826
+ "--atomix-glass-overlay-highlight-bg": `radial-gradient(circle at ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_X}% ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_Y}%, rgba(255, 255, 255, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.WHITE_OPACITY}) 0%, transparent ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.STOP}%)`
2819
2827
  };
2820
- }), [ gradientValues, opacityValues, effectiveBorderRadius, transformStyle, positionStyles, adjustedSize, isOverLight, overLightConfig.borderOpacity ]), renderBackgroundLayer = layerType => jsx("div", {
2821
- className: [ ATOMIX_GLASS.BACKGROUND_LAYER_CLASS, "dark" === layerType ? ATOMIX_GLASS.BACKGROUND_LAYER_DARK_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_BLACK_CLASS, isOverLight ? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS ].filter(Boolean).join(" "),
2822
- style: {
2823
- ...positionStyles,
2824
- height: adjustedSize.height,
2825
- width: adjustedSize.width,
2826
- borderRadius: `${effectiveBorderRadius}px`,
2827
- transform: baseStyle.transform
2828
- }
2828
+ }), [ gradientValues, opacityValues, effectiveBorderRadius, transformStyle, positionStyles, adjustedSize, isOverLight, overLightConfig.borderOpacity, customZIndex ]), renderBackgroundLayer = layerType => jsx("div", {
2829
+ className: [ ATOMIX_GLASS.BACKGROUND_LAYER_CLASS, "dark" === layerType ? ATOMIX_GLASS.BACKGROUND_LAYER_DARK_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_BLACK_CLASS, isOverLight ? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS ].filter(Boolean).join(" ")
2829
2830
  });
2830
2831
  return jsxs("div", {
2831
2832
  ...rest,
2832
2833
  className: componentClassName,
2833
- style: glassVars,
2834
+ style: {
2835
+ ...glassVars
2836
+ },
2834
2837
  role: role || (onClick ? "button" : void 0),
2835
2838
  tabIndex: onClick ? tabIndex ?? 0 : tabIndex,
2836
2839
  "aria-label": ariaLabel,
@@ -2842,7 +2845,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2842
2845
  ref: glassRef,
2843
2846
  contentRef: contentRef,
2844
2847
  className: className,
2845
- style: baseStyle,
2848
+ style: rootLayoutStyle,
2846
2849
  borderRadius: effectiveBorderRadius,
2847
2850
  displacementScale: effectiveWithoutEffects ? 0 : "shader" === mode ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_DISPLACEMENT : isOverLight ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.OVER_LIGHT_DISPLACEMENT : displacementScale,
2848
2851
  blurAmount: effectiveWithoutEffects ? 0 : blurAmount,
@@ -2893,11 +2896,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2893
2896
  }), jsx("div", {
2894
2897
  className: ATOMIX_GLASS.OVERLAY_LAYER_CLASS
2895
2898
  }), jsx("div", {
2896
- className: ATOMIX_GLASS.OVERLAY_HIGHLIGHT_CLASS,
2897
- style: {
2898
- opacity: opacityValues.over * ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER,
2899
- background: `radial-gradient(circle at ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_X}% ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_Y}%, rgba(255, 255, 255, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.WHITE_OPACITY}) 0%, transparent ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.STOP}%)`
2900
- }
2899
+ className: ATOMIX_GLASS.OVERLAY_HIGHLIGHT_CLASS
2901
2900
  }) ]
2902
2901
  }), withBorder && jsxs(Fragment, {
2903
2902
  children: [ jsx("span", {
@@ -3993,120 +3992,6 @@ const BaseChart = memo( forwardRef((({type: type, datasets: datasets = [], conf
3993
3992
 
3994
3993
  BaseChart.displayName = "BaseChart";
3995
3994
 
3996
- const AnimatedChart = memo( forwardRef((({datasets: datasets = [], config: config = {}, chartType: chartType = "line", particleEffects: particleEffects, onDataPointClick: onDataPointClick, ...props}, ref) => {
3997
- const animationRef = useRef(0), timeRef = useRef(0), particlesRef = useRef([]);
3998
- // Animation time tracking - moved outside callback
3999
- useEffect((() => {
4000
- const animateFrame = timestamp => {
4001
- timeRef.current = timestamp, animationRef.current = requestAnimationFrame(animateFrame);
4002
- };
4003
- return animationRef.current = requestAnimationFrame(animateFrame), () => {
4004
- animationRef.current && cancelAnimationFrame(animationRef.current);
4005
- };
4006
- }), []);
4007
- const renderContent = useCallback((({scales: scales, colors: colors, datasets: chartDatasets, handlers: handlers, hoveredPoint: hoveredPoint, toolbarState: toolbarState, config: renderConfig}) => {
4008
- if (!chartDatasets.length) return null;
4009
- const chartWidth = scales.width - 80, chartHeight = scales.height - 80, elements = [];
4010
- // Particle effects
4011
- if (chartDatasets.forEach(((dataset, datasetIndex) => {
4012
- const color = dataset.color || colors[datasetIndex % colors.length];
4013
- switch (chartType) {
4014
- case "bar":
4015
- // Create animated bars
4016
- dataset.data.forEach(((point, pointIndex) => {
4017
- const barWidth = chartWidth / dataset.data.length * .8, x = 40 + pointIndex * (chartWidth / dataset.data.length) + (chartWidth / dataset.data.length - barWidth) / 2, height = point.value / 100 * chartHeight, y = 40 + chartHeight - height;
4018
- elements.push(jsx("rect", {
4019
- x: x,
4020
- y: y,
4021
- width: barWidth,
4022
- height: height,
4023
- fill: color,
4024
- style: {
4025
- transform: `scaleY(${.1 * Math.sin(.01 * timeRef.current + .2 * pointIndex) + .9})`,
4026
- transformOrigin: "bottom"
4027
- },
4028
- onClick: () => handlers.onDataPointClick?.(point, datasetIndex, pointIndex)
4029
- }, `bar-${datasetIndex}-${pointIndex}`));
4030
- }));
4031
- break;
4032
-
4033
- default:
4034
- {
4035
- // Create animated line/area
4036
- const points = dataset.data.map(((point, pointIndex) => ({
4037
- x: 40 + pointIndex / (dataset.data.length - 1) * chartWidth,
4038
- y: 40 + chartHeight - point.value / 100 * chartHeight
4039
- })));
4040
- if (points.length > 0) {
4041
- const linePath = `M ${points.map((p => `${p.x},${p.y}`)).join(" L ")}`;
4042
- // Area for area chart
4043
- if ("area" === chartType) {
4044
- const areaPath = `${linePath} L ${40 + chartWidth},${40 + chartHeight} L 40,${40 + chartHeight} Z`;
4045
- elements.push(jsx("path", {
4046
- d: areaPath,
4047
- fill: color,
4048
- fillOpacity: "0.3",
4049
- style: {
4050
- transform: `translateY(${2 * Math.sin(.01 * timeRef.current)}px)`
4051
- }
4052
- }, `area-${datasetIndex}`));
4053
- }
4054
- // Line
4055
- elements.push(jsx("path", {
4056
- d: linePath,
4057
- stroke: color,
4058
- fill: "none",
4059
- className: "c-chart__data-line",
4060
- style: {
4061
- transform: `translateY(${2 * Math.sin(.01 * timeRef.current)}px)`
4062
- }
4063
- }, `line-${datasetIndex}`)),
4064
- // Data points
4065
- points.forEach(((point, pointIndex) => {
4066
- elements.push(jsx("circle", {
4067
- cx: point.x,
4068
- cy: point.y,
4069
- r: "4",
4070
- fill: color,
4071
- style: {
4072
- transform: `scale(${1 + .2 * Math.sin(.01 * timeRef.current + pointIndex)})`
4073
- },
4074
- onClick: () => handlers.onDataPointClick?.(dataset.data[pointIndex], datasetIndex, pointIndex)
4075
- }, `point-${datasetIndex}-${pointIndex}`));
4076
- }));
4077
- }
4078
- break;
4079
- }
4080
- }
4081
- })), particleEffects?.enabled) for (let i = 0; i < particleEffects.count; i++) {
4082
- const particle = particlesRef.current[i];
4083
- particle && elements.push(jsx("circle", {
4084
- cx: particle.x,
4085
- cy: particle.y,
4086
- r: particle.size,
4087
- fill: particle.color,
4088
- style: {
4089
- opacity: particle.life
4090
- }
4091
- }, `particle-${i}`));
4092
- }
4093
- return jsx("g", {
4094
- children: elements
4095
- });
4096
- }), [ chartType, particleEffects ]);
4097
- return jsx(BaseChart, {
4098
- ref: ref,
4099
- type: "line",
4100
- datasets: datasets,
4101
- config: config,
4102
- renderContent: renderContent,
4103
- onDataPointClick: onDataPointClick,
4104
- ...props
4105
- });
4106
- })));
4107
-
4108
- AnimatedChart.displayName = "AnimatedChart";
4109
-
4110
3995
  const ChartTooltip = memo((({dataPoint: dataPoint, datasetLabel: datasetLabel, datasetColor: datasetColor, position: position, visible: visible, customRenderer: customRenderer}) => {
4111
3996
  const tooltipRef = useRef(null), [adjustedPosition, setAdjustedPosition] = useState(position);
4112
3997
  // Dynamic positioning to keep tooltip in viewport
@@ -4128,15 +4013,16 @@ const ChartTooltip = memo((({dataPoint: dataPoint, datasetLabel: datasetLabel,
4128
4013
  ref: tooltipRef,
4129
4014
  className: "c-chart__tooltip",
4130
4015
  style: {
4131
- left: `${adjustedPosition.x}px`,
4132
- top: `${adjustedPosition.y}px`,
4016
+ transform: `translate3d(${adjustedPosition.x}px, ${adjustedPosition.y}px, 0)`,
4133
4017
  opacity: visible ? 1 : 0,
4134
4018
  visibility: visible ? "visible" : "hidden",
4135
- transition: "opacity 0.2s ease, transform 0.2s ease",
4136
- transform: "translateZ(0)",
4019
+ transition: "opacity 0.2s ease",
4137
4020
  position: "fixed",
4021
+ left: 0,
4022
+ top: 0,
4138
4023
  zIndex: 1e3,
4139
- pointerEvents: "none"
4024
+ pointerEvents: "none",
4025
+ willChange: "transform"
4140
4026
  },
4141
4027
  children: customRenderer ? customRenderer(dataPoint) : jsxs(Fragment, {
4142
4028
  children: [ jsx("div", {
@@ -4454,8 +4340,9 @@ const BubbleChart = memo( forwardRef((({bubbleData: bubbleData = [], config: co
4454
4340
  if (!bubbleData.length) return null;
4455
4341
  const showTooltips = toolbarState?.showTooltips ?? renderConfig?.showTooltips ?? !0, sizeValues = bubbleData.map((b => b.size)), minSize = Math.min(...sizeValues), sizeRange = Math.max(...sizeValues) - minSize || 1, bubbles = bubbleData.map(((bubble, index) => {
4456
4342
  // Calculate scaled size
4457
- const scaledSize = minBubbleSize + (bubble.size - minSize) / sizeRange * (maxBubbleSize - minBubbleSize), x = scales.padding.left + bubble.x / 100 * scales.innerWidth, y = scales.padding.top + scales.innerHeight - bubble.y / 100 * scales.innerHeight;
4343
+ const scaledSize = minBubbleSize + (bubble.size - minSize) / sizeRange * (maxBubbleSize - minBubbleSize), effectiveWidth = scales.innerWidth - 2 * maxBubbleSize, effectiveHeight = scales.innerHeight - 2 * maxBubbleSize, x = scales.padding.left + maxBubbleSize + bubble.x / 100 * effectiveWidth, y = scales.padding.top + maxBubbleSize + effectiveHeight - bubble.y / 100 * effectiveHeight;
4458
4344
  // Calculate position
4345
+ // Ensure bubbles don't get cut off by adding padding equal to maxBubbleSize
4459
4346
  // Determine color
4460
4347
  let bubbleColor = bubble.color;
4461
4348
  if (!bubbleColor) if (sizeBasedColoring) {
@@ -4916,9 +4803,10 @@ const GaugeChart = memo( forwardRef((({value: value, min: min = 0, max: max = 1
4916
4803
  // Create ticks
4917
4804
  const ticks = [];
4918
4805
  if (showTicks) {
4806
+ const innerRadius = radius * (1 - thickness);
4919
4807
  // Major ticks
4920
- for (let i = 0; i <= majorTicks; i++) {
4921
- const tickValue = min + i / majorTicks * (max - min), tickAngle = startAngleRad + i / majorTicks * angleRange, tickRadius = .95 * radius, tickLength = .05 * radius, x1 = centerX + tickRadius * Math.cos(tickAngle), y1 = centerY + tickRadius * Math.sin(tickAngle), x2 = centerX + (tickRadius - tickLength) * Math.cos(tickAngle), y2 = centerY + (tickRadius - tickLength) * Math.sin(tickAngle);
4808
+ for (let i = 0; i <= majorTicks; i++) {
4809
+ const tickValue = min + i / majorTicks * (max - min), tickAngle = startAngleRad + i / majorTicks * angleRange, tickRadius = innerRadius - 2, tickLength = .05 * radius, x1 = centerX + tickRadius * Math.cos(tickAngle), y1 = centerY + tickRadius * Math.sin(tickAngle), x2 = centerX + (tickRadius - tickLength) * Math.cos(tickAngle), y2 = centerY + (tickRadius - tickLength) * Math.sin(tickAngle);
4922
4810
  // Labels for major ticks
4923
4811
  if (ticks.push(jsx("line", {
4924
4812
  x1: x1,
@@ -4928,12 +4816,12 @@ const GaugeChart = memo( forwardRef((({value: value, min: min = 0, max: max = 1
4928
4816
  stroke: "var(--atomix-brand-border-subtle)",
4929
4817
  strokeWidth: "2"
4930
4818
  }, `major-tick-${i}`)), showMinMaxLabels) {
4931
- const labelX = centerX + (tickRadius - tickLength - 10) * Math.cos(tickAngle), labelY = centerY + (tickRadius - tickLength - 10) * Math.sin(tickAngle);
4819
+ const labelRadius = tickRadius - tickLength - 15, labelX = centerX + labelRadius * Math.cos(tickAngle), labelY = centerY + labelRadius * Math.sin(tickAngle);
4932
4820
  ticks.push(jsx("text", {
4933
4821
  x: labelX,
4934
4822
  y: labelY,
4935
4823
  textAnchor: "middle",
4936
- dominantBaseline: "middle",
4824
+ dominantBaseline: "central",
4937
4825
  fontSize: "12",
4938
4826
  fill: "var(--atomix-brand-text-emphasis)",
4939
4827
  children: tickValue
@@ -4941,8 +4829,9 @@ const GaugeChart = memo( forwardRef((({value: value, min: min = 0, max: max = 1
4941
4829
  }
4942
4830
  }
4943
4831
  // Minor ticks
4944
- for (let i = 0; i < majorTicks * minorTicks; i++) {
4945
- const tickAngle = startAngleRad + i / (majorTicks * minorTicks) * angleRange, tickRadius = .95 * radius, tickLength = .025 * radius, x1 = centerX + tickRadius * Math.cos(tickAngle), y1 = centerY + tickRadius * Math.sin(tickAngle), x2 = centerX + (tickRadius - tickLength) * Math.cos(tickAngle), y2 = centerY + (tickRadius - tickLength) * Math.sin(tickAngle);
4832
+ for (let i = 0; i <= majorTicks * minorTicks; i++) {
4833
+ if (i % minorTicks == 0) continue;
4834
+ const tickAngle = startAngleRad + i / (majorTicks * minorTicks) * angleRange, tickRadius = innerRadius - 2, tickLength = .025 * radius, x1 = centerX + tickRadius * Math.cos(tickAngle), y1 = centerY + tickRadius * Math.sin(tickAngle), x2 = centerX + (tickRadius - tickLength) * Math.cos(tickAngle), y2 = centerY + (tickRadius - tickLength) * Math.sin(tickAngle);
4946
4835
  ticks.push(jsx("line", {
4947
4836
  x1: x1,
4948
4837
  y1: y1,
@@ -4953,39 +4842,43 @@ const GaugeChart = memo( forwardRef((({value: value, min: min = 0, max: max = 1
4953
4842
  }, `minor-tick-${i}`));
4954
4843
  }
4955
4844
  }
4956
- // Create needle
4957
- const needle = showNeedle ? jsxs("g", {
4845
+ const innerRadius = radius * (1 - thickness), needle = showNeedle ? jsxs("g", {
4958
4846
  children: [ jsx("line", {
4959
4847
  x1: centerX,
4960
4848
  y1: centerY,
4961
- x2: centerX + .8 * radius * Math.cos(valueAngle),
4962
- y2: centerY + .8 * radius * Math.sin(valueAngle),
4849
+ x2: centerX + (innerRadius - 15) * Math.cos(valueAngle),
4850
+ y2: centerY + (innerRadius - 15) * Math.sin(valueAngle),
4963
4851
  stroke: needleColor,
4964
- strokeWidth: "3",
4852
+ strokeWidth: "4",
4965
4853
  strokeLinecap: "round"
4966
4854
  }), jsx("circle", {
4967
4855
  cx: centerX,
4968
4856
  cy: centerY,
4969
4857
  r: "8",
4970
4858
  fill: needleColor
4859
+ }), jsx("circle", {
4860
+ cx: centerX,
4861
+ cy: centerY,
4862
+ r: "3",
4863
+ fill: "var(--atomix-primary-bg, #fff)"
4971
4864
  }) ]
4972
4865
  }) : null, valueText = showValue ? jsx("text", {
4973
4866
  x: centerX,
4974
- y: centerY + 10,
4867
+ y: centerY + 35,
4975
4868
  textAnchor: "middle",
4976
- fontSize: "24",
4869
+ fontSize: "32",
4977
4870
  fontWeight: "bold",
4978
4871
  fill: "var(--atomix-primary-text-emphasis)",
4979
4872
  children: valueFormatter(clampedValue)
4980
4873
  }) : null, labelText = label ? jsx("text", {
4981
4874
  x: centerX,
4982
- y: "top" === labelPosition ? centerY - .7 * radius : centerY + .7 * radius,
4875
+ y: "top" === labelPosition ? centerY - .7 * radius : centerY + .7 * radius + 10,
4983
4876
  textAnchor: "middle",
4984
4877
  fontSize: "16",
4985
4878
  fill: "var(--atomix-brand-text-emphasis)",
4986
4879
  children: label
4987
4880
  }) : null;
4988
- // Value text
4881
+ // Create needle
4989
4882
  return jsxs("g", {
4990
4883
  children: [ jsx("path", {
4991
4884
  d: createArcPath(centerX, centerY, radius, startAngleRad, endAngleRad, thickness),
@@ -5017,11 +4910,9 @@ const colorSchemes = {
5017
4910
  greens: [ "var(--atomix-green-1)", "var(--atomix-green-2)", "var(--atomix-green-3)", "var(--atomix-green-4)", "var(--atomix-green-5)", "var(--atomix-green-6)", "var(--atomix-green-7)", "var(--atomix-green-8)", "var(--atomix-green-9)" ],
5018
4911
  github: [ "var(--atomix-gray-2)", "var(--atomix-green-3)", "var(--atomix-green-4)", "var(--atomix-green-5)", "var(--atomix-green-6)" ]
5019
4912
  }, HeatmapChart = memo( forwardRef((({data: data = [], config: config = {}, colorScale: colorScale = {
5020
- scheme: "viridis",
4913
+ scheme: "blues",
5021
4914
  steps: 9
5022
4915
  }, cellConfig: cellConfig = {
5023
- width: 40,
5024
- height: 40,
5025
4916
  spacing: 2,
5026
4917
  borderRadius: 4,
5027
4918
  showLabels: !1
@@ -5081,9 +4972,8 @@ const colorSchemes = {
5081
4972
  renderContent: ({scales: scales, colors: colors, datasets: renderedDatasets, handlers: handlers, hoveredPoint: hoveredPoint, toolbarState: toolbarState, config: renderConfig}) => {
5082
4973
  const {matrix: matrix, xLabels: xLabels, yLabels: yLabels} = processedData, showTooltips = toolbarState?.showTooltips ?? renderConfig?.showTooltips ?? !0;
5083
4974
  if (!matrix.length) return null;
5084
- const cellWidth = cellConfig.width || 40, cellHeight = cellConfig.height || 40, spacing = cellConfig.spacing || 2, borderRadius = cellConfig.borderRadius || 4;
5085
- // Leave space for x-axis labels
5086
- return xLabels.length, yLabels.length, jsxs(Fragment, {
4975
+ const spacing = cellConfig.spacing ?? 2, borderRadius = cellConfig.borderRadius ?? 4, {width: width, height: height} = scales, paddingRight = 20 + (showColorLegend ? 60 : 0), availableWidth = Math.max(0, width - 60 - paddingRight), availableHeight = Math.max(0, height - 20 - 40), cols = Math.max(1, xLabels.length), rows = Math.max(1, yLabels.length), maxCellWidth = Math.max(2, Math.floor((availableWidth - (cols - 1) * spacing) / cols)), maxCellHeight = Math.max(2, Math.floor((availableHeight - (rows - 1) * spacing) / rows)), cellWidth = cellConfig.width || maxCellWidth, cellHeight = cellConfig.height || maxCellHeight, totalWidth = cols * cellWidth + (cols - 1) * spacing, totalHeight = rows * cellHeight + (rows - 1) * spacing, startX = 60 + Math.max(0, (availableWidth - totalWidth) / 2), startY = 20 + Math.max(0, (availableHeight - totalHeight) / 2);
4976
+ return jsxs(Fragment, {
5087
4977
  children: [ jsxs("g", {
5088
4978
  children: [ jsx("defs", {
5089
4979
  children: showColorLegend && (() => {
@@ -5102,7 +4992,7 @@ const colorSchemes = {
5102
4992
  })()
5103
4993
  }), matrix.map(((row, rowIndex) => row.map(((cell, colIndex) => {
5104
4994
  if (!cell) return null;
5105
- const x = 100 + colIndex * (cellWidth + spacing), y = 50 + rowIndex * (cellHeight + spacing), color = getColorForValue(cell.value), isHovered = hoveredCell === cell;
4995
+ const x = startX + colIndex * (cellWidth + spacing), y = startY + rowIndex * (cellHeight + spacing), color = getColorForValue(cell.value);
5106
4996
  return jsxs("g", {
5107
4997
  children: [ jsx("rect", {
5108
4998
  x: x,
@@ -5112,12 +5002,7 @@ const colorSchemes = {
5112
5002
  rx: borderRadius,
5113
5003
  ry: borderRadius,
5114
5004
  fill: color,
5115
- className: "c-chart__heatmap-cell " + (isHovered ? "c-chart__heatmap-cell--hovered" : ""),
5116
- style: {
5117
- transition: "all 0.2s ease",
5118
- transform: isHovered ? "scale(1.05)" : "scale(1)",
5119
- transformOrigin: "center"
5120
- },
5005
+ className: "c-chart__heatmap-cell " + (hoveredCell === cell ? "c-chart__heatmap-cell--hovered" : ""),
5121
5006
  onClick: () => {
5122
5007
  cell && handlers.onDataPointClick?.({
5123
5008
  ...cell,
@@ -5127,8 +5012,14 @@ const colorSchemes = {
5127
5012
  },
5128
5013
  onMouseEnter: e => {
5129
5014
  setHoveredCell(cell);
5015
+ const pointIndex = data.findIndex((d => d.x === cell.x && d.y === cell.y)), rect = e.currentTarget.getBoundingClientRect();
5016
+ handlers.onPointHover(0,
5017
+ // datasetIndex is always 0 for Heatmap
5018
+ pointIndex >= 0 ? pointIndex : 0, x, y, rect.left + rect.width / 2, rect.top + rect.height / 2);
5130
5019
  },
5131
- onMouseLeave: () => setHoveredCell(null)
5020
+ onMouseLeave: () => {
5021
+ setHoveredCell(null), handlers.onPointLeave();
5022
+ }
5132
5023
  }), cellConfig.showLabels && cell.label && jsx("text", {
5133
5024
  x: x + cellWidth / 2,
5134
5025
  y: y + cellHeight / 2,
@@ -5139,7 +5030,7 @@ const colorSchemes = {
5139
5030
  }) ]
5140
5031
  }, `cell-${rowIndex}-${colIndex}`);
5141
5032
  })))), xLabels.map(((label, index) => {
5142
- const x = 100 + index * (cellWidth + spacing) + cellWidth / 2, y = 50 + matrix.length * (cellHeight + spacing) + 20;
5033
+ const x = startX + index * (cellWidth + spacing) + cellWidth / 2, y = startY + matrix.length * (cellHeight + spacing) + 20;
5143
5034
  return jsx("text", {
5144
5035
  x: x,
5145
5036
  y: y,
@@ -5148,36 +5039,38 @@ const colorSchemes = {
5148
5039
  children: String(label)
5149
5040
  }, `x-label-${index}`);
5150
5041
  })), yLabels.map(((label, index) => jsx("text", {
5151
- x: 80,
5152
- y: 50 + index * (cellHeight + spacing) + cellHeight / 2,
5042
+ x: startX - 20,
5043
+ y: startY + index * (cellHeight + spacing) + cellHeight / 2,
5153
5044
  textAnchor: "end",
5154
5045
  dominantBaseline: "middle",
5155
5046
  className: "c-chart__heatmap-axis-label",
5156
5047
  children: String(label)
5157
5048
  }, `y-label-${index}`))), showColorLegend && jsxs("g", {
5158
- transform: "translate(600, 100)",
5049
+ transform: `translate(${startX + totalWidth + 20}, ${startY})`,
5159
5050
  children: [ jsx("rect", {
5160
5051
  x: "0",
5161
5052
  y: "0",
5162
- width: "20",
5163
- height: "200",
5053
+ width: "12",
5054
+ height: totalHeight,
5164
5055
  fill: "url(#heatmap-legend-gradient)",
5165
5056
  stroke: "var(--atomix-border-color)",
5166
- className: "c-chart__grid"
5057
+ className: "c-chart__grid",
5058
+ rx: borderRadius,
5059
+ ry: borderRadius
5167
5060
  }), jsx("text", {
5168
- x: "-10",
5061
+ x: "-5",
5169
5062
  y: "-10",
5170
5063
  className: "c-chart__heatmap-legend-title",
5171
5064
  children: "Values"
5172
5065
  }), jsx("text", {
5173
- x: "25",
5174
- y: "5",
5066
+ x: "20",
5067
+ y: "8",
5175
5068
  textAnchor: "start",
5176
5069
  className: "c-chart__heatmap-legend-label",
5177
5070
  children: "High"
5178
5071
  }), jsx("text", {
5179
- x: "25",
5180
- y: "200",
5072
+ x: "20",
5073
+ y: totalHeight,
5181
5074
  textAnchor: "start",
5182
5075
  className: "c-chart__heatmap-legend-label",
5183
5076
  children: "Low"
@@ -5947,8 +5840,7 @@ const DEFAULT_COLOR_CONFIG = {
5947
5840
  }, DEFAULT_LABEL_CONFIG = {
5948
5841
  showLabels: !0,
5949
5842
  minSize: 1e3,
5950
- fontSize: 12,
5951
- textColor: "white"
5843
+ fontSize: 12
5952
5844
  }, DEFAULT_CONFIG = {}, TreemapChart = memo( forwardRef((({data: data = [], algorithm: algorithm = "squarified", colorConfig: colorConfig = DEFAULT_COLOR_CONFIG, labelConfig: labelConfig = DEFAULT_LABEL_CONFIG, onDataPointClick: onDataPointClick, config: config = DEFAULT_CONFIG, ...props}, ref) => {
5953
5845
  const [hoveredNode, setHoveredNode] = useState(null), [selectedNode, setSelectedNode] = useState(null);
5954
5846
  useState({
@@ -6012,13 +5904,13 @@ const DEFAULT_COLOR_CONFIG = {
6012
5904
  }
6013
5905
  // Sort nodes by value (descending)
6014
5906
  const sortedNodes = [ ...nodes ].sort(((a, b) => b.value - a.value)), aspectRatio = rect => Math.max(rect.width / rect.height, rect.height / rect.width);
6015
- let currentRow = [], remainingNodes = [ ...sortedNodes ], currentX = x, currentY = y, remainingWidth = width, remainingHeight = height;
5907
+ let currentRow = [], remainingNodes = [ ...sortedNodes ], currentX = x, currentY = y, remainingWidth = width, remainingHeight = height, remainingValue = totalValue;
6016
5908
  for (;remainingNodes.length > 0; ) {
6017
5909
  const node = remainingNodes.shift();
6018
5910
  if (!node) break;
6019
5911
  currentRow.push(node);
6020
5912
  // Calculate dimensions for current row
6021
- const rowValue = _reduceInstanceProperty(currentRow).call(currentRow, ((sum, n) => sum + n.value), 0), rowRatio = rowValue / totalValue;
5913
+ const rowValue = _reduceInstanceProperty(currentRow).call(currentRow, ((sum, n) => sum + n.value), 0), rowRatio = remainingValue > 0 ? rowValue / remainingValue : 0;
6022
5914
  let rowWidth, rowHeight;
6023
5915
  remainingWidth >= remainingHeight ? (rowWidth = remainingWidth * rowRatio, rowHeight = remainingHeight) : (rowWidth = remainingWidth,
6024
5916
  rowHeight = remainingHeight * rowRatio);
@@ -6027,7 +5919,7 @@ const DEFAULT_COLOR_CONFIG = {
6027
5919
  if (remainingNodes.length > 0) {
6028
5920
  const nextNode = remainingNodes[0];
6029
5921
  if (!nextNode) break;
6030
- const testRow = [ ...currentRow, nextNode ], testRowValue = _reduceInstanceProperty(testRow).call(testRow, ((sum, n) => sum + n.value), 0), testRowRatio = testRowValue / totalValue;
5922
+ const testRow = [ ...currentRow, nextNode ], testRowValue = _reduceInstanceProperty(testRow).call(testRow, ((sum, n) => sum + n.value), 0), testRowRatio = remainingValue > 0 ? testRowValue / remainingValue : 0;
6031
5923
  let testRowWidth, testRowHeight;
6032
5924
  remainingWidth >= remainingHeight ? (testRowWidth = remainingWidth * testRowRatio,
6033
5925
  testRowHeight = remainingHeight) : (testRowWidth = remainingWidth, testRowHeight = remainingHeight * testRowRatio);
@@ -6058,14 +5950,14 @@ const DEFAULT_COLOR_CONFIG = {
6058
5950
  })),
6059
5951
  // Update remaining space
6060
5952
  remainingWidth >= remainingHeight ? (currentX += rowWidth, remainingWidth -= rowWidth) : (currentY += rowHeight,
6061
- remainingHeight -= rowHeight), currentRow = [];
5953
+ remainingHeight -= rowHeight), remainingValue -= rowValue, currentRow = [];
6062
5954
  }
6063
5955
  }
6064
- }), []), renderContent = useCallback((({scales: scales, colors: colors, datasets: renderedDatasets, handlers: handlers, hoveredPoint: hoveredPoint}) => {
5956
+ }), []), renderContent = useCallback((({scales: scales, colors: colors, datasets: renderedDatasets, handlers: handlers, hoveredPoint: hoveredPoint, toolbarState: toolbarState, config: renderConfig}) => {
6065
5957
  if (!data.length) return null;
6066
- // Calculate available space with padding
6067
- const availableWidth = scales.width - 40, availableHeight = scales.height - 40, leafNodes = data.filter((item => !item.children || 0 === item.children.length));
6068
- if (!leafNodes.length) return null;
5958
+ const showTooltips = toolbarState?.showTooltips ?? renderConfig?.showTooltips ?? !0, availableWidth = Math.max(0, scales.width), availableHeight = Math.max(0, scales.height), leafNodes = data.filter((item => !item.children || 0 === item.children.length));
5959
+ // Calculate available space
5960
+ if (!leafNodes.length) return null;
6069
5961
  const totalValue = _reduceInstanceProperty(leafNodes).call(leafNodes, ((sum, node) => sum + node.value), 0), treemapNodes = leafNodes.map(((item, index) => ({
6070
5962
  id: item.id,
6071
5963
  label: item.label,
@@ -6085,24 +5977,26 @@ const DEFAULT_COLOR_CONFIG = {
6085
5977
  })));
6086
5978
  // Create treemap nodes with proper dimensions
6087
5979
  // Apply squarified algorithm to layout nodes proportionally by value
6088
- if ("squarified" === algorithm && totalValue > 0) squarify(treemapNodes, 20, 20, availableWidth, availableHeight); else {
5980
+ if ("squarified" === algorithm && totalValue > 0) squarify(treemapNodes, 0, 0, availableWidth, availableHeight); else {
6089
5981
  // Fallback: simple grid layout (equal sizes)
6090
5982
  const cols = Math.ceil(Math.sqrt(leafNodes.length)), rows = Math.ceil(leafNodes.length / cols), nodeWidth = availableWidth / cols, nodeHeight = availableHeight / rows;
6091
5983
  treemapNodes.forEach(((node, index) => {
6092
5984
  const col = index % cols, row = Math.floor(index / cols);
6093
- node.x = 20 + col * nodeWidth, node.y = 20 + row * nodeHeight, node.width = nodeWidth,
5985
+ node.x = 0 + col * nodeWidth, node.y = 0 + row * nodeHeight, node.width = nodeWidth,
6094
5986
  node.height = nodeHeight;
6095
5987
  }));
6096
5988
  }
6097
- return jsx(Fragment, {
6098
- children: treemapNodes.map((node => {
5989
+ return jsxs(Fragment, {
5990
+ children: [ treemapNodes.map((node => {
6099
5991
  const isHovered = hoveredNode === node, isSelected = selectedNode === node, area = node.width * node.height, showLabel = labelConfig.showLabels && area >= (labelConfig.minSize || 1e3);
6100
5992
  return jsxs("g", {
6101
5993
  children: [ jsx("rect", {
6102
- x: node.x,
6103
- y: node.y,
6104
- width: node.width,
6105
- height: node.height,
5994
+ x: node.x + 2,
5995
+ y: node.y + 2,
5996
+ width: Math.max(0, node.width - 4),
5997
+ height: Math.max(0, node.height - 4),
5998
+ rx: 6,
5999
+ ry: 6,
6106
6000
  fill: node.color,
6107
6001
  className: `c-chart__treemap-node ${isHovered ? "c-chart__treemap-node--hovered" : ""} ${isSelected ? "c-chart__treemap-node--selected" : ""}`,
6108
6002
  onClick: () => {
@@ -6110,8 +6004,8 @@ const DEFAULT_COLOR_CONFIG = {
6110
6004
  },
6111
6005
  onMouseEnter: e => {
6112
6006
  setHoveredNode(node);
6113
- const rect = e.currentTarget.getBoundingClientRect();
6114
- handlers.onPointHover(0, 0, node.x, node.y, rect.left + rect.width / 2, rect.top + rect.height / 2);
6007
+ const rect = e.currentTarget.getBoundingClientRect(), pointIndex = data.indexOf(node.originalData);
6008
+ handlers.onPointHover(0, pointIndex >= 0 ? pointIndex : 0, node.x, node.y, rect.left + rect.width / 2, rect.top + rect.height / 2);
6115
6009
  },
6116
6010
  onMouseLeave: () => {
6117
6011
  setHoveredNode(null), handlers.onPointLeave();
@@ -6123,13 +6017,21 @@ const DEFAULT_COLOR_CONFIG = {
6123
6017
  dominantBaseline: "middle",
6124
6018
  className: "c-chart__treemap-label",
6125
6019
  style: {
6126
- fontSize: labelConfig.fontSize,
6127
- fill: labelConfig.textColor
6020
+ fontSize: labelConfig.fontSize
6128
6021
  },
6129
6022
  children: node.label
6130
6023
  }) ]
6131
6024
  }, node.id);
6132
- }))
6025
+ })), showTooltips && hoveredPoint && renderedDatasets[hoveredPoint.datasetIndex]?.data?.[hoveredPoint.pointIndex] && jsx(ChartTooltip, {
6026
+ dataPoint: renderedDatasets[hoveredPoint.datasetIndex].data[hoveredPoint.pointIndex],
6027
+ datasetLabel: renderedDatasets[hoveredPoint.datasetIndex]?.label,
6028
+ datasetColor: renderedDatasets[hoveredPoint.datasetIndex]?.color || colors[hoveredPoint.datasetIndex % colors.length],
6029
+ position: {
6030
+ x: hoveredPoint.clientX,
6031
+ y: hoveredPoint.clientY
6032
+ },
6033
+ visible: !0
6034
+ }) ]
6133
6035
  });
6134
6036
  }), [ data, algorithm, generateColor, squarify, labelConfig, hoveredNode, selectedNode ]), datasets = useMemo((() => [ {
6135
6037
  label: "Treemap Data",
@@ -6614,5 +6516,5 @@ const smoothStep = (a, b, t) => {
6614
6516
  value: "Module"
6615
6517
  }));
6616
6518
 
6617
- export { AnimatedChart, AreaChart, BarChart, BubbleChart, CandlestickChart, Chart, ChartRenderer, DonutChart, FunnelChart, GaugeChart, HeatmapChart, LineChart, MultiAxisChart, PieChart, RadarChart, ScatterChart, TreemapChart, WaterfallChart };
6519
+ export { AreaChart, BarChart, BubbleChart, CandlestickChart, Chart, ChartRenderer, DonutChart, FunnelChart, GaugeChart, HeatmapChart, LineChart, MultiAxisChart, PieChart, RadarChart, ScatterChart, TreemapChart, WaterfallChart };
6618
6520
  //# sourceMappingURL=charts.js.map