@shohojdhara/atomix 0.2.9 → 0.3.1
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/CHANGELOG.md +4 -0
- package/dist/atomix.css +309 -105
- package/dist/atomix.min.css +3 -5
- package/dist/index.d.ts +807 -51
- package/dist/index.esm.js +16367 -16405
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +16277 -16330
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/themes/applemix.css +309 -105
- package/dist/themes/applemix.min.css +5 -7
- package/dist/themes/boomdevs.css +202 -10
- package/dist/themes/boomdevs.min.css +3 -5
- package/dist/themes/esrar.css +309 -105
- package/dist/themes/esrar.min.css +4 -6
- package/dist/themes/flashtrade.css +310 -105
- package/dist/themes/flashtrade.min.css +5 -7
- package/dist/themes/mashroom.css +300 -96
- package/dist/themes/mashroom.min.css +4 -6
- package/dist/themes/shaj-default.css +300 -96
- package/dist/themes/shaj-default.min.css +4 -6
- package/package.json +1 -1
- package/src/components/AtomixGlass/AtomixGlass.test.tsx +21 -32
- package/src/components/AtomixGlass/AtomixGlass.tsx +55 -42
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +205 -57
- package/src/components/AtomixGlass/GlassFilter.tsx +22 -8
- package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +221 -0
- package/src/components/AtomixGlass/atomixGLass.old.tsx +0 -3
- package/src/components/AtomixGlass/shader-utils.ts +8 -0
- package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +319 -100
- package/src/components/AtomixGlass/stories/Examples.stories.tsx +601 -105
- package/src/components/AtomixGlass/stories/Modes.stories.tsx +30 -12
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +173 -38
- package/src/components/AtomixGlass/stories/ShaderVariants.stories.tsx +18 -18
- package/src/components/AtomixGlass/stories/shared-components.tsx +27 -5
- package/src/components/Breadcrumb/Breadcrumb.tsx +8 -3
- package/src/components/Button/Button.tsx +62 -17
- package/src/components/Callout/Callout.test.tsx +8 -14
- package/src/components/Card/Card.tsx +103 -1
- package/src/components/Card/index.ts +3 -2
- package/src/components/Footer/Footer.stories.tsx +1 -2
- package/src/components/Footer/Footer.tsx +0 -5
- package/src/components/Footer/FooterLink.tsx +3 -2
- package/src/components/Footer/FooterSection.tsx +0 -7
- package/src/components/Icon/index.ts +1 -1
- package/src/components/Modal/Modal.stories.tsx +29 -38
- package/src/components/Modal/Modal.tsx +4 -4
- package/src/components/Navigation/Nav/NavItem.tsx +8 -3
- package/src/components/Navigation/SideMenu/SideMenu.tsx +49 -41
- package/src/components/Navigation/SideMenu/SideMenuItem.tsx +63 -19
- package/src/components/Popover/Popover.tsx +1 -1
- package/src/components/VideoPlayer/VideoPlayer.stories.tsx +977 -400
- package/src/components/VideoPlayer/VideoPlayer.tsx +1 -6
- package/src/lib/composables/shared-mouse-tracker.ts +133 -0
- package/src/lib/composables/useAtomixGlass.ts +303 -115
- package/src/lib/theme/ThemeManager.integration.test.ts +124 -0
- package/src/lib/theme/ThemeManager.stories.tsx +13 -13
- package/src/lib/theme/ThemeManager.test.ts +4 -0
- package/src/lib/theme/ThemeManager.ts +203 -59
- package/src/lib/theme/ThemeProvider.tsx +183 -33
- package/src/lib/theme/composeTheme.ts +375 -0
- package/src/lib/theme/createTheme.test.ts +475 -0
- package/src/lib/theme/createTheme.ts +510 -0
- package/src/lib/theme/generateCSSVariables.ts +713 -0
- package/src/lib/theme/index.ts +67 -0
- package/src/lib/theme/themeUtils.ts +333 -0
- package/src/lib/theme/types.ts +337 -8
- package/src/lib/theme/useTheme.test.tsx +2 -1
- package/src/lib/theme/useTheme.ts +6 -22
- package/src/lib/types/components.ts +152 -57
- package/src/styles/01-settings/_index.scss +2 -2
- package/src/styles/01-settings/_settings.badge.scss +2 -2
- package/src/styles/01-settings/_settings.border-radius.scss +1 -1
- package/src/styles/01-settings/{_settings.maps.scss → _settings.design-tokens.scss} +163 -49
- package/src/styles/01-settings/_settings.modal.scss +1 -1
- package/src/styles/01-settings/_settings.spacing.scss +14 -13
- package/src/styles/03-generic/_generic.root.scss +131 -50
- package/src/styles/05-objects/_objects.block.scss +1 -1
- package/src/styles/06-components/_components.atomix-glass.scss +20 -22
- package/src/styles/06-components/_components.badge.scss +2 -2
- package/src/styles/06-components/_components.button.scss +1 -1
- package/src/styles/06-components/_components.callout.scss +1 -1
- package/src/styles/06-components/_components.card.scss +74 -2
- package/src/styles/06-components/_components.chart.scss +1 -1
- package/src/styles/06-components/_components.dropdown.scss +6 -0
- package/src/styles/06-components/_components.footer.scss +1 -1
- package/src/styles/06-components/_components.list-group.scss +1 -1
- package/src/styles/06-components/_components.list.scss +1 -1
- package/src/styles/06-components/_components.menu.scss +1 -1
- package/src/styles/06-components/_components.messages.scss +1 -1
- package/src/styles/06-components/_components.modal.scss +7 -2
- package/src/styles/06-components/_components.navbar.scss +1 -1
- package/src/styles/06-components/_components.popover.scss +10 -0
- package/src/styles/06-components/_components.product-review.scss +1 -1
- package/src/styles/06-components/_components.progress.scss +1 -1
- package/src/styles/06-components/_components.rating.scss +1 -1
- package/src/styles/06-components/_components.spinner.scss +1 -1
- package/src/styles/99-utilities/_utilities.background.scss +1 -1
- package/src/styles/99-utilities/_utilities.border.scss +1 -1
- package/src/styles/99-utilities/_utilities.link.scss +1 -1
- package/src/styles/99-utilities/_utilities.text.scss +1 -1
|
@@ -1,11 +1,32 @@
|
|
|
1
|
-
import React, { useState, useEffect, useRef, forwardRef } from 'react';
|
|
1
|
+
import React, { useState, useEffect, useRef, forwardRef, createContext, useContext } from 'react';
|
|
2
2
|
import { SideMenuProps } from '../../../lib/types/components';
|
|
3
3
|
import { useSideMenu } from '../../../lib/composables/useSideMenu';
|
|
4
4
|
import { Icon } from '../../Icon';
|
|
5
5
|
import { AtomixGlass } from '../../AtomixGlass/AtomixGlass';
|
|
6
|
+
import useForkRef from '../../../lib/utils/useForkRef';
|
|
6
7
|
import SideMenuList from './SideMenuList';
|
|
7
8
|
import SideMenuItem from './SideMenuItem';
|
|
8
9
|
|
|
10
|
+
// Context for passing LinkComponent to SideMenuItem children
|
|
11
|
+
const SideMenuContext = createContext<{
|
|
12
|
+
LinkComponent?: React.ComponentType<{
|
|
13
|
+
href?: string;
|
|
14
|
+
to?: string;
|
|
15
|
+
children: React.ReactNode;
|
|
16
|
+
className?: string;
|
|
17
|
+
onClick?: (event: React.MouseEvent) => void;
|
|
18
|
+
target?: string;
|
|
19
|
+
rel?: string;
|
|
20
|
+
'aria-disabled'?: boolean;
|
|
21
|
+
'aria-current'?: string;
|
|
22
|
+
tabIndex?: number;
|
|
23
|
+
ref?: React.Ref<HTMLAnchorElement>;
|
|
24
|
+
}>;
|
|
25
|
+
}>({});
|
|
26
|
+
|
|
27
|
+
// Hook to use SideMenu context
|
|
28
|
+
export const useSideMenuContext = () => useContext(SideMenuContext);
|
|
29
|
+
|
|
9
30
|
/**
|
|
10
31
|
* SideMenu component provides a collapsible navigation menu with title and menu items.
|
|
11
32
|
* Automatically collapses on mobile devices and can be toggled via a header button.
|
|
@@ -38,6 +59,7 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
|
|
|
38
59
|
toggleIcon,
|
|
39
60
|
id,
|
|
40
61
|
glass,
|
|
62
|
+
LinkComponent,
|
|
41
63
|
},
|
|
42
64
|
ref
|
|
43
65
|
) => {
|
|
@@ -49,7 +71,6 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
|
|
|
49
71
|
generateSideMenuClass,
|
|
50
72
|
generateWrapperClass,
|
|
51
73
|
handleToggle,
|
|
52
|
-
handleDesktopCollapse,
|
|
53
74
|
} = useSideMenu({
|
|
54
75
|
isOpen,
|
|
55
76
|
onToggle,
|
|
@@ -59,6 +80,7 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
|
|
|
59
80
|
disabled,
|
|
60
81
|
});
|
|
61
82
|
|
|
83
|
+
// Mobile breakpoint matches md breakpoint (768px)
|
|
62
84
|
const MOBILE_BREAKPOINT = 768;
|
|
63
85
|
|
|
64
86
|
// Track mobile state
|
|
@@ -116,23 +138,23 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
|
|
|
116
138
|
});
|
|
117
139
|
}, [menuItems?.length]);
|
|
118
140
|
|
|
141
|
+
// Helper function to update nested wrapper height
|
|
142
|
+
const updateNestedHeight = (index: number, isOpen: boolean) => {
|
|
143
|
+
const wrapper = nestedWrapperRefs.current[index];
|
|
144
|
+
const inner = nestedInnerRefs.current[index];
|
|
145
|
+
if (wrapper && inner) {
|
|
146
|
+
wrapper.style.height = isOpen ? `${inner.scrollHeight}px` : '0px';
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
119
150
|
// Set initial heights for nested wrappers on mount and when menuItems change
|
|
120
151
|
useEffect(() => {
|
|
121
152
|
if (!menuItems?.length) return;
|
|
122
153
|
|
|
123
154
|
const timeoutId = setTimeout(() => {
|
|
124
155
|
menuItems.forEach((_, index) => {
|
|
125
|
-
const wrapper = nestedWrapperRefs.current[index];
|
|
126
|
-
const inner = nestedInnerRefs.current[index];
|
|
127
156
|
const isOpen = nestedItemStates[index] ?? true;
|
|
128
|
-
|
|
129
|
-
if (wrapper && inner) {
|
|
130
|
-
if (isOpen) {
|
|
131
|
-
wrapper.style.height = `${inner.scrollHeight}px`;
|
|
132
|
-
} else {
|
|
133
|
-
wrapper.style.height = '0px';
|
|
134
|
-
}
|
|
135
|
-
}
|
|
157
|
+
updateNestedHeight(index, isOpen);
|
|
136
158
|
});
|
|
137
159
|
}, 0);
|
|
138
160
|
|
|
@@ -149,22 +171,12 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
|
|
|
149
171
|
|
|
150
172
|
Object.keys(nestedItemStates).forEach(key => {
|
|
151
173
|
const index = Number(key);
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if (wrapper && inner) {
|
|
159
|
-
if (isOpen) {
|
|
160
|
-
wrapper.style.height = `${inner.scrollHeight}px`;
|
|
161
|
-
} else {
|
|
162
|
-
wrapper.style.height = '0px';
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
frameIds.push(frameId);
|
|
167
|
-
}
|
|
174
|
+
const isOpen = nestedItemStates[index] ?? true;
|
|
175
|
+
|
|
176
|
+
const frameId = requestAnimationFrame(() => {
|
|
177
|
+
updateNestedHeight(index, isOpen);
|
|
178
|
+
});
|
|
179
|
+
frameIds.push(frameId);
|
|
168
180
|
});
|
|
169
181
|
|
|
170
182
|
return () => {
|
|
@@ -172,15 +184,8 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
|
|
|
172
184
|
};
|
|
173
185
|
}, [nestedItemStates, menuItems?.length]);
|
|
174
186
|
|
|
175
|
-
// Combine refs
|
|
176
|
-
const combinedRef = (
|
|
177
|
-
(sideMenuRef as React.MutableRefObject<HTMLDivElement | null>).current = node;
|
|
178
|
-
if (typeof ref === 'function') {
|
|
179
|
-
ref(node);
|
|
180
|
-
} else if (ref) {
|
|
181
|
-
(ref as React.MutableRefObject<HTMLDivElement | null>).current = node;
|
|
182
|
-
}
|
|
183
|
-
};
|
|
187
|
+
// Combine refs using utility
|
|
188
|
+
const combinedRef = useForkRef(sideMenuRef, ref);
|
|
184
189
|
|
|
185
190
|
const sideMenuClass = generateSideMenuClass({
|
|
186
191
|
className,
|
|
@@ -230,8 +235,9 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
|
|
|
230
235
|
id={id ? `${id}-content` : undefined}
|
|
231
236
|
aria-hidden={shouldShowToggler ? !isOpenState : false}
|
|
232
237
|
>
|
|
233
|
-
<
|
|
234
|
-
{
|
|
238
|
+
<SideMenuContext.Provider value={{ LinkComponent }}>
|
|
239
|
+
<div ref={innerRef} className="c-side-menu__inner">
|
|
240
|
+
{children}
|
|
235
241
|
{menuItems?.map((item, index) => {
|
|
236
242
|
const isNestedItemOpen = nestedItemStates[index] ?? true;
|
|
237
243
|
const hasItems = item.items && item.items.length > 0;
|
|
@@ -302,6 +308,7 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
|
|
|
302
308
|
active={subItem.active}
|
|
303
309
|
disabled={subItem.disabled}
|
|
304
310
|
icon={subItem.icon}
|
|
311
|
+
LinkComponent={LinkComponent}
|
|
305
312
|
>
|
|
306
313
|
{subItem.title}
|
|
307
314
|
</SideMenuItem>
|
|
@@ -313,7 +320,8 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
|
|
|
313
320
|
</div>
|
|
314
321
|
);
|
|
315
322
|
})}
|
|
316
|
-
|
|
323
|
+
</div>
|
|
324
|
+
</SideMenuContext.Provider>
|
|
317
325
|
</div>
|
|
318
326
|
</>
|
|
319
327
|
);
|
|
@@ -330,7 +338,7 @@ export const SideMenu = forwardRef<HTMLDivElement, SideMenuProps>(
|
|
|
330
338
|
<AtomixGlass {...glassProps}>
|
|
331
339
|
<div
|
|
332
340
|
ref={combinedRef}
|
|
333
|
-
className={sideMenuClass
|
|
341
|
+
className={`${sideMenuClass} c-side-menu--glass`}
|
|
334
342
|
id={id}
|
|
335
343
|
style={style}
|
|
336
344
|
>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { forwardRef } from 'react';
|
|
2
2
|
import { SideMenuItemProps } from '../../../lib/types/components';
|
|
3
3
|
import { useSideMenuItem } from '../../../lib/composables/useSideMenu';
|
|
4
|
+
import { useSideMenuContext } from './SideMenu';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* SideMenuItem component represents a single navigation item in a side menu.
|
|
@@ -39,10 +40,14 @@ export const SideMenuItem = forwardRef<HTMLAnchorElement | HTMLButtonElement, Si
|
|
|
39
40
|
className = '',
|
|
40
41
|
target,
|
|
41
42
|
rel,
|
|
42
|
-
LinkComponent,
|
|
43
|
+
LinkComponent: LinkComponentProp,
|
|
43
44
|
},
|
|
44
45
|
ref
|
|
45
46
|
) => {
|
|
47
|
+
const { LinkComponent: LinkComponentFromContext } = useSideMenuContext();
|
|
48
|
+
// Use LinkComponent from props first, then fall back to context
|
|
49
|
+
const LinkComponent = LinkComponentProp ?? LinkComponentFromContext;
|
|
50
|
+
|
|
46
51
|
const { generateSideMenuItemClass, handleClick } = useSideMenuItem({
|
|
47
52
|
active,
|
|
48
53
|
disabled,
|
|
@@ -51,26 +56,65 @@ export const SideMenuItem = forwardRef<HTMLAnchorElement | HTMLButtonElement, Si
|
|
|
51
56
|
|
|
52
57
|
const itemClass = generateSideMenuItemClass();
|
|
53
58
|
|
|
54
|
-
const linkProps = {
|
|
55
|
-
ref: ref as React.Ref<HTMLAnchorElement>,
|
|
56
|
-
href: disabled ? undefined : href,
|
|
57
|
-
className: itemClass,
|
|
58
|
-
onClick: handleClick(onClick),
|
|
59
|
-
'aria-disabled': disabled,
|
|
60
|
-
'aria-current': (active ? 'page' : undefined) as React.AriaAttributes['aria-current'],
|
|
61
|
-
target: target,
|
|
62
|
-
rel: rel,
|
|
63
|
-
tabIndex: disabled ? -1 : 0,
|
|
64
|
-
};
|
|
65
|
-
|
|
66
59
|
// Render as link if href is provided
|
|
67
60
|
if (href) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
61
|
+
// When using a custom LinkComponent (e.g., Next.js Link, React Router Link)
|
|
62
|
+
if (LinkComponent) {
|
|
63
|
+
const Component = LinkComponent;
|
|
64
|
+
|
|
65
|
+
// Build link props - support both 'href' (Next.js) and 'to' (React Router)
|
|
66
|
+
// The Link component will use whichever prop it needs
|
|
67
|
+
const linkProps: {
|
|
68
|
+
ref?: React.Ref<HTMLAnchorElement>;
|
|
69
|
+
className?: string;
|
|
70
|
+
onClick?: (event: React.MouseEvent) => void;
|
|
71
|
+
'aria-disabled'?: boolean;
|
|
72
|
+
'aria-current'?: string;
|
|
73
|
+
target?: string;
|
|
74
|
+
rel?: string;
|
|
75
|
+
tabIndex?: number;
|
|
76
|
+
href?: string;
|
|
77
|
+
to?: string;
|
|
78
|
+
} = {
|
|
79
|
+
ref: ref as React.Ref<HTMLAnchorElement>,
|
|
80
|
+
className: itemClass,
|
|
81
|
+
onClick: disabled
|
|
82
|
+
? (e: React.MouseEvent) => {
|
|
83
|
+
e.preventDefault();
|
|
84
|
+
}
|
|
85
|
+
: onClick,
|
|
86
|
+
'aria-disabled': disabled,
|
|
87
|
+
'aria-current': active ? 'page' : undefined,
|
|
88
|
+
target: target,
|
|
89
|
+
rel: rel,
|
|
90
|
+
tabIndex: disabled ? -1 : 0,
|
|
91
|
+
// Support both Next.js (href) and React Router (to) Link components
|
|
92
|
+
// Pass both props - the Link component will use whichever it needs
|
|
93
|
+
...(disabled ? {} : { href, to: href }),
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<Component {...linkProps}>
|
|
98
|
+
{icon && <span className="c-side-menu__link-icon">{icon}</span>}
|
|
99
|
+
<span className="c-side-menu__link-text">{children}</span>
|
|
100
|
+
</Component>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Regular anchor tag
|
|
105
|
+
const linkProps = {
|
|
106
|
+
ref: ref as React.Ref<HTMLAnchorElement>,
|
|
107
|
+
href: disabled ? undefined : href,
|
|
108
|
+
className: itemClass,
|
|
109
|
+
onClick: handleClick(onClick),
|
|
110
|
+
'aria-disabled': disabled,
|
|
111
|
+
'aria-current': (active ? 'page' : undefined) as React.AriaAttributes['aria-current'],
|
|
112
|
+
target: target,
|
|
113
|
+
rel: rel,
|
|
114
|
+
tabIndex: disabled ? -1 : 0,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
return (
|
|
74
118
|
<a {...linkProps}>
|
|
75
119
|
{icon && <span className="c-side-menu__link-icon">{icon}</span>}
|
|
76
120
|
<span className="c-side-menu__link-text">{children}</span>
|
|
@@ -94,7 +94,7 @@ export const Popover: React.FC<PopoverProps> = ({
|
|
|
94
94
|
glass === true ? defaultGlassProps : { ...defaultGlassProps, ...glass };
|
|
95
95
|
|
|
96
96
|
return (
|
|
97
|
-
<AtomixGlass {...glassProps}>
|
|
97
|
+
<AtomixGlass {...glassProps} style={style}>
|
|
98
98
|
<div className="c-popover__content">
|
|
99
99
|
<div className="c-popover__content-inner">{content}</div>
|
|
100
100
|
</div>
|