@shohojdhara/atomix 0.4.3 → 0.4.5
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.
- package/dist/atomix.css +26 -5
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +1 -1
- package/dist/atomix.min.css.map +1 -1
- package/dist/charts.js +4 -16
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +4 -4
- package/dist/core.js +14 -26
- package/dist/core.js.map +1 -1
- package/dist/forms.js +4 -16
- package/dist/forms.js.map +1 -1
- package/dist/heavy.js +9 -21
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +40 -16
- package/dist/index.esm.js +307 -341
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +337 -357
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/package.json +1 -1
- package/src/components/AtomixGlass/AtomixGlass.tsx +2 -15
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +3 -8
- package/src/components/Breadcrumb/Breadcrumb.tsx +5 -5
- package/src/components/Breadcrumb/BreadcrumbCompound.test.tsx +2 -2
- package/src/components/Button/Button.tsx +6 -6
- package/src/components/Card/Card.tsx +3 -3
- package/src/components/Dropdown/Dropdown.tsx +5 -3
- package/src/components/Footer/Footer.tsx +124 -166
- package/src/components/Footer/FooterLink.tsx +16 -19
- package/src/components/Footer/FooterSection.tsx +40 -39
- package/src/components/Footer/FooterSocialLink.tsx +59 -58
- package/src/components/Footer/README.md +1 -1
- package/src/components/Hero/Hero.tsx +72 -142
- package/src/components/Navigation/Menu/MegaMenu.tsx +17 -12
- package/src/components/Navigation/Menu/Menu.tsx +49 -24
- package/src/components/Navigation/Nav/NavItem.tsx +5 -3
- package/src/components/Navigation/SideMenu/SideMenu.tsx +2 -2
- package/src/components/Navigation/SideMenu/SideMenuItem.tsx +4 -4
- package/src/components/Slider/Slider.tsx +7 -4
- package/src/lib/composables/useFooter.ts +117 -20
- package/src/lib/composables/useSlider.ts +3 -1
- package/src/lib/types/components.ts +44 -12
- package/src/styles/06-components/_components.atomix-glass.scss +39 -5
- package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +0 -222
|
@@ -39,11 +39,12 @@ export const NavItem = forwardRef<HTMLLIElement, NavItemProps>(
|
|
|
39
39
|
megaMenu = false,
|
|
40
40
|
active = false,
|
|
41
41
|
href,
|
|
42
|
+
target,
|
|
42
43
|
onClick,
|
|
43
44
|
className = '',
|
|
44
45
|
disabled = false,
|
|
45
46
|
'aria-expanded': ariaExpanded,
|
|
46
|
-
|
|
47
|
+
linkComponent,
|
|
47
48
|
},
|
|
48
49
|
ref
|
|
49
50
|
) => {
|
|
@@ -139,6 +140,7 @@ export const NavItem = forwardRef<HTMLLIElement, NavItemProps>(
|
|
|
139
140
|
ref: combinedRef,
|
|
140
141
|
href: href || '#',
|
|
141
142
|
to: href || '#',
|
|
143
|
+
target,
|
|
142
144
|
className: navLinkClass,
|
|
143
145
|
onClick: dropdown || megaMenu ? handleDropdownToggle : handleClick(onClick),
|
|
144
146
|
'aria-disabled': disabled,
|
|
@@ -150,9 +152,9 @@ export const NavItem = forwardRef<HTMLLIElement, NavItemProps>(
|
|
|
150
152
|
|
|
151
153
|
return (
|
|
152
154
|
<li className={navItemClass} role="menuitem" aria-haspopup={dropdown || megaMenu}>
|
|
153
|
-
{
|
|
155
|
+
{linkComponent ? (
|
|
154
156
|
(() => {
|
|
155
|
-
const Component =
|
|
157
|
+
const Component = linkComponent as React.ComponentType<any>;
|
|
156
158
|
return (
|
|
157
159
|
<Component {...linkProps}>
|
|
158
160
|
{dropdown || megaMenu ? childContent[0] : children}
|
|
@@ -39,7 +39,7 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
|
|
|
39
39
|
toggleIcon,
|
|
40
40
|
id,
|
|
41
41
|
glass,
|
|
42
|
-
|
|
42
|
+
linkComponent,
|
|
43
43
|
},
|
|
44
44
|
ref
|
|
45
45
|
) => {
|
|
@@ -287,7 +287,7 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
|
|
|
287
287
|
active={subItem.active}
|
|
288
288
|
disabled={subItem.disabled}
|
|
289
289
|
icon={subItem.icon}
|
|
290
|
-
|
|
290
|
+
linkComponent={linkComponent}
|
|
291
291
|
>
|
|
292
292
|
{subItem.title}
|
|
293
293
|
</SideMenuItem>
|
|
@@ -18,7 +18,7 @@ import { useSideMenuItem } from '../../../lib/composables/useSideMenu';
|
|
|
18
18
|
*
|
|
19
19
|
* // With icon and custom link component
|
|
20
20
|
* import Link from 'next/link';
|
|
21
|
-
* <SideMenuItem href="/settings" icon={<Icon name="Settings" />}
|
|
21
|
+
* <SideMenuItem href="/settings" icon={<Icon name="Settings" />} linkComponent={Link}>
|
|
22
22
|
* Settings
|
|
23
23
|
* </SideMenuItem>
|
|
24
24
|
*
|
|
@@ -45,7 +45,7 @@ export const SideMenuItem = forwardRef<HTMLAnchorElement | HTMLButtonElement, Si
|
|
|
45
45
|
className = '',
|
|
46
46
|
target,
|
|
47
47
|
rel,
|
|
48
|
-
|
|
48
|
+
linkComponent: linkComponentProp,
|
|
49
49
|
},
|
|
50
50
|
ref
|
|
51
51
|
) => {
|
|
@@ -59,8 +59,8 @@ export const SideMenuItem = forwardRef<HTMLAnchorElement | HTMLButtonElement, Si
|
|
|
59
59
|
|
|
60
60
|
// Render as link if href is provided
|
|
61
61
|
if (href) {
|
|
62
|
-
if (
|
|
63
|
-
const LinkComp =
|
|
62
|
+
if (linkComponentProp) {
|
|
63
|
+
const LinkComp = linkComponentProp as React.ComponentType<any>;
|
|
64
64
|
const linkProps: {
|
|
65
65
|
ref?: React.Ref<HTMLAnchorElement>;
|
|
66
66
|
className?: string;
|
|
@@ -25,9 +25,12 @@ export const Slider = forwardRef<HTMLDivElement, SliderProps>((props, ref) => {
|
|
|
25
25
|
...rest
|
|
26
26
|
} = props;
|
|
27
27
|
|
|
28
|
+
// Ensure slides is an array to prevent .map errors
|
|
29
|
+
const validSlides = Array.isArray(slides) ? slides : [];
|
|
30
|
+
|
|
28
31
|
// Hooks must be called unconditionally - before early return
|
|
29
32
|
const slider = useSlider({
|
|
30
|
-
slides:
|
|
33
|
+
slides: validSlides,
|
|
31
34
|
slidesToShow,
|
|
32
35
|
spaceBetween,
|
|
33
36
|
loop,
|
|
@@ -65,7 +68,7 @@ export const Slider = forwardRef<HTMLDivElement, SliderProps>((props, ref) => {
|
|
|
65
68
|
return allSlides.length * (slideWidth + spaceBetween) - spaceBetween;
|
|
66
69
|
}, [allSlides.length, slideWidth, spaceBetween]);
|
|
67
70
|
|
|
68
|
-
if (
|
|
71
|
+
if (validSlides.length === 0) {
|
|
69
72
|
return (
|
|
70
73
|
<div className="c-slider c-slider--empty" style={{ height, width, ...style }}>
|
|
71
74
|
<div className="c-slider__empty-message">No slides available</div>
|
|
@@ -131,7 +134,7 @@ export const Slider = forwardRef<HTMLDivElement, SliderProps>((props, ref) => {
|
|
|
131
134
|
(() => {
|
|
132
135
|
if (!loop) return index === realIndex;
|
|
133
136
|
// For triple array: check if this slide index matches current real index
|
|
134
|
-
return index %
|
|
137
|
+
return index % validSlides.length === realIndex;
|
|
135
138
|
})() && 'c-slider__slide--active',
|
|
136
139
|
(slide as any).isClone && 'c-slider__slide--duplicate',
|
|
137
140
|
]
|
|
@@ -211,7 +214,7 @@ export const Slider = forwardRef<HTMLDivElement, SliderProps>((props, ref) => {
|
|
|
211
214
|
|
|
212
215
|
{pagination && (
|
|
213
216
|
<div className="c-slider__pagination">
|
|
214
|
-
{
|
|
217
|
+
{validSlides.map((_, index) => (
|
|
215
218
|
<button
|
|
216
219
|
key={index}
|
|
217
220
|
type="button"
|
|
@@ -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
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
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[
|
|
111
|
+
FOOTER.CLASSES[layoutKey] || FOOTER.CLASSES.COLUMNS,
|
|
36
112
|
`c-footer--${variant}`,
|
|
37
|
-
FOOTER.CLASSES[
|
|
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
|
-
|
|
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
|
-
|
|
48
|
-
|
|
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
|
-
|
|
55
|
-
|
|
132
|
+
]
|
|
133
|
+
.filter(Boolean)
|
|
134
|
+
.join(' ');
|
|
135
|
+
}, [layout]);
|
|
136
|
+
|
|
56
137
|
const bottomClass = FOOTER.CLASSES.BOTTOM;
|
|
57
138
|
|
|
58
|
-
//
|
|
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
|
-
|
|
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);
|
|
@@ -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
|
-
|
|
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
|
|
1574
|
+
* <SideMenu linkComponent={Link} />
|
|
1548
1575
|
*
|
|
1549
1576
|
* // React Router
|
|
1550
1577
|
* import { Link } from 'react-router-dom';
|
|
1551
|
-
* <SideMenu
|
|
1578
|
+
* <SideMenu linkComponent={Link} />
|
|
1552
1579
|
* ```
|
|
1553
1580
|
*/
|
|
1554
|
-
|
|
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?:
|
|
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
|
|
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"
|
|
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"
|
|
1672
|
+
* <SideMenuItem href="/about" linkComponent={Link}>About</SideMenuItem>
|
|
1646
1673
|
* ```
|
|
1647
1674
|
*/
|
|
1648
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
6584
|
+
linkComponent?: React.ElementType;
|
|
6553
6585
|
}
|
|
6554
6586
|
|
|
6555
6587
|
/**
|
|
@@ -9,16 +9,46 @@
|
|
|
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:
|
|
12
|
+
--atomix-glass-transition: transform var(--atomix-transition-duration, 0.15s) ease-out;
|
|
13
13
|
--atomix-glass-position: absolute;
|
|
14
14
|
--atomix-glass-container-width: 100%;
|
|
15
15
|
--atomix-glass-container-height: 100%;
|
|
16
16
|
--atomix-glass-border-width: var(--atomix-spacing-0-5, 0.09375rem);
|
|
17
17
|
|
|
18
|
+
// =========================================================================
|
|
19
|
+
// Z-INDEX STACKING ORDER (local scale, scoped to this component)
|
|
20
|
+
// =========================================================================
|
|
21
|
+
// 0: background layers
|
|
22
|
+
// 1: filter (SVG filter + backdrop)
|
|
23
|
+
// 2: base / overlay effect layers
|
|
24
|
+
// 3: hover effect layers
|
|
25
|
+
// 4: content (user-facing children)
|
|
26
|
+
// 5: border-1
|
|
27
|
+
// 6: border-2
|
|
28
|
+
// 7: overlay-highlight
|
|
29
|
+
// =========================================================================
|
|
30
|
+
--_glass-z-background: 0;
|
|
31
|
+
--_glass-z-filter: 1;
|
|
32
|
+
--_glass-z-effect: 2;
|
|
33
|
+
--_glass-z-hover: 3;
|
|
34
|
+
--_glass-z-overlay-highlight: 4;
|
|
35
|
+
--_glass-z-border-1: 5;
|
|
36
|
+
--_glass-z-border-2: 6;
|
|
37
|
+
--_glass-z-content: 7;
|
|
38
|
+
|
|
18
39
|
// Base layer styles for all effect layers (hover, border, overlay)
|
|
19
40
|
&__hover-1,
|
|
20
41
|
&__hover-2,
|
|
21
|
-
&__hover-3
|
|
42
|
+
&__hover-3 {
|
|
43
|
+
position: absolute;
|
|
44
|
+
inset: 0;
|
|
45
|
+
pointer-events: none;
|
|
46
|
+
border-radius: var(--atomix-glass-radius);
|
|
47
|
+
transform: var(--atomix-glass-transform);
|
|
48
|
+
transition: var(--atomix-glass-transition);
|
|
49
|
+
z-index: var(--_glass-z-hover);
|
|
50
|
+
}
|
|
51
|
+
|
|
22
52
|
&__base,
|
|
23
53
|
&__overlay {
|
|
24
54
|
position: absolute;
|
|
@@ -27,6 +57,7 @@
|
|
|
27
57
|
border-radius: var(--atomix-glass-radius);
|
|
28
58
|
transform: var(--atomix-glass-transform);
|
|
29
59
|
transition: var(--atomix-glass-transition);
|
|
60
|
+
z-index: var(--_glass-z-effect);
|
|
30
61
|
}
|
|
31
62
|
|
|
32
63
|
// Interactive hover effects
|
|
@@ -80,6 +111,7 @@
|
|
|
80
111
|
transform: var(--atomix-glass-transform);
|
|
81
112
|
transition: var(--atomix-glass-transition);
|
|
82
113
|
mix-blend-mode: screen;
|
|
114
|
+
z-index: var(--_glass-z-overlay-highlight);
|
|
83
115
|
// Dynamic opacity and background are set via inline styles
|
|
84
116
|
// Opacity is calculated: opacityValues.over * OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER
|
|
85
117
|
// Background gradient uses constants for positioning
|
|
@@ -119,7 +151,7 @@
|
|
|
119
151
|
&__border-1 {
|
|
120
152
|
opacity: var(--atomix-opacity-20, 0.2);
|
|
121
153
|
mix-blend-mode: screen;
|
|
122
|
-
z-index: var(--
|
|
154
|
+
z-index: var(--_glass-z-border-1);
|
|
123
155
|
background: var(--atomix-glass-border-gradient-1, none);
|
|
124
156
|
box-shadow: var(
|
|
125
157
|
--atomix-glass-border-shadow,
|
|
@@ -131,7 +163,7 @@
|
|
|
131
163
|
|
|
132
164
|
&__border-2 {
|
|
133
165
|
mix-blend-mode: overlay;
|
|
134
|
-
z-index: var(--
|
|
166
|
+
z-index: var(--_glass-z-border-2);
|
|
135
167
|
background: var(--atomix-glass-border-gradient-2, none);
|
|
136
168
|
box-shadow: var(
|
|
137
169
|
--atomix-glass-border-shadow,
|
|
@@ -164,6 +196,7 @@
|
|
|
164
196
|
width: 100%;
|
|
165
197
|
height: 100%;
|
|
166
198
|
pointer-events: none;
|
|
199
|
+
z-index: var(--_glass-z-filter);
|
|
167
200
|
|
|
168
201
|
svg {
|
|
169
202
|
border-radius: var(--atomix-glass-radius);
|
|
@@ -188,6 +221,7 @@
|
|
|
188
221
|
width: var(--atomix-glass-container-width);
|
|
189
222
|
height: var(--atomix-glass-container-height);
|
|
190
223
|
border-radius: var(--atomix-glass-radius);
|
|
224
|
+
z-index: var(--_glass-z-content);
|
|
191
225
|
}
|
|
192
226
|
|
|
193
227
|
// Background layers for over-light mode
|
|
@@ -197,6 +231,7 @@
|
|
|
197
231
|
border-radius: var(--atomix-glass-radius);
|
|
198
232
|
transform: var(--atomix-glass-transform);
|
|
199
233
|
transition: var(--atomix-glass-transition);
|
|
234
|
+
z-index: var(--_glass-z-background);
|
|
200
235
|
|
|
201
236
|
&--dark {
|
|
202
237
|
background-color: var(--atomix-gray-9, #1f2937);
|
|
@@ -209,7 +244,6 @@
|
|
|
209
244
|
|
|
210
245
|
&--dark#{&}--over-light {
|
|
211
246
|
opacity: var(--atomix-opacity-50, 0.5);
|
|
212
|
-
z-index: -1;
|
|
213
247
|
}
|
|
214
248
|
|
|
215
249
|
&--black#{&}--over-light {
|