@shohojdhara/atomix 0.4.4 → 0.4.6

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 (62) hide show
  1. package/dist/atomix.css +50 -11
  2. package/dist/atomix.css.map +1 -1
  3. package/dist/atomix.min.css +1 -1
  4. package/dist/atomix.min.css.map +1 -1
  5. package/dist/charts.js +184 -189
  6. package/dist/charts.js.map +1 -1
  7. package/dist/core.d.ts +4 -4
  8. package/dist/core.js +194 -199
  9. package/dist/core.js.map +1 -1
  10. package/dist/forms.js +184 -189
  11. package/dist/forms.js.map +1 -1
  12. package/dist/heavy.js +189 -194
  13. package/dist/heavy.js.map +1 -1
  14. package/dist/index.d.ts +44 -47
  15. package/dist/index.esm.js +496 -613
  16. package/dist/index.esm.js.map +1 -1
  17. package/dist/index.js +528 -631
  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 -39
  23. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +8 -42
  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/Breadcrumb/Breadcrumb.tsx +5 -5
  29. package/src/components/Breadcrumb/BreadcrumbCompound.test.tsx +2 -2
  30. package/src/components/Button/Button.tsx +6 -6
  31. package/src/components/Card/Card.tsx +3 -3
  32. package/src/components/Dropdown/Dropdown.tsx +5 -3
  33. package/src/components/Footer/Footer.tsx +124 -166
  34. package/src/components/Footer/FooterLink.tsx +16 -19
  35. package/src/components/Footer/FooterSection.tsx +40 -39
  36. package/src/components/Footer/FooterSocialLink.tsx +59 -58
  37. package/src/components/Footer/README.md +1 -1
  38. package/src/components/Hero/Hero.tsx +72 -142
  39. package/src/components/Navigation/Menu/MegaMenu.tsx +17 -12
  40. package/src/components/Navigation/Menu/Menu.tsx +49 -24
  41. package/src/components/Navigation/Nav/NavItem.tsx +5 -3
  42. package/src/components/Navigation/Navbar/Navbar.tsx +13 -5
  43. package/src/components/Navigation/SideMenu/SideMenu.tsx +2 -2
  44. package/src/components/Navigation/SideMenu/SideMenuItem.tsx +4 -4
  45. package/src/components/Slider/Slider.tsx +7 -4
  46. package/src/lib/composables/index.ts +1 -2
  47. package/src/lib/composables/useAtomixGlass.ts +246 -222
  48. package/src/lib/composables/useAtomixGlassStyles.ts +46 -23
  49. package/src/lib/composables/useFooter.ts +117 -20
  50. package/src/lib/composables/useSlider.ts +3 -1
  51. package/src/lib/constants/components.ts +3 -1
  52. package/src/lib/types/components.ts +44 -12
  53. package/src/styles/06-components/_components.atomix-glass.scss +72 -14
  54. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +0 -222
  55. package/src/lib/composables/atomix-glass/useGlassBackgroundDetection.ts +0 -329
  56. package/src/lib/composables/atomix-glass/useGlassCornerRadius.ts +0 -82
  57. package/src/lib/composables/atomix-glass/useGlassMouseTracking.ts +0 -153
  58. package/src/lib/composables/atomix-glass/useGlassOverLight.ts +0 -198
  59. package/src/lib/composables/atomix-glass/useGlassState.ts +0 -112
  60. package/src/lib/composables/atomix-glass/useGlassTransforms.ts +0 -160
  61. package/src/lib/composables/glass-styles.ts +0 -302
  62. package/src/lib/composables/useGlassContainer.ts +0 -177
@@ -1,5 +1,5 @@
1
1
  import { ATOMIX_GLASS } from '../constants/components';
2
- import { calculateDistance, calculateElementCenter, calculateMouseInfluence, validateGlassSize, clampBlur } from '../../components/AtomixGlass/glass-utils';
2
+ import { calculateDistance, calculateElementCenter, calculateMouseInfluence, validateGlassSize, clampBlur, smoothstep, softClamp } from '../../components/AtomixGlass/glass-utils';
3
3
  import type { GlassSize, MousePosition, OverLightObjectConfig } from '../types/components';
4
4
 
5
5
  /**
@@ -73,30 +73,53 @@ export const updateAtomixGlassStyles = (
73
73
  saturationBoost: baseOverLightConfig.saturationBoost
74
74
  };
75
75
 
76
- // Calculate elastic translation
77
- let elasticTranslation = { x: 0, y: 0 };
78
- if (!effectiveWithoutEffects && wrapperElement) {
79
- const rect = wrapperElement.getBoundingClientRect();
80
- const center = calculateElementCenter(rect);
81
-
82
- // Calculate fade in factor
83
- let fadeInFactor = 0;
84
- if (globalMousePosition.x && globalMousePosition.y && validateGlassSize(glassSize)) {
85
- const edgeDistanceX = Math.max(0, Math.abs(globalMousePosition.x - center.x) - glassSize.width / 2);
86
- const edgeDistanceY = Math.max(0, Math.abs(globalMousePosition.y - center.y) - glassSize.height / 2);
87
- const edgeDistance = calculateDistance({ x: edgeDistanceX, y: edgeDistanceY }, { x: 0, y: 0 });
88
- fadeInFactor = edgeDistance > ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE ? 0 : 1 - edgeDistance / ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE;
89
- }
76
+ let computedDirectionalScale = directionalScale;
77
+
78
+ // Calculate elastic translation and directional scale
79
+ let elasticTranslation = { x: 0, y: 0 };
80
+ if (!effectiveWithoutEffects && wrapperElement) {
81
+ const rect = wrapperElement.getBoundingClientRect();
82
+ const center = calculateElementCenter(rect);
83
+
84
+ // Mouse presence and edge distance logic
85
+ if (globalMousePosition.x && globalMousePosition.y && validateGlassSize(glassSize)) {
86
+ const deltaX = globalMousePosition.x - center.x;
87
+ const deltaY = globalMousePosition.y - center.y;
88
+ const edgeDistanceX = Math.max(0, Math.abs(deltaX) - glassSize.width / 2);
89
+ const edgeDistanceY = Math.max(0, Math.abs(deltaY) - glassSize.height / 2);
90
+ const edgeDistance = calculateDistance({ x: edgeDistanceX, y: edgeDistanceY }, { x: 0, y: 0 });
91
+
92
+ // Elastic translation
93
+ const rawT = edgeDistance > ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE ? 0 : 1 - edgeDistance / ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE;
94
+ const fadeInFactor = smoothstep(rawT);
95
+ elasticTranslation = {
96
+ x: deltaX * elasticity * 0.1 * fadeInFactor,
97
+ y: deltaY * elasticity * 0.1 * fadeInFactor,
98
+ };
90
99
 
91
- elasticTranslation = {
92
- x: (globalMousePosition.x - center.x) * elasticity * 0.1 * fadeInFactor,
93
- y: (globalMousePosition.y - center.y) * elasticity * 0.1 * fadeInFactor,
94
- };
95
- }
100
+ // Directional scale
101
+ if (!isOverLight && edgeDistance <= ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE) {
102
+ const centerDistance = calculateDistance(globalMousePosition, center);
103
+ if (centerDistance > 0) {
104
+ const normalizedX = deltaX / centerDistance;
105
+ const normalizedY = deltaY / centerDistance;
106
+ const stretchIntensity = Math.min(centerDistance / 300, 1) * elasticity * rawT;
107
+
108
+ const scaleX = 1 + Math.abs(normalizedX) * stretchIntensity * 0.3 - Math.abs(normalizedY) * stretchIntensity * 0.15;
109
+ const scaleY = 1 + Math.abs(normalizedY) * stretchIntensity * 0.3 - Math.abs(normalizedX) * stretchIntensity * 0.15;
110
+
111
+ const softScaleX = 1 - softClamp(Math.max(0, 1 - scaleX), 0.2);
112
+ const softScaleY = 1 - softClamp(Math.max(0, 1 - scaleY), 0.2);
113
+
114
+ computedDirectionalScale = `scaleX(${Math.max(0.85, softScaleX)}) scaleY(${Math.max(0.85, softScaleY)})`;
115
+ }
116
+ }
117
+ }
118
+ }
96
119
 
97
- const transformStyle = effectiveWithoutEffects
98
- ? isActive && Boolean(onClick) ? 'scale(0.98)' : 'scale(1)'
99
- : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) ${isActive && Boolean(onClick) ? 'scale(0.96)' : directionalScale}`;
120
+ const transformStyle = effectiveWithoutEffects
121
+ ? isActive && Boolean(onClick) ? 'scale(0.98)' : 'scale(1)'
122
+ : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) ${isActive && Boolean(onClick) ? 'scale(0.96)' : computedDirectionalScale}`;
100
123
 
101
124
  // Update Wrapper Styles (glassVars)
102
125
  if (wrapperElement) {
@@ -1,3 +1,4 @@
1
+ import { useMemo } from 'react';
1
2
  import { FooterLayout, ThemeColor, Size, SocialLink } from '../types/components';
2
3
  import { FOOTER } from '../constants/components';
3
4
 
@@ -8,61 +9,149 @@ export interface UseFooterOptions {
8
9
  sticky?: boolean;
9
10
  showNewsletter?: boolean;
10
11
  showBackToTop?: boolean;
12
+ showDivider?: boolean;
11
13
  socialLinks?: SocialLink[];
12
14
  onNewsletterSubmit?: (email: string) => void | Promise<void>;
13
15
  onBackToTop?: () => void;
16
+ glass?: boolean;
14
17
  className?: string;
15
18
  }
16
19
 
20
+ /** Raw column size map per layout */
21
+ type ColumnSizeMap = {
22
+ brand: number | 'auto';
23
+ content: number | 'auto';
24
+ newsletter: number | 'auto';
25
+ };
26
+
27
+ /**
28
+ * Resolves grid column size map for a given layout.
29
+ */
30
+ function resolveColumnSizes(layout: FooterLayout, showNewsletter: boolean): ColumnSizeMap {
31
+ switch (layout) {
32
+ case 'columns':
33
+ return {
34
+ brand: 4,
35
+ content: showNewsletter ? 4 : 8,
36
+ newsletter: showNewsletter ? 4 : 0,
37
+ };
38
+ case 'centered':
39
+ case 'minimal':
40
+ case 'stacked':
41
+ return {
42
+ brand: 12,
43
+ content: 12,
44
+ newsletter: showNewsletter ? 12 : 0,
45
+ };
46
+ case 'flexible':
47
+ return { brand: 'auto', content: 'auto', newsletter: 'auto' };
48
+ case 'sidebar':
49
+ return {
50
+ brand: 3,
51
+ content: 9,
52
+ newsletter: showNewsletter ? 9 : 0,
53
+ };
54
+ case 'wide':
55
+ return {
56
+ brand: 3,
57
+ content: 6,
58
+ newsletter: showNewsletter ? 3 : 0,
59
+ };
60
+ default:
61
+ return {
62
+ brand: 4,
63
+ content: showNewsletter ? 4 : 8,
64
+ newsletter: showNewsletter ? 4 : 0,
65
+ };
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Computes responsive GridCol props for a given column type.
71
+ */
72
+ function resolveResponsiveColProps(
73
+ columnType: 'brand' | 'content' | 'newsletter',
74
+ layout: FooterLayout,
75
+ columnSizes: ColumnSizeMap
76
+ ): Record<string, number | boolean> {
77
+ if (layout === 'flexible' && columnSizes[columnType] === 'auto') {
78
+ return { xs: 12, sm: true, md: true };
79
+ }
80
+
81
+ const isMultiColumn = layout === 'columns' || layout === 'sidebar' || layout === 'wide';
82
+ const baseMd = isMultiColumn ? columnSizes[columnType] : 12;
83
+
84
+ return { xs: 12, md: baseMd as number };
85
+ }
86
+
17
87
  export function useFooter(options: UseFooterOptions = {}) {
18
88
  const {
19
- layout = FOOTER.DEFAULTS.LAYOUT,
89
+ layout = FOOTER.DEFAULTS.LAYOUT as FooterLayout,
20
90
  variant = FOOTER.DEFAULTS.VARIANT,
21
- size = FOOTER.DEFAULTS.SIZE,
91
+ size = FOOTER.DEFAULTS.SIZE as Size,
22
92
  sticky = FOOTER.DEFAULTS.STICKY,
23
93
  showNewsletter = FOOTER.DEFAULTS.SHOW_NEWSLETTER,
24
94
  showBackToTop = FOOTER.DEFAULTS.SHOW_BACK_TO_TOP,
95
+ showDivider = FOOTER.DEFAULTS.SHOW_DIVIDER,
25
96
  socialLinks = [],
26
97
  onNewsletterSubmit,
27
98
  onBackToTop,
99
+ glass = false,
28
100
  className = '',
29
101
  } = options;
30
102
 
31
- // Generate footer classes
32
- const footerClass = (() => {
33
- const classes = [
103
+ // ---------- CSS class strings ----------
104
+
105
+ const footerClass = useMemo(() => {
106
+ const layoutKey = layout.toUpperCase() as keyof typeof FOOTER.CLASSES;
107
+ const sizeKey = size.toUpperCase() as keyof typeof FOOTER.CLASSES;
108
+
109
+ return [
34
110
  FOOTER.CLASSES.BASE,
35
- FOOTER.CLASSES[layout.toUpperCase() as keyof typeof FOOTER.CLASSES] || FOOTER.CLASSES.COLUMNS,
111
+ FOOTER.CLASSES[layoutKey] || FOOTER.CLASSES.COLUMNS,
36
112
  `c-footer--${variant}`,
37
- FOOTER.CLASSES[size.toUpperCase() as keyof typeof FOOTER.CLASSES] || FOOTER.CLASSES.MD,
113
+ FOOTER.CLASSES[sizeKey] || FOOTER.CLASSES.MD,
38
114
  sticky && FOOTER.CLASSES.STICKY,
39
115
  showNewsletter && 'c-footer--with-newsletter',
116
+ glass && 'c-footer--glass',
40
117
  className,
41
- ];
42
- return classes.filter(Boolean).join(' ');
43
- })();
118
+ ]
119
+ .filter(Boolean)
120
+ .join(' ');
121
+ }, [layout, variant, size, sticky, showNewsletter, glass, className]);
44
122
 
45
123
  const containerClass = FOOTER.CLASSES.CONTAINER;
46
124
  const brandClass = FOOTER.CLASSES.BRAND;
47
- const sectionsClass = (() => {
48
- const classes = [
125
+
126
+ const sectionsClass = useMemo(() => {
127
+ return [
49
128
  FOOTER.CLASSES.SECTIONS,
50
129
  layout === 'columns' && 'c-footer__sections--columns',
51
130
  layout === 'centered' && 'c-footer__sections--centered',
52
131
  layout === 'stacked' && 'c-footer__sections--stacked',
53
- ];
54
- return classes.filter(Boolean).join(' ');
55
- })();
132
+ ]
133
+ .filter(Boolean)
134
+ .join(' ');
135
+ }, [layout]);
136
+
56
137
  const bottomClass = FOOTER.CLASSES.BOTTOM;
57
138
 
58
- // Handle newsletter submission
139
+ // ---------- Grid helpers ----------
140
+
141
+ const columnSizes = useMemo(
142
+ () => resolveColumnSizes(layout, showNewsletter),
143
+ [layout, showNewsletter]
144
+ );
145
+
146
+ const getResponsiveColumnProps = (columnType: 'brand' | 'content' | 'newsletter') =>
147
+ resolveResponsiveColProps(columnType, layout, columnSizes);
148
+
149
+ // ---------- Handlers ----------
150
+
59
151
  const handleNewsletterSubmit = (email: string) => {
60
- if (onNewsletterSubmit) {
61
- onNewsletterSubmit(email);
62
- }
152
+ onNewsletterSubmit?.(email);
63
153
  };
64
154
 
65
- // Handle back to top
66
155
  const handleBackToTop = () => {
67
156
  if (onBackToTop) {
68
157
  onBackToTop();
@@ -72,14 +161,22 @@ export function useFooter(options: UseFooterOptions = {}) {
72
161
  };
73
162
 
74
163
  return {
164
+ // Classes
75
165
  footerClass,
76
166
  containerClass,
77
167
  brandClass,
78
168
  sectionsClass,
79
169
  bottomClass,
170
+ // Grid helpers
171
+ columnSizes,
172
+ getResponsiveColumnProps,
173
+ // Handlers
80
174
  handleNewsletterSubmit,
81
175
  handleBackToTop,
176
+ // Pass-through state
82
177
  socialLinks,
83
178
  showNewsletter,
179
+ showBackToTop,
180
+ showDivider,
84
181
  };
85
182
  }
@@ -26,7 +26,7 @@ export interface UseSliderReturn extends SliderState {
26
26
 
27
27
  export function useSlider(options: UseSliderOptions): UseSliderReturn {
28
28
  const {
29
- slides,
29
+ slides: rawSlides,
30
30
  slidesToShow = 1,
31
31
  spaceBetween = 0,
32
32
  loop = false,
@@ -39,6 +39,8 @@ export function useSlider(options: UseSliderOptions): UseSliderReturn {
39
39
  onSlideChange,
40
40
  } = options;
41
41
 
42
+ const slides = Array.isArray(rawSlides) ? rawSlides : [];
43
+
42
44
  const containerRef = useRef<HTMLDivElement | null>(null);
43
45
  const wrapperRef = useRef<HTMLDivElement | null>(null);
44
46
  const repositioningRef = useRef(false);
@@ -1663,7 +1663,9 @@ export const ATOMIX_GLASS = {
1663
1663
  ENABLE_OVER_LIGHT_LAYERS: true,
1664
1664
  },
1665
1665
  CONSTANTS: {
1666
- ACTIVATION_ZONE: 200,
1666
+ ACTIVATION_ZONE: 350,
1667
+ LERP_FACTOR: 0.08,
1668
+ SMOOTHSTEP_POWER: 2.5,
1667
1669
  MIN_BLUR: 0.1,
1668
1670
  MOUSE_INFLUENCE_DIVISOR: 100,
1669
1671
  EDGE_FADE_PIXELS: 2,
@@ -1344,6 +1344,11 @@ export interface NavItemProps extends BaseComponentProps {
1344
1344
  */
1345
1345
  href?: string;
1346
1346
 
1347
+ /**
1348
+ * Link target attribute (used with href)
1349
+ */
1350
+ target?: '_blank' | '_self' | '_parent' | '_top';
1351
+
1347
1352
  /**
1348
1353
  * Optional click handler
1349
1354
  */
@@ -1357,7 +1362,7 @@ export interface NavItemProps extends BaseComponentProps {
1357
1362
  /**
1358
1363
  * Optional custom link component
1359
1364
  */
1360
- LinkComponent?: React.ElementType;
1365
+ linkComponent?: React.ElementType;
1361
1366
  }
1362
1367
 
1363
1368
  /**
@@ -1409,6 +1414,16 @@ export interface MenuItemProps extends BaseComponentProps {
1409
1414
  */
1410
1415
  href?: string;
1411
1416
 
1417
+ /**
1418
+ * Link target attribute (used with href)
1419
+ */
1420
+ target?: '_blank' | '_self' | '_parent' | '_top';
1421
+
1422
+ /**
1423
+ * Optional custom link component
1424
+ */
1425
+ linkComponent?: React.ElementType;
1426
+
1412
1427
  /**
1413
1428
  * Item icon
1414
1429
  */
@@ -1469,6 +1484,18 @@ export interface MegaMenuLinkProps extends BaseComponentProps {
1469
1484
  */
1470
1485
  href: string;
1471
1486
 
1487
+ /**
1488
+ * Link target attribute (used with href)
1489
+ */
1490
+ target?: '_blank' | '_self' | '_parent' | '_top';
1491
+
1492
+ /**
1493
+ * Optional custom link component
1494
+ */
1495
+ linkComponent?: React.ElementType;
1496
+
1497
+
1498
+
1472
1499
  /**
1473
1500
  * Link content
1474
1501
  */
@@ -1544,14 +1571,14 @@ export interface SideMenuProps extends BaseComponentProps {
1544
1571
  * ```tsx
1545
1572
  * // Next.js
1546
1573
  * import Link from 'next/link';
1547
- * <SideMenu LinkComponent={Link} />
1574
+ * <SideMenu linkComponent={Link} />
1548
1575
  *
1549
1576
  * // React Router
1550
1577
  * import { Link } from 'react-router-dom';
1551
- * <SideMenu LinkComponent={Link} />
1578
+ * <SideMenu linkComponent={Link} />
1552
1579
  * ```
1553
1580
  */
1554
- LinkComponent?: React.ElementType;
1581
+ linkComponent?: React.ElementType;
1555
1582
 
1556
1583
  /**
1557
1584
  * Menu items
@@ -1623,7 +1650,7 @@ export interface SideMenuItemProps extends BaseComponentProps {
1623
1650
  /**
1624
1651
  * Link target attribute
1625
1652
  */
1626
- target?: string;
1653
+ target?: '_blank' | '_self' | '_parent' | '_top';
1627
1654
 
1628
1655
  /**
1629
1656
  * Link rel attribute
@@ -1632,20 +1659,20 @@ export interface SideMenuItemProps extends BaseComponentProps {
1632
1659
 
1633
1660
  /**
1634
1661
  * Optional custom link component (e.g., Next.js Link, React Router Link)
1635
- * If not provided, will use LinkComponent from parent SideMenu context
1662
+ * If not provided, will use linkComponent from parent SideMenu context
1636
1663
  *
1637
1664
  * @example
1638
1665
  * ```tsx
1639
1666
  * // Next.js
1640
1667
  * import Link from 'next/link';
1641
- * <SideMenuItem href="/about" LinkComponent={Link}>About</SideMenuItem>
1668
+ * <SideMenuItem href="/about" linkComponent={Link}>About</SideMenuItem>
1642
1669
  *
1643
1670
  * // React Router
1644
1671
  * import { Link } from 'react-router-dom';
1645
- * <SideMenuItem href="/about" LinkComponent={Link}>About</SideMenuItem>
1672
+ * <SideMenuItem href="/about" linkComponent={Link}>About</SideMenuItem>
1646
1673
  * ```
1647
1674
  */
1648
- LinkComponent?: React.ElementType;
1675
+ linkComponent?: React.ElementType;
1649
1676
  }
1650
1677
 
1651
1678
  /**
@@ -3460,6 +3487,11 @@ export interface DropdownItemProps extends BaseComponentProps {
3460
3487
  */
3461
3488
  href?: string;
3462
3489
 
3490
+ /**
3491
+ * Link target attribute (used with href)
3492
+ */
3493
+ target?: '_blank' | '_self' | '_parent' | '_top';
3494
+
3463
3495
  /**
3464
3496
  * Whether item is active
3465
3497
  */
@@ -3483,7 +3515,7 @@ export interface DropdownItemProps extends BaseComponentProps {
3483
3515
  /**
3484
3516
  * Optional custom link component
3485
3517
  */
3486
- LinkComponent?: React.ElementType;
3518
+ linkComponent?: React.ElementType;
3487
3519
  }
3488
3520
 
3489
3521
  /**
@@ -4044,7 +4076,7 @@ export interface CardProps extends BaseComponentProps {
4044
4076
  /**
4045
4077
  * Optional custom link component (e.g., Next.js Link, React Router Link)
4046
4078
  */
4047
- LinkComponent?: React.ElementType;
4079
+ linkComponent?: React.ElementType;
4048
4080
 
4049
4081
  /**
4050
4082
  * Optional click handler
@@ -6549,7 +6581,7 @@ export interface FooterLinkProps extends BaseComponentProps {
6549
6581
  /**
6550
6582
  * Custom link component (e.g., React Router Link)
6551
6583
  */
6552
- LinkComponent?: React.ElementType;
6584
+ linkComponent?: React.ElementType;
6553
6585
  }
6554
6586
 
6555
6587
  /**
@@ -9,16 +9,53 @@
9
9
  // CSS custom property defaults
10
10
  --atomix-glass-radius: var(--atomix-radius-md, 16px);
11
11
  --atomix-glass-transform: none;
12
- --atomix-glass-transition: transform var(--atomix-transition-duration, 0.15s) ease-out;
12
+ --atomix-glass-transition: transform var(--atomix-transition-duration, 0.45s)
13
+ cubic-bezier(0.22, 1, 0.36, 1);
13
14
  --atomix-glass-position: absolute;
14
15
  --atomix-glass-container-width: 100%;
15
16
  --atomix-glass-container-height: 100%;
16
17
  --atomix-glass-border-width: var(--atomix-spacing-0-5, 0.09375rem);
17
18
 
19
+ // =========================================================================
20
+ // Z-INDEX STACKING ORDER (local scale, scoped to this component)
21
+ // =========================================================================
22
+ // 0: background layers
23
+ // 1: container (wraps filter + content)
24
+ // 2: base / overlay effect layers
25
+ // 3: hover effect layers
26
+ // 4: overlay-highlight
27
+ // 5: border-1
28
+ // 6: border-2
29
+ // =========================================================================
30
+ // Internal layers within the container:
31
+ // filter = base + 1
32
+ // content = base + 7
33
+ // =========================================================================
34
+ --atomix-glass-base-z-index: 0;
35
+
36
+ --_glass-z-background: calc(var(--atomix-glass-base-z-index) + 0);
37
+ --_glass-z-container: calc(var(--atomix-glass-base-z-index) + 1);
38
+ --_glass-z-filter: calc(var(--atomix-glass-base-z-index) + 1);
39
+ --_glass-z-effect: calc(var(--atomix-glass-base-z-index) + 2);
40
+ --_glass-z-hover: calc(var(--atomix-glass-base-z-index) + 3);
41
+ --_glass-z-overlay-highlight: calc(var(--atomix-glass-base-z-index) + 4);
42
+ --_glass-z-border-1: calc(var(--atomix-glass-base-z-index) + 5);
43
+ --_glass-z-border-2: calc(var(--atomix-glass-base-z-index) + 6);
44
+ --_glass-z-content: calc(var(--atomix-glass-base-z-index) + 7);
45
+
18
46
  // Base layer styles for all effect layers (hover, border, overlay)
19
47
  &__hover-1,
20
48
  &__hover-2,
21
- &__hover-3,
49
+ &__hover-3 {
50
+ position: absolute;
51
+ inset: 0;
52
+ pointer-events: none;
53
+ border-radius: var(--atomix-glass-radius);
54
+ transform: var(--atomix-glass-transform);
55
+ transition: var(--atomix-glass-transition);
56
+ z-index: var(--_glass-z-hover);
57
+ }
58
+
22
59
  &__base,
23
60
  &__overlay {
24
61
  position: absolute;
@@ -27,6 +64,7 @@
27
64
  border-radius: var(--atomix-glass-radius);
28
65
  transform: var(--atomix-glass-transform);
29
66
  transition: var(--atomix-glass-transition);
67
+ z-index: var(--_glass-z-effect);
30
68
  }
31
69
 
32
70
  // Interactive hover effects
@@ -40,19 +78,25 @@
40
78
  }
41
79
 
42
80
  &__hover-1 {
43
- transition: opacity var(--atomix-transition-duration-fast, 0.15s) ease-out;
81
+ transition:
82
+ opacity 0.2s cubic-bezier(0.22, 1, 0.36, 1),
83
+ background 0.35s cubic-bezier(0.22, 1, 0.36, 1);
44
84
  opacity: var(--atomix-glass-hover-1-opacity, 0);
45
85
  background: var(--atomix-glass-hover-1-gradient, none);
46
86
  }
47
87
 
48
88
  &__hover-2 {
49
- transition: opacity var(--atomix-transition-duration-base, 0.3s) ease-out;
89
+ transition:
90
+ opacity 0.35s cubic-bezier(0.22, 1, 0.36, 1),
91
+ background 0.45s cubic-bezier(0.22, 1, 0.36, 1);
50
92
  opacity: var(--atomix-glass-hover-2-opacity, 0);
51
93
  background: var(--atomix-glass-hover-2-gradient, none);
52
94
  }
53
95
 
54
96
  &__hover-3 {
55
- transition: opacity var(--atomix-transition-duration-slow, 0.5s) ease-out;
97
+ transition:
98
+ opacity 0.55s cubic-bezier(0.22, 1, 0.36, 1),
99
+ background 0.6s cubic-bezier(0.22, 1, 0.36, 1);
56
100
  opacity: var(--atomix-glass-hover-3-opacity, 0);
57
101
  background: var(--atomix-glass-hover-3-gradient, none);
58
102
  }
@@ -80,9 +124,9 @@
80
124
  transform: var(--atomix-glass-transform);
81
125
  transition: var(--atomix-glass-transition);
82
126
  mix-blend-mode: screen;
83
- // Dynamic opacity and background are set via inline styles
84
- // Opacity is calculated: opacityValues.over * OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER
85
- // Background gradient uses constants for positioning
127
+ z-index: var(--_glass-z-overlay-highlight);
128
+ opacity: var(--atomix-glass-overlay-highlight-opacity, 0);
129
+ background: var(--atomix-glass-overlay-highlight-bg, none);
86
130
  }
87
131
 
88
132
  // Border effect layers - matching old version exactly
@@ -114,13 +158,12 @@
114
158
  border-radius: var(--atomix-glass-radius);
115
159
  transform: var(--atomix-glass-transform);
116
160
  transition: var(--atomix-glass-transition);
117
- z-index: var(--atomix-z-index-5);
118
161
  }
119
162
 
120
163
  &__border-1 {
121
164
  opacity: var(--atomix-opacity-20, 0.2);
122
165
  mix-blend-mode: screen;
123
- z-index: var(--atomix-z-index-5, 5);
166
+ z-index: var(--_glass-z-border-1);
124
167
  background: var(--atomix-glass-border-gradient-1, none);
125
168
  box-shadow: var(
126
169
  --atomix-glass-border-shadow,
@@ -132,7 +175,7 @@
132
175
 
133
176
  &__border-2 {
134
177
  mix-blend-mode: overlay;
135
- z-index: var(--atomix-z-index-6, 6);
178
+ z-index: var(--_glass-z-border-2);
136
179
  background: var(--atomix-glass-border-gradient-2, none);
137
180
  box-shadow: var(
138
181
  --atomix-glass-border-shadow,
@@ -149,6 +192,7 @@
149
192
  position: relative;
150
193
  border-radius: var(--atomix-glass-radius);
151
194
  transition: var(--atomix-glass-transition);
195
+ z-index: var(--_glass-z-container);
152
196
  }
153
197
 
154
198
  &__inner {
@@ -156,6 +200,8 @@
156
200
  height: var(--atomix-glass-container-height);
157
201
  position: relative;
158
202
  border-radius: var(--atomix-glass-radius);
203
+ padding: var(--atomix-glass-container-padding);
204
+ box-shadow: var(--atomix-glass-container-box-shadow);
159
205
  }
160
206
 
161
207
  &__filter {
@@ -165,6 +211,7 @@
165
211
  width: 100%;
166
212
  height: 100%;
167
213
  pointer-events: none;
214
+ z-index: var(--_glass-z-filter);
168
215
 
169
216
  svg {
170
217
  border-radius: var(--atomix-glass-radius);
@@ -175,13 +222,18 @@
175
222
  position: absolute;
176
223
  inset: 0;
177
224
  pointer-events: none;
178
- border-radius: var(--atomix-glass-radius);
225
+ border-radius: var(--atomix-glass-container-radius);
226
+ backdrop-filter: var(--atomix-glass-container-backdrop);
179
227
  }
180
228
 
181
229
  &__filter-shadow {
182
230
  position: absolute;
183
231
  inset: var(--atomix-glass-border-width);
184
232
  pointer-events: none;
233
+ border-radius: var(--atomix-glass-container-radius);
234
+ box-shadow: var(--atomix-glass-container-shadow);
235
+ opacity: var(--atomix-glass-container-shadow-opacity);
236
+ background: var(--atomix-glass-container-bg);
185
237
  }
186
238
 
187
239
  &__content {
@@ -189,15 +241,22 @@
189
241
  width: var(--atomix-glass-container-width);
190
242
  height: var(--atomix-glass-container-height);
191
243
  border-radius: var(--atomix-glass-radius);
244
+ z-index: var(--_glass-z-content);
245
+ text-shadow: var(--atomix-glass-container-text-shadow);
192
246
  }
193
247
 
194
248
  // Background layers for over-light mode
195
249
  &__background-layer {
196
- position: absolute;
250
+ position: var(--atomix-glass-position);
251
+ top: var(--atomix-glass-top);
252
+ left: var(--atomix-glass-left);
253
+ width: var(--atomix-glass-width);
254
+ height: var(--atomix-glass-height);
197
255
  pointer-events: none;
198
256
  border-radius: var(--atomix-glass-radius);
199
257
  transform: var(--atomix-glass-transform);
200
258
  transition: var(--atomix-glass-transition);
259
+ z-index: var(--_glass-z-background);
201
260
 
202
261
  &--dark {
203
262
  background-color: var(--atomix-gray-9, #1f2937);
@@ -210,7 +269,6 @@
210
269
 
211
270
  &--dark#{&}--over-light {
212
271
  opacity: var(--atomix-opacity-50, 0.5);
213
- z-index: -1;
214
272
  }
215
273
 
216
274
  &--black#{&}--over-light {