@shohojdhara/atomix 0.3.4 → 0.3.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 +9 -10
- package/dist/atomix.css.map +1 -0
- package/dist/atomix.min.css +15108 -11
- package/dist/atomix.min.css.map +1 -0
- package/dist/charts.d.ts +1929 -0
- package/dist/charts.js +6482 -0
- package/dist/charts.js.map +1 -0
- package/dist/core.d.ts +1289 -0
- package/dist/core.js +3357 -0
- package/dist/core.js.map +1 -0
- package/dist/forms.d.ts +1085 -0
- package/dist/forms.js +2450 -0
- package/dist/forms.js.map +1 -0
- package/dist/heavy.d.ts +636 -0
- package/dist/heavy.js +4550 -0
- package/dist/heavy.js.map +1 -0
- package/dist/index.d.ts +5161 -4990
- package/dist/index.esm.js +1457 -784
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1473 -790
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/layout.d.ts +300 -0
- package/dist/layout.js +336 -0
- package/dist/layout.js.map +1 -0
- package/dist/theme.d.ts +1992 -0
- package/dist/theme.js +5348 -0
- package/dist/theme.js.map +1 -0
- package/package.json +66 -20
- package/scripts/atomix-cli.js +544 -16
- package/scripts/cli/__tests__/cli-commands.test.js +204 -0
- package/scripts/cli/__tests__/utils.test.js +201 -0
- package/scripts/cli/__tests__/vitest.config.js +26 -0
- package/scripts/cli/interactive-init.js +1 -1
- package/scripts/cli/token-manager.js +32 -7
- package/scripts/cli/utils.js +347 -0
- package/src/components/Accordion/Accordion.tsx +5 -54
- package/src/components/Accordion/index.ts +1 -1
- package/src/components/Avatar/Avatar.tsx +3 -3
- package/src/components/Badge/Badge.tsx +3 -3
- package/src/components/Breadcrumb/Breadcrumb.tsx +3 -3
- package/src/components/Card/ElevationCard.tsx +1 -1
- package/src/components/Chart/AnimatedChart.tsx +19 -17
- package/src/components/Chart/AreaChart.tsx +5 -1
- package/src/components/Chart/BarChart.tsx +1 -0
- package/src/components/Chart/BubbleChart.tsx +6 -5
- package/src/components/Chart/ChartToolbar.tsx +1 -0
- package/src/components/Chart/FunnelChart.tsx +1 -1
- package/src/components/Chart/RadarChart.tsx +19 -12
- package/src/components/Chart/ScatterChart.tsx +3 -3
- package/src/components/Chart/TreemapChart.tsx +2 -1
- package/src/components/Chart/WaterfallChart.tsx +0 -1
- package/src/components/Chart/types.ts +12 -2
- package/src/components/Chart/utils.ts +4 -3
- package/src/components/DataTable/DataTable.tsx +3 -3
- package/src/components/Dropdown/Dropdown.tsx +12 -9
- package/src/components/Footer/FooterSection.tsx +3 -3
- package/src/components/Form/Checkbox.tsx +3 -3
- package/src/components/Form/Input.tsx +4 -2
- package/src/components/Form/Radio.tsx +3 -3
- package/src/components/Form/Select.tsx +3 -3
- package/src/components/Form/Textarea.tsx +4 -2
- package/src/components/List/List.stories.tsx +3 -3
- package/src/components/List/List.tsx +3 -3
- package/src/components/List/ListGroup.tsx +3 -1
- package/src/components/Modal/Modal.tsx +3 -3
- package/src/components/Navigation/Menu/MegaMenu.tsx +9 -3
- package/src/components/Navigation/Menu/Menu.tsx +9 -3
- package/src/components/Pagination/Pagination.tsx +6 -5
- package/src/components/PhotoViewer/PhotoViewerImage.tsx +2 -2
- package/src/components/Popover/Popover.tsx +4 -4
- package/src/components/Progress/Progress.tsx +6 -2
- package/src/components/Rating/Rating.tsx +5 -2
- package/src/components/Slider/Slider.tsx +10 -9
- package/src/components/Spinner/Spinner.tsx +3 -3
- package/src/components/Tabs/Tabs.tsx +3 -3
- package/src/components/Tooltip/Tooltip.tsx +3 -3
- package/src/components/index.ts +5 -2
- package/src/layouts/MasonryGrid/MasonryGrid.tsx +2 -2
- package/src/lib/composables/useChartPerformance.ts +102 -78
- package/src/lib/composables/useChartScale.ts +10 -0
- package/src/lib/composables/useHero.ts +9 -2
- package/src/lib/composables/useHeroBackgroundSlider.ts +5 -3
- package/src/lib/composables/useSideMenu.ts +1 -0
- package/src/lib/composables/useVideoPlayer.ts +3 -2
- package/src/lib/config/loader.ts +55 -13
- package/src/lib/hooks/index.ts +0 -1
- package/src/lib/hooks/useComponentCustomization.ts +10 -14
- package/src/lib/hooks/usePerformanceMonitor.ts +149 -0
- package/src/lib/patterns/index.ts +2 -2
- package/src/lib/patterns/slots.tsx +2 -2
- package/src/lib/theme/composeTheme.ts +1 -1
- package/src/lib/theme/core/ThemeEngine.ts +8 -0
- package/src/lib/theme/core/ThemeValidator.ts +5 -2
- package/src/lib/theme/devtools/Inspector.tsx +1 -1
- package/src/lib/theme/devtools/LiveEditor.tsx +11 -5
- package/src/lib/theme/generateCSSVariables.ts +1 -1
- package/src/lib/theme/i18n/rtl.ts +2 -1
- package/src/lib/theme/runtime/ThemeApplicator.ts +28 -11
- package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +3 -3
- package/src/lib/theme/runtime/ThemeManager.ts +4 -0
- package/src/lib/theme-tools.ts +1 -1
- package/src/lib/types/components.ts +183 -34
- package/src/lib/types/partProps.ts +0 -16
- package/src/lib/utils/fontPreloader.ts +148 -0
- package/src/lib/utils/index.ts +11 -0
- package/src/lib/utils/memoryMonitor.ts +189 -0
- package/src/styles/01-settings/_settings.fonts.scss +2 -5
- package/src/styles/03-generic/_generated-root.css +22 -1
- package/src/styles/06-components/_components.navbar.scss +0 -6
- package/src/themes/themes.config.js +37 -4
- package/scripts/build-themes.js +0 -208
- package/src/components/AtomixGlass/atomixGLass.old.tsx +0 -1263
|
@@ -54,6 +54,9 @@ export const Rating = forwardRef<HTMLDivElement, RatingProps>(
|
|
|
54
54
|
onChange,
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
+
// Create forked ref - must be called unconditionally
|
|
58
|
+
const forkedRef = useForkRef(internalRef, ref);
|
|
59
|
+
|
|
57
60
|
// Handle mouse enter on star with half-star support
|
|
58
61
|
const handleMouseEnter = useCallback(
|
|
59
62
|
(e: React.MouseEvent, starValue: number) => {
|
|
@@ -171,7 +174,7 @@ export const Rating = forwardRef<HTMLDivElement, RatingProps>(
|
|
|
171
174
|
// If using vanilla JS, just render the container
|
|
172
175
|
if (useVanillaJS) {
|
|
173
176
|
return (
|
|
174
|
-
<div className={ratingClasses} ref={
|
|
177
|
+
<div className={ratingClasses} ref={forkedRef} id={id} {...restProps}>
|
|
175
178
|
{/* Stars will be generated by the vanilla JS implementation */}
|
|
176
179
|
</div>
|
|
177
180
|
);
|
|
@@ -268,7 +271,7 @@ export const Rating = forwardRef<HTMLDivElement, RatingProps>(
|
|
|
268
271
|
const ratingContent = (
|
|
269
272
|
<div
|
|
270
273
|
className={ratingClasses}
|
|
271
|
-
ref={
|
|
274
|
+
ref={forkedRef}
|
|
272
275
|
id={id}
|
|
273
276
|
style={style}
|
|
274
277
|
data-readonly={readOnly ? 'true' : 'false'}
|
|
@@ -25,16 +25,9 @@ export const Slider = forwardRef<HTMLDivElement, SliderProps>((props, ref) => {
|
|
|
25
25
|
...rest
|
|
26
26
|
} = props;
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<div className="c-slider c-slider--empty" style={{ height, width, ...style }}>
|
|
31
|
-
<div className="c-slider__empty-message">No slides available</div>
|
|
32
|
-
</div>
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
28
|
+
// Hooks must be called unconditionally - before early return
|
|
36
29
|
const slider = useSlider({
|
|
37
|
-
slides,
|
|
30
|
+
slides: slides || [],
|
|
38
31
|
slidesToShow,
|
|
39
32
|
spaceBetween,
|
|
40
33
|
loop,
|
|
@@ -72,6 +65,14 @@ export const Slider = forwardRef<HTMLDivElement, SliderProps>((props, ref) => {
|
|
|
72
65
|
return allSlides.length * (slideWidth + spaceBetween) - spaceBetween;
|
|
73
66
|
}, [allSlides.length, slideWidth, spaceBetween]);
|
|
74
67
|
|
|
68
|
+
if (!slides || slides.length === 0) {
|
|
69
|
+
return (
|
|
70
|
+
<div className="c-slider c-slider--empty" style={{ height, width, ...style }}>
|
|
71
|
+
<div className="c-slider__empty-message">No slides available</div>
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
75
76
|
const containerClasses = [
|
|
76
77
|
'c-slider',
|
|
77
78
|
direction === 'vertical' && 'c-slider--vertical',
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
2
|
import { SpinnerProps } from '../../lib/types/components';
|
|
3
3
|
import { useSpinner } from '../../lib/composables/useSpinner';
|
|
4
4
|
import { SPINNER } from '../../lib/constants/components';
|
|
5
5
|
import { AtomixGlass } from '../AtomixGlass/AtomixGlass';
|
|
6
6
|
|
|
7
|
-
export const Spinner: React.FC<SpinnerProps> = ({
|
|
7
|
+
export const Spinner: React.FC<SpinnerProps> = memo(({
|
|
8
8
|
size = 'md',
|
|
9
9
|
variant = 'primary',
|
|
10
10
|
fullscreen = false,
|
|
@@ -43,7 +43,7 @@ export const Spinner: React.FC<SpinnerProps> = ({
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
return spinnerContent;
|
|
46
|
-
};
|
|
46
|
+
});
|
|
47
47
|
|
|
48
48
|
export type { SpinnerProps };
|
|
49
49
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, ReactNode } from 'react';
|
|
1
|
+
import React, { useState, ReactNode, memo } from 'react';
|
|
2
2
|
import { TAB } from '../../lib/constants/components';
|
|
3
3
|
import { AtomixGlass } from '../AtomixGlass/AtomixGlass';
|
|
4
4
|
import { AtomixGlassProps } from '../../lib/types/components';
|
|
@@ -61,7 +61,7 @@ export interface TabsProps {
|
|
|
61
61
|
/**
|
|
62
62
|
* Tabs component for switching between different content panels
|
|
63
63
|
*/
|
|
64
|
-
export const Tabs: React.FC<TabsProps> = ({
|
|
64
|
+
export const Tabs: React.FC<TabsProps> = memo(({
|
|
65
65
|
items,
|
|
66
66
|
activeIndex = TAB.DEFAULTS.ACTIVE_INDEX,
|
|
67
67
|
onTabChange,
|
|
@@ -137,7 +137,7 @@ export const Tabs: React.FC<TabsProps> = ({
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
return tabContent;
|
|
140
|
-
};
|
|
140
|
+
});
|
|
141
141
|
|
|
142
142
|
Tabs.displayName = 'Tabs';
|
|
143
143
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { ReactNode } from 'react';
|
|
1
|
+
import React, { ReactNode, memo } from 'react';
|
|
2
2
|
import { TOOLTIP } from '../../lib/constants/components';
|
|
3
3
|
import { AtomixGlass } from '../AtomixGlass/AtomixGlass';
|
|
4
4
|
import { AtomixGlassProps } from '../../lib/types/components';
|
|
@@ -60,7 +60,7 @@ export interface TooltipProps {
|
|
|
60
60
|
glass?: AtomixGlassProps | boolean;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
export const Tooltip: React.FC<TooltipProps> = ({
|
|
63
|
+
export const Tooltip: React.FC<TooltipProps> = memo(({
|
|
64
64
|
content,
|
|
65
65
|
children,
|
|
66
66
|
position = TOOLTIP.DEFAULTS.POSITION,
|
|
@@ -162,7 +162,7 @@ export const Tooltip: React.FC<TooltipProps> = ({
|
|
|
162
162
|
)}
|
|
163
163
|
</div>
|
|
164
164
|
);
|
|
165
|
-
};
|
|
165
|
+
});
|
|
166
166
|
|
|
167
167
|
Tooltip.displayName = 'Tooltip';
|
|
168
168
|
|
package/src/components/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export type { SliderProps, VideoPlayerProps } from '../lib/types/components';
|
|
2
|
-
export { default as Accordion
|
|
2
|
+
export { default as Accordion } from './Accordion/Accordion';
|
|
3
|
+
export type { AccordionProps } from '../lib/types/components';
|
|
3
4
|
export { default as AtomixLogo, type AtomixLogoProps } from './AtomixLogo/AtomixLogo';
|
|
4
5
|
export { default as AtomixGlass, type AtomixGlassProps } from './AtomixGlass';
|
|
5
6
|
export { default as Avatar, type AvatarProps } from './Avatar/Avatar';
|
|
@@ -37,7 +38,7 @@ export {
|
|
|
37
38
|
type BubbleDataPoint,
|
|
38
39
|
type CandlestickChartProps,
|
|
39
40
|
type CandlestickDataPoint,
|
|
40
|
-
|
|
41
|
+
// ChartProps exported separately from lib/types/components to avoid conflict
|
|
41
42
|
type DonutChartProps,
|
|
42
43
|
type FunnelChartProps,
|
|
43
44
|
type FunnelDataPoint,
|
|
@@ -56,6 +57,8 @@ export {
|
|
|
56
57
|
type WaterfallChartProps,
|
|
57
58
|
type WaterfallDataPoint,
|
|
58
59
|
} from './Chart';
|
|
60
|
+
// Export ChartProps from lib/types/components to avoid duplicate export conflict
|
|
61
|
+
export type { ChartProps } from '../lib/types/components';
|
|
59
62
|
export {
|
|
60
63
|
default as ColorModeToggle,
|
|
61
64
|
type ColorModeToggleProps,
|
|
@@ -374,7 +374,7 @@ export const MasonryGrid = forwardRef<HTMLDivElement, MasonryGridProps>(
|
|
|
374
374
|
const position = positions[index];
|
|
375
375
|
if (!position) {
|
|
376
376
|
return (
|
|
377
|
-
<div key={item.id} ref={item.ref} style={{ opacity: 0, position: 'absolute' }}>
|
|
377
|
+
<div key={item.id} ref={item.ref as React.LegacyRef<HTMLDivElement>} style={{ opacity: 0, position: 'absolute' }}>
|
|
378
378
|
{item.element}
|
|
379
379
|
</div>
|
|
380
380
|
);
|
|
@@ -382,7 +382,7 @@ export const MasonryGrid = forwardRef<HTMLDivElement, MasonryGridProps>(
|
|
|
382
382
|
return (
|
|
383
383
|
<div
|
|
384
384
|
key={item.id}
|
|
385
|
-
ref={item.ref}
|
|
385
|
+
ref={item.ref as React.LegacyRef<HTMLDivElement>}
|
|
386
386
|
className="o-masonry-grid__item"
|
|
387
387
|
style={{
|
|
388
388
|
position: 'absolute',
|
|
@@ -70,35 +70,33 @@ export function useChartPerformance() {
|
|
|
70
70
|
height: number,
|
|
71
71
|
padding: { top: number; right: number; bottom: number; left: number }
|
|
72
72
|
) => {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
};
|
|
101
|
-
}, [datasets, width, height, padding.top, padding.right, padding.bottom, padding.left]);
|
|
73
|
+
if (!datasets.length) return null;
|
|
74
|
+
|
|
75
|
+
const innerWidth = width - padding.left - padding.right;
|
|
76
|
+
const innerHeight = height - padding.top - padding.bottom;
|
|
77
|
+
|
|
78
|
+
// Calculate bounds efficiently
|
|
79
|
+
const allValues = datasets.flatMap(dataset => dataset.data.map(d => d.value));
|
|
80
|
+
const minValue = Math.min(...allValues);
|
|
81
|
+
const maxValue = Math.max(...allValues);
|
|
82
|
+
const valueRange = maxValue - minValue;
|
|
83
|
+
|
|
84
|
+
// Pre-calculate scale functions for better performance
|
|
85
|
+
const xScale = (i: number, dataLength: number) =>
|
|
86
|
+
padding.left + (i / (dataLength - 1)) * innerWidth;
|
|
87
|
+
|
|
88
|
+
const yScale = (value: number) =>
|
|
89
|
+
padding.top + innerHeight - ((value - minValue) / valueRange) * innerHeight;
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
xScale,
|
|
93
|
+
yScale,
|
|
94
|
+
minValue,
|
|
95
|
+
maxValue,
|
|
96
|
+
valueRange,
|
|
97
|
+
innerWidth,
|
|
98
|
+
innerHeight,
|
|
99
|
+
};
|
|
102
100
|
},
|
|
103
101
|
[]
|
|
104
102
|
);
|
|
@@ -113,47 +111,65 @@ export function useChartPerformance() {
|
|
|
113
111
|
viewportEnd: number,
|
|
114
112
|
bufferSize: number = 50
|
|
115
113
|
) => {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
// No virtualization needed for small datasets
|
|
119
|
-
return {
|
|
120
|
-
visibleData: data,
|
|
121
|
-
startIndex: 0,
|
|
122
|
-
endIndex: data.length - 1,
|
|
123
|
-
isVirtualized: false,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const start = Math.max(0, viewportStart - bufferSize);
|
|
128
|
-
const end = Math.min(data.length - 1, viewportEnd + bufferSize);
|
|
129
|
-
|
|
114
|
+
if (data.length <= 1000) {
|
|
115
|
+
// No virtualization needed for small datasets
|
|
130
116
|
return {
|
|
131
|
-
visibleData: data
|
|
132
|
-
startIndex:
|
|
133
|
-
endIndex:
|
|
134
|
-
isVirtualized:
|
|
135
|
-
totalLength: data.length,
|
|
117
|
+
visibleData: data,
|
|
118
|
+
startIndex: 0,
|
|
119
|
+
endIndex: data.length - 1,
|
|
120
|
+
isVirtualized: false,
|
|
136
121
|
};
|
|
137
|
-
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const start = Math.max(0, viewportStart - bufferSize);
|
|
125
|
+
const end = Math.min(data.length - 1, viewportEnd + bufferSize);
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
visibleData: data.slice(start, end + 1),
|
|
129
|
+
startIndex: start,
|
|
130
|
+
endIndex: end,
|
|
131
|
+
isVirtualized: true,
|
|
132
|
+
totalLength: data.length,
|
|
133
|
+
};
|
|
138
134
|
},
|
|
139
135
|
[]
|
|
140
136
|
);
|
|
141
137
|
|
|
142
138
|
/**
|
|
143
139
|
* Debounced data updates for real-time charts
|
|
140
|
+
* Returns a debounced function that maintains timeout state across calls
|
|
141
|
+
* Uses a closure to maintain state - each call to useDebouncedUpdates creates
|
|
142
|
+
* a new debounced function with its own persistent timeout state
|
|
144
143
|
*/
|
|
145
144
|
const useDebouncedUpdates = useCallback((updateFunction: () => void, delay: number = 100) => {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
145
|
+
// Use a closure variable to maintain timeout state across multiple calls to the returned function
|
|
146
|
+
// This variable is created once when useDebouncedUpdates is called and persists
|
|
147
|
+
// across all invocations of the returned debounced function
|
|
148
|
+
let timeoutId: NodeJS.Timeout | null = null;
|
|
149
|
+
|
|
150
|
+
const debouncedFn: (() => void) & { cancel: () => void } = () => {
|
|
151
|
+
// Clear any existing timeout before setting a new one
|
|
152
|
+
if (timeoutId !== null) {
|
|
153
|
+
clearTimeout(timeoutId);
|
|
154
|
+
timeoutId = null;
|
|
151
155
|
}
|
|
152
156
|
|
|
153
|
-
|
|
157
|
+
// Set new timeout and store the ID
|
|
158
|
+
timeoutId = setTimeout(() => {
|
|
154
159
|
updateFunction();
|
|
160
|
+
timeoutId = null;
|
|
155
161
|
}, delay);
|
|
156
|
-
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Add cleanup method to cancel pending debounced calls
|
|
165
|
+
debouncedFn.cancel = () => {
|
|
166
|
+
if (timeoutId !== null) {
|
|
167
|
+
clearTimeout(timeoutId);
|
|
168
|
+
timeoutId = null;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
return debouncedFn;
|
|
157
173
|
}, []);
|
|
158
174
|
|
|
159
175
|
/**
|
|
@@ -192,32 +208,40 @@ export function useChartPerformance() {
|
|
|
192
208
|
|
|
193
209
|
/**
|
|
194
210
|
* Optimized animation frame handling
|
|
211
|
+
* Returns animation control functions that maintain state across calls
|
|
212
|
+
* Uses closures to maintain state - each call to useAnimationFrame creates
|
|
213
|
+
* a new animation controller with its own persistent state
|
|
195
214
|
*/
|
|
196
215
|
const useAnimationFrame = useCallback((callback: () => void) => {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const startAnimation =
|
|
213
|
-
|
|
214
|
-
|
|
216
|
+
// Use closure variables to maintain animation state across multiple calls
|
|
217
|
+
// These variables are created once when useAnimationFrame is called and persist
|
|
218
|
+
// across all invocations of the returned animation control functions
|
|
219
|
+
let requestId: number | null = null;
|
|
220
|
+
let previousTime: number | null = null;
|
|
221
|
+
|
|
222
|
+
const animate = (time: number) => {
|
|
223
|
+
if (previousTime !== null && previousTime !== undefined) {
|
|
224
|
+
const deltaTime = time - previousTime;
|
|
225
|
+
callback();
|
|
226
|
+
}
|
|
227
|
+
previousTime = time;
|
|
228
|
+
requestId = requestAnimationFrame(animate);
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const startAnimation = () => {
|
|
232
|
+
// Only start if not already running
|
|
233
|
+
if (requestId === null) {
|
|
234
|
+
requestId = requestAnimationFrame(animate);
|
|
235
|
+
}
|
|
236
|
+
};
|
|
215
237
|
|
|
216
|
-
const stopAnimation =
|
|
217
|
-
if (
|
|
218
|
-
cancelAnimationFrame(
|
|
238
|
+
const stopAnimation = () => {
|
|
239
|
+
if (requestId !== null) {
|
|
240
|
+
cancelAnimationFrame(requestId);
|
|
241
|
+
requestId = null;
|
|
219
242
|
}
|
|
220
|
-
|
|
243
|
+
previousTime = null;
|
|
244
|
+
};
|
|
221
245
|
|
|
222
246
|
return { startAnimation, stopAnimation };
|
|
223
247
|
}, []);
|
|
@@ -18,6 +18,11 @@ export function useChartScale(
|
|
|
18
18
|
return {
|
|
19
19
|
xScale: () => padding.left,
|
|
20
20
|
yScale: () => padding.top + innerHeight,
|
|
21
|
+
minValue: 0,
|
|
22
|
+
maxValue: 0,
|
|
23
|
+
valueRange: 0,
|
|
24
|
+
innerWidth,
|
|
25
|
+
innerHeight,
|
|
21
26
|
width,
|
|
22
27
|
height,
|
|
23
28
|
padding,
|
|
@@ -40,6 +45,11 @@ export function useChartScale(
|
|
|
40
45
|
return {
|
|
41
46
|
xScale,
|
|
42
47
|
yScale,
|
|
48
|
+
minValue,
|
|
49
|
+
maxValue,
|
|
50
|
+
valueRange,
|
|
51
|
+
innerWidth,
|
|
52
|
+
innerHeight,
|
|
43
53
|
width,
|
|
44
54
|
height,
|
|
45
55
|
padding,
|
|
@@ -97,10 +97,17 @@ export function useHero(initialProps?: Partial<HeroProps>): UseHeroResult {
|
|
|
97
97
|
const hasBackgroundSlider = !!defaultProps.backgroundSlider;
|
|
98
98
|
|
|
99
99
|
/**
|
|
100
|
-
* Initialize background slider hook
|
|
100
|
+
* Initialize background slider hook - always call hook, conditionally use result
|
|
101
101
|
*/
|
|
102
|
+
const backgroundSliderResult = useHeroBackgroundSlider(
|
|
103
|
+
defaultProps.backgroundSlider || {
|
|
104
|
+
slides: [],
|
|
105
|
+
autoplay: { delay: 5000, pauseOnHover: true }
|
|
106
|
+
}
|
|
107
|
+
);
|
|
108
|
+
|
|
102
109
|
const backgroundSlider = hasBackgroundSlider && defaultProps.backgroundSlider
|
|
103
|
-
?
|
|
110
|
+
? backgroundSliderResult
|
|
104
111
|
: undefined;
|
|
105
112
|
|
|
106
113
|
/**
|
|
@@ -89,8 +89,9 @@ export function useHeroBackgroundSlider(
|
|
|
89
89
|
|
|
90
90
|
// Play video if it's a video slide
|
|
91
91
|
const currentVideo = videoRefs[nextIndex]?.current;
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
const nextSlide = slides[nextIndex];
|
|
93
|
+
if (currentVideo && nextSlide && nextSlide.type === 'video') {
|
|
94
|
+
const videoOptions = nextSlide.videoOptions || {};
|
|
94
95
|
if (videoOptions.autoplay !== false) {
|
|
95
96
|
currentVideo.play().catch(() => {
|
|
96
97
|
// Ignore autoplay errors
|
|
@@ -100,7 +101,8 @@ export function useHeroBackgroundSlider(
|
|
|
100
101
|
|
|
101
102
|
// Pause previous video if it exists
|
|
102
103
|
const prevVideo = videoRefs[currentIndex]?.current;
|
|
103
|
-
|
|
104
|
+
const currentSlide = slides[currentIndex];
|
|
105
|
+
if (prevVideo && currentSlide && currentSlide.type === 'video') {
|
|
104
106
|
prevVideo.pause();
|
|
105
107
|
}
|
|
106
108
|
|
|
@@ -60,6 +60,7 @@ export function useSideMenu(initialProps?: Partial<SideMenuProps>) {
|
|
|
60
60
|
} else if (!shouldCollapse && wrapperRef.current) {
|
|
61
61
|
wrapperRef.current.style.height = 'auto';
|
|
62
62
|
}
|
|
63
|
+
return undefined;
|
|
63
64
|
}, []); // Only run on mount
|
|
64
65
|
|
|
65
66
|
// Handle responsive behavior - vertical collapse for both mobile and desktop
|
|
@@ -41,18 +41,19 @@ export function useVideoPlayer({
|
|
|
41
41
|
const [currentQuality, setCurrentQuality] = useState<VideoQuality | null>(quality?.[0] || null);
|
|
42
42
|
const [showControls, setShowControls] = useState(true);
|
|
43
43
|
|
|
44
|
-
const controlsTimeoutRef = useRef<NodeJS.Timeout>(null);
|
|
44
|
+
const controlsTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
45
45
|
|
|
46
46
|
const resetControlsTimeout = useCallback(() => {
|
|
47
47
|
if (controlsTimeoutRef.current) {
|
|
48
48
|
clearTimeout(controlsTimeoutRef.current);
|
|
49
49
|
}
|
|
50
50
|
setShowControls(true);
|
|
51
|
-
|
|
51
|
+
const timeout = setTimeout(() => {
|
|
52
52
|
if (isPlaying) {
|
|
53
53
|
setShowControls(false);
|
|
54
54
|
}
|
|
55
55
|
}, 3000);
|
|
56
|
+
controlsTimeoutRef.current = timeout;
|
|
56
57
|
}, [isPlaying]);
|
|
57
58
|
|
|
58
59
|
const play = useCallback(async () => {
|
package/src/lib/config/loader.ts
CHANGED
|
@@ -76,26 +76,68 @@ export function loadAtomixConfig(
|
|
|
76
76
|
* Resolve config path
|
|
77
77
|
*
|
|
78
78
|
* Finds atomix.config.ts in the project, checking common locations.
|
|
79
|
+
* Returns null in browser environments where file system access is not available.
|
|
80
|
+
*
|
|
81
|
+
* This function is designed to work in Node.js environments only.
|
|
82
|
+
* In browser builds, it will always return null without attempting to access Node.js modules.
|
|
83
|
+
*
|
|
84
|
+
* @internal This function uses Node.js modules and should not be called in browser environments.
|
|
79
85
|
*/
|
|
80
86
|
export function resolveConfigPath(): string | null {
|
|
81
|
-
|
|
87
|
+
// Early return for browser environments - prevents any Node.js module access
|
|
88
|
+
// This check happens before any require() calls, preventing bundlers from analyzing them
|
|
89
|
+
if (typeof window !== 'undefined' || typeof process === 'undefined' || !process.cwd) {
|
|
82
90
|
return null;
|
|
83
91
|
}
|
|
84
92
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
// Only attempt to load Node.js modules in Node.js runtime
|
|
94
|
+
// Use a lazy-loading pattern that prevents static analysis by bundlers
|
|
95
|
+
try {
|
|
96
|
+
// Create a function that only executes in Node.js runtime
|
|
97
|
+
// Use string-based module names to prevent static analysis by bundlers
|
|
98
|
+
const loadNodeModules = () => {
|
|
99
|
+
// These requires are only executed at runtime in Node.js environments
|
|
100
|
+
// They are marked as external in Rollup config and should not be bundled
|
|
101
|
+
// Using string concatenation and computed property access to prevent static analysis
|
|
102
|
+
if (typeof require === 'undefined') {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Use a try-catch wrapper to safely access require
|
|
107
|
+
try {
|
|
108
|
+
// Build module names dynamically to prevent static analysis
|
|
109
|
+
const moduleNames: [string, string] = ['f' + 's', 'p' + 'a' + 't' + 'h'];
|
|
110
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
111
|
+
const fs = require(moduleNames[0]);
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
113
|
+
const path = require(moduleNames[1]);
|
|
114
|
+
return { fs, path };
|
|
115
|
+
} catch {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
94
119
|
|
|
95
|
-
|
|
96
|
-
if (
|
|
97
|
-
return
|
|
120
|
+
const modules = loadNodeModules();
|
|
121
|
+
if (!modules) {
|
|
122
|
+
return null;
|
|
98
123
|
}
|
|
124
|
+
|
|
125
|
+
const { fs, path } = modules;
|
|
126
|
+
const cwd = process.cwd();
|
|
127
|
+
const possiblePaths = [
|
|
128
|
+
path.join(cwd, 'atomix.config.ts'),
|
|
129
|
+
path.join(cwd, 'atomix.config.js'),
|
|
130
|
+
path.join(cwd, 'atomix.config.mjs'),
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
for (const configPath of possiblePaths) {
|
|
134
|
+
if (fs.existsSync(configPath)) {
|
|
135
|
+
return configPath;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} catch (error) {
|
|
139
|
+
// Silently fail in browser environments or when modules are unavailable
|
|
140
|
+
return null;
|
|
99
141
|
}
|
|
100
142
|
|
|
101
143
|
return null;
|
package/src/lib/hooks/index.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type { ComponentPartsMap } from '../types/partProps';
|
|
|
11
11
|
import type { ComponentCSSVariables } from '../constants/cssVariables';
|
|
12
12
|
import { mergeCSSVars } from '../theme/cssVariableMapper';
|
|
13
13
|
import { mergePartStyles } from '../types/partProps';
|
|
14
|
+
import { mergeClassNames } from '../utils/componentUtils';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Component names that support customization
|
|
@@ -22,7 +23,9 @@ export type ComponentName = keyof ComponentPartsMap;
|
|
|
22
23
|
*/
|
|
23
24
|
export interface CustomizableComponentProps<T extends ComponentName> {
|
|
24
25
|
/** CSS variable overrides */
|
|
25
|
-
cssVars?:
|
|
26
|
+
cssVars?: T extends keyof ComponentCSSVariables
|
|
27
|
+
? Partial<Record<ComponentCSSVariables[T], string | number>>
|
|
28
|
+
: Record<string, string | number>;
|
|
26
29
|
/** Part-based styling */
|
|
27
30
|
parts?: ComponentPartsMap[T];
|
|
28
31
|
/** Additional className */
|
|
@@ -72,17 +75,17 @@ export function useComponentCustomization<T extends ComponentName>(
|
|
|
72
75
|
|
|
73
76
|
// Merge CSS variables
|
|
74
77
|
const cssVars = useMemo(() => {
|
|
75
|
-
const themeVars = theme?.components?.[component]?.cssVars || {};
|
|
78
|
+
const themeVars = (theme as any)?.components?.[component]?.cssVars || {};
|
|
76
79
|
const propVars = props.cssVars || {};
|
|
77
80
|
return mergeCSSVars(themeVars, propVars as any);
|
|
78
81
|
}, [theme, component, props.cssVars]);
|
|
79
82
|
|
|
80
83
|
// Merge parts
|
|
81
84
|
const parts = useMemo(() => {
|
|
82
|
-
const themeParts = theme?.components?.[component]?.parts || {};
|
|
83
|
-
const propParts = props.parts || {}
|
|
85
|
+
const themeParts = (theme as any)?.components?.[component]?.parts || {};
|
|
86
|
+
const propParts = (props.parts || {}) as Record<string, any>;
|
|
84
87
|
|
|
85
|
-
const merged: any = {};
|
|
88
|
+
const merged: Record<string, any> = {};
|
|
86
89
|
const allPartNames = new Set([
|
|
87
90
|
...Object.keys(themeParts),
|
|
88
91
|
...Object.keys(propParts),
|
|
@@ -100,7 +103,7 @@ export function useComponentCustomization<T extends ComponentName>(
|
|
|
100
103
|
|
|
101
104
|
// Merge className
|
|
102
105
|
const className = useMemo(() => {
|
|
103
|
-
const themeClassName = theme?.components?.[component]?.className || '';
|
|
106
|
+
const themeClassName = (theme as any)?.components?.[component]?.className || '';
|
|
104
107
|
const propClassName = props.className || '';
|
|
105
108
|
return [themeClassName, propClassName].filter(Boolean).join(' ');
|
|
106
109
|
}, [theme, component, props.className]);
|
|
@@ -136,7 +139,7 @@ export function useComponentDefaultProps<T extends ComponentName>(
|
|
|
136
139
|
const { theme } = useTheme();
|
|
137
140
|
|
|
138
141
|
return useMemo(() => {
|
|
139
|
-
return theme?.components?.[component]?.defaultProps || {};
|
|
142
|
+
return (theme as any)?.components?.[component]?.defaultProps || {};
|
|
140
143
|
}, [theme, component]);
|
|
141
144
|
}
|
|
142
145
|
|
|
@@ -152,13 +155,6 @@ export function useMergedProps<T extends Record<string, any>>(
|
|
|
152
155
|
}, [defaultProps, props]);
|
|
153
156
|
}
|
|
154
157
|
|
|
155
|
-
/**
|
|
156
|
-
* Utility to create className from parts
|
|
157
|
-
*/
|
|
158
|
-
export function mergeClassNames(...classNames: Array<string | undefined | null | false>): string {
|
|
159
|
-
return classNames.filter(Boolean).join(' ');
|
|
160
|
-
}
|
|
161
|
-
|
|
162
158
|
/**
|
|
163
159
|
* Utility to apply CSS variables to style object
|
|
164
160
|
*/
|