@shohojdhara/atomix 0.5.0 → 0.5.2
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/atomix.config.ts +12 -0
- package/build-tools/webpack-loader.js +5 -4
- package/dist/atomix.css +230 -83
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +1 -1
- package/dist/atomix.min.css.map +1 -1
- package/dist/build-tools/webpack-loader.js +5 -4
- package/dist/charts.d.ts +24 -23
- package/dist/charts.js +271 -369
- package/dist/charts.js.map +1 -1
- package/dist/config.d.ts +624 -0
- package/dist/config.js +59 -0
- package/dist/config.js.map +1 -0
- package/dist/core.d.ts +3 -2
- package/dist/core.js +342 -382
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +4 -6
- package/dist/forms.js +233 -334
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +11 -2
- package/dist/heavy.js +406 -445
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +109 -65
- package/dist/index.esm.js +654 -748
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +621 -717
- 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.js +59 -60
- package/dist/layout.js.map +1 -1
- package/dist/theme.js +4 -4
- package/dist/theme.js.map +1 -1
- package/package.json +24 -9
- package/scripts/atomix-cli.js +15 -1
- package/scripts/cli/__tests__/complexity-utils.test.js +24 -0
- package/scripts/cli/__tests__/detector.test.js +50 -0
- package/scripts/cli/__tests__/template-engine.test.js +23 -0
- package/scripts/cli/__tests__/test-setup.js +1 -133
- package/scripts/cli/commands/doctor.js +15 -3
- package/scripts/cli/commands/generate.js +113 -51
- package/scripts/cli/internal/ai-engine.js +30 -10
- package/scripts/cli/internal/complexity-utils.js +60 -0
- package/scripts/cli/internal/component-validator.js +49 -16
- package/scripts/cli/internal/generator.js +89 -36
- package/scripts/cli/internal/hook-generator.js +5 -2
- package/scripts/cli/internal/itcss-generator.js +16 -12
- package/scripts/cli/templates/next-templates.js +81 -30
- package/scripts/cli/templates/storybook-templates.js +12 -2
- package/scripts/cli/utils/detector.js +45 -7
- package/scripts/cli/utils/diagnostics.js +78 -0
- package/scripts/cli/utils/telemetry.js +13 -0
- package/src/components/Accordion/Accordion.stories.tsx +4 -0
- package/src/components/AtomixGlass/AtomixGlass.tsx +188 -128
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +63 -91
- package/src/components/AtomixGlass/PerformanceDashboard.tsx +153 -201
- package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +9 -6
- package/src/components/AtomixGlass/glass-utils.ts +51 -1
- package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +52 -46
- package/src/components/AtomixGlass/stories/Examples.stories.tsx +573 -236
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +88 -41
- package/src/components/AtomixGlass/stories/argTypes.ts +19 -19
- package/src/components/AtomixGlass/stories/shared-components.tsx +7 -12
- package/src/components/AtomixGlass/stories/types.ts +3 -3
- package/src/components/Button/Button.tsx +114 -57
- package/src/components/Callout/Callout.tsx +4 -4
- package/src/components/Chart/ChartRenderer.tsx +1 -1
- package/src/components/Chart/DonutChart.tsx +11 -8
- package/src/components/EdgePanel/EdgePanel.tsx +119 -115
- package/src/components/Form/Select.tsx +4 -4
- package/src/components/List/List.tsx +4 -4
- package/src/components/Navigation/SideMenu/SideMenu.tsx +6 -6
- package/src/components/PhotoViewer/PhotoViewerImage.tsx +1 -1
- package/src/components/ProductReview/ProductReview.tsx +4 -2
- package/src/components/Rating/Rating.tsx +4 -2
- package/src/components/SectionIntro/SectionIntro.tsx +4 -2
- package/src/components/Steps/Steps.tsx +1 -1
- package/src/components/Tabs/Tabs.tsx +5 -5
- package/src/components/Testimonial/Testimonial.tsx +4 -2
- package/src/components/VideoPlayer/VideoPlayer.tsx +4 -2
- package/src/layouts/CssGrid/CssGrid.stories.tsx +464 -0
- package/src/layouts/CssGrid/CssGrid.tsx +215 -0
- package/src/layouts/CssGrid/index.ts +8 -0
- package/src/layouts/CssGrid/scripts/CssGrid.js +284 -0
- package/src/layouts/CssGrid/scripts/index.js +43 -0
- package/src/layouts/Grid/scripts/Container.js +139 -0
- package/src/layouts/Grid/scripts/Grid.js +184 -0
- package/src/layouts/Grid/scripts/GridCol.js +273 -0
- package/src/layouts/Grid/scripts/Row.js +154 -0
- package/src/layouts/Grid/scripts/index.js +48 -0
- package/src/layouts/MasonryGrid/MasonryGrid.tsx +71 -59
- package/src/lib/composables/atomix-glass/useGlassSize.ts +1 -1
- package/src/lib/composables/useAccordion.ts +5 -5
- package/src/lib/composables/useAtomixGlass.ts +111 -74
- package/src/lib/composables/useAtomixGlassStyles.ts +0 -2
- package/src/lib/composables/useBarChart.ts +2 -2
- package/src/lib/composables/useChart.ts +3 -2
- package/src/lib/composables/useChartToolbar.ts +48 -66
- package/src/lib/composables/useDataTable.ts +1 -1
- package/src/lib/composables/useDatePicker.ts +2 -2
- package/src/lib/composables/useEdgePanel.ts +45 -54
- package/src/lib/composables/useHeroBackgroundSlider.ts +5 -5
- package/src/lib/composables/usePhotoViewer.ts +2 -3
- package/src/lib/composables/usePieChart.ts +1 -1
- package/src/lib/composables/usePopover.ts +151 -139
- package/src/lib/composables/useSideMenu.ts +28 -41
- package/src/lib/composables/useSlider.ts +2 -6
- package/src/lib/composables/useTooltip.ts +2 -2
- package/src/lib/config/index.ts +39 -0
- package/src/lib/constants/components.ts +1 -0
- package/src/lib/theme/devtools/Comparator.tsx +1 -1
- package/src/lib/theme/devtools/Inspector.tsx +1 -1
- package/src/lib/theme/devtools/LiveEditor.tsx +1 -1
- package/src/lib/theme/runtime/ThemeProvider.tsx +1 -1
- package/src/lib/types/components.ts +1 -0
- package/src/styles/01-settings/_index.scss +1 -0
- package/src/styles/01-settings/_settings.atomix-glass.scss +174 -0
- package/src/styles/01-settings/_settings.masonry-grid.scss +42 -6
- package/src/styles/02-tools/_tools.glass.scss +6 -0
- package/src/styles/05-objects/_objects.masonry-grid.scss +162 -24
- package/src/styles/06-components/_components.atomix-glass.scss +160 -99
- package/scripts/cli/__tests__/README.md +0 -81
- package/scripts/cli/__tests__/basic.test.js +0 -116
- package/scripts/cli/__tests__/clean.test.js +0 -278
- package/scripts/cli/__tests__/component-generator.test.js +0 -332
- package/scripts/cli/__tests__/component-validator.test.js +0 -433
- package/scripts/cli/__tests__/generator.test.js +0 -613
- package/scripts/cli/__tests__/glass-motion.test.js +0 -256
- package/scripts/cli/__tests__/integration.test.js +0 -938
- package/scripts/cli/__tests__/migrate.test.js +0 -74
- package/scripts/cli/__tests__/security.test.js +0 -206
- package/scripts/cli/__tests__/theme-bridge.test.js +0 -507
- package/scripts/cli/__tests__/token-manager.test.js +0 -251
- package/scripts/cli/__tests__/token-provider.test.js +0 -361
- package/scripts/cli/__tests__/utils.test.js +0 -165
- package/src/components/AtomixGlass/stories/AnimationTests.stories.tsx +0 -95
- package/src/components/AtomixGlass/stories/CardExamples.stories.tsx +0 -212
- package/src/components/AtomixGlass/stories/Customization.stories.tsx +0 -131
- package/src/components/AtomixGlass/stories/DashboardExamples.stories.tsx +0 -348
- package/src/components/AtomixGlass/stories/EcommerceExamples.stories.tsx +0 -410
- package/src/components/AtomixGlass/stories/FormExamples.stories.tsx +0 -436
- package/src/components/AtomixGlass/stories/HeroExamples.stories.tsx +0 -264
- package/src/components/AtomixGlass/stories/InteractivePlayground.stories.tsx +0 -247
- package/src/components/AtomixGlass/stories/MobileUIExamples.stories.tsx +0 -418
- package/src/components/AtomixGlass/stories/ModalExamples.stories.tsx +0 -402
- package/src/components/AtomixGlass/stories/Modes.stories.tsx +0 -1082
- package/src/components/AtomixGlass/stories/Overview.stories.tsx +0 -497
- package/src/components/AtomixGlass/stories/Performance.stories.tsx +0 -103
- package/src/components/AtomixGlass/stories/PresetGallery.stories.tsx +0 -335
- package/src/components/AtomixGlass/stories/Shaders.stories.tsx +0 -395
- package/src/components/AtomixGlass/stories/WidgetExamples.stories.tsx +0 -441
- package/src/components/TypedButton/TypedButton.stories.tsx +0 -59
- package/src/components/TypedButton/TypedButton.tsx +0 -39
- package/src/components/TypedButton/index.ts +0 -2
- package/src/lib/composables/useBreadcrumb.ts +0 -81
- package/src/lib/composables/useChartInteractions.ts +0 -123
- package/src/lib/composables/useChartPerformance.ts +0 -347
- package/src/lib/composables/useDropdown.ts +0 -338
- package/src/lib/composables/useModal.ts +0 -110
- package/src/lib/composables/useTypedButton.ts +0 -66
- package/src/lib/hooks/usePerformanceMonitor.ts +0 -148
- package/src/lib/utils/displacement-generator.ts +0 -92
- package/src/lib/utils/memoryMonitor.ts +0 -191
- package/src/styles/01-settings/_settings.testtypecheck.scss +0 -53
- package/src/styles/01-settings/_settings.typedbutton.scss +0 -53
- package/src/styles/06-components/_components.testbutton.scss +0 -212
- package/src/styles/06-components/_components.testtypecheck.scss +0 -212
- package/src/styles/06-components/_components.typedbutton.scss +0 -212
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useMemo, useRef } from 'react';
|
|
1
|
+
import React, { forwardRef, memo, useMemo, useRef } from 'react';
|
|
2
2
|
import type { AtomixGlassProps } from '../../lib/types/components';
|
|
3
3
|
import { ATOMIX_GLASS } from '../../lib/constants/components';
|
|
4
4
|
import { AtomixGlassContainer } from './AtomixGlassContainer';
|
|
@@ -7,7 +7,10 @@ import { useAtomixGlass } from '../../lib/composables/useAtomixGlass';
|
|
|
7
7
|
import { useResponsiveGlass } from '../../lib/composables/useResponsiveGlass';
|
|
8
8
|
import { usePerformanceMonitor } from '../../lib/composables/usePerformanceMonitor';
|
|
9
9
|
import { PerformanceDashboard } from './PerformanceDashboard';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
getDevicePreset,
|
|
12
|
+
MOBILE_OPTIMIZED_BREAKPOINTS,
|
|
13
|
+
} from '../../lib/composables/useResponsiveGlass.presets';
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
16
|
* AtomixGlass - A high-performance glass morphism component with liquid distortion effects
|
|
@@ -88,53 +91,83 @@ import { getDevicePreset, MOBILE_OPTIMIZED_BREAKPOINTS } from '../../lib/composa
|
|
|
88
91
|
* <div>Mobile-optimized glass effect</div>
|
|
89
92
|
* </AtomixGlass>
|
|
90
93
|
*/
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
94
|
+
|
|
95
|
+
// ─── Type guard for the dev-only performance flag ────────────────────────────
|
|
96
|
+
declare global {
|
|
97
|
+
interface Window {
|
|
98
|
+
enablePerformanceMonitoring?: boolean;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Helper to merge refs
|
|
103
|
+
function mergeRefs<T = any>(
|
|
104
|
+
...refs: (React.MutableRefObject<T> | React.LegacyRef<T> | undefined | null)[]
|
|
105
|
+
) {
|
|
106
|
+
return (node: T) => {
|
|
107
|
+
refs.forEach(ref => {
|
|
108
|
+
if (typeof ref === 'function') {
|
|
109
|
+
ref(node);
|
|
110
|
+
} else if (ref != null) {
|
|
111
|
+
(ref as React.MutableRefObject<T | null>).current = node;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Internal implementation with forwardRef
|
|
118
|
+
const AtomixGlassInner = forwardRef<HTMLDivElement, AtomixGlassProps>(function AtomixGlass(
|
|
119
|
+
{
|
|
120
|
+
children,
|
|
121
|
+
displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE,
|
|
122
|
+
blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT,
|
|
123
|
+
saturation = ATOMIX_GLASS.DEFAULTS.SATURATION,
|
|
124
|
+
aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY,
|
|
125
|
+
elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY,
|
|
126
|
+
borderRadius,
|
|
127
|
+
globalMousePosition: externalGlobalMousePosition,
|
|
128
|
+
mouseOffset: externalMouseOffset,
|
|
129
|
+
mouseContainer = null,
|
|
130
|
+
className = '',
|
|
131
|
+
padding = ATOMIX_GLASS.DEFAULTS.PADDING,
|
|
132
|
+
overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT,
|
|
133
|
+
style = {},
|
|
134
|
+
mode = ATOMIX_GLASS.DEFAULTS.MODE,
|
|
135
|
+
onClick,
|
|
136
|
+
shaderVariant = 'liquidGlass',
|
|
137
|
+
'aria-label': ariaLabel,
|
|
138
|
+
'aria-describedby': ariaDescribedBy,
|
|
139
|
+
role,
|
|
140
|
+
tabIndex,
|
|
141
|
+
reducedMotion = false,
|
|
142
|
+
highContrast = false,
|
|
143
|
+
withoutEffects = false,
|
|
144
|
+
withLiquidBlur = false,
|
|
145
|
+
withBorder = true,
|
|
146
|
+
withOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS,
|
|
147
|
+
debugPerformance = false,
|
|
148
|
+
debugOverLight = false,
|
|
149
|
+
height,
|
|
150
|
+
width,
|
|
151
|
+
withTimeAnimation = false,
|
|
152
|
+
animationSpeed = 1.0,
|
|
153
|
+
withMultiLayerDistortion = false,
|
|
154
|
+
distortionOctaves = 3,
|
|
155
|
+
distortionLacunarity = 2.0,
|
|
156
|
+
distortionGain = 0.5,
|
|
157
|
+
distortionQuality = 'medium',
|
|
158
|
+
devicePreset = 'balanced',
|
|
159
|
+
disableResponsiveBreakpoints = false,
|
|
160
|
+
isFixedOrSticky: propsIsFixedOrSticky,
|
|
161
|
+
...rest
|
|
162
|
+
},
|
|
163
|
+
ref
|
|
164
|
+
) {
|
|
134
165
|
const glassRef = useRef<HTMLDivElement>(null);
|
|
135
166
|
const contentRef = useRef<HTMLDivElement>(null);
|
|
167
|
+
const internalWrapperRef = useRef<HTMLDivElement>(null);
|
|
168
|
+
const mergedRef = useMemo(() => mergeRefs(ref, internalWrapperRef), [ref]);
|
|
136
169
|
|
|
137
|
-
// ── Layout hoisting
|
|
170
|
+
// ── Layout hoisting ──────────────────────────────────────────────────────
|
|
138
171
|
// When position is fixed/sticky the layout props must live on the ROOT
|
|
139
172
|
// `.c-atomix-glass` element so that every decorative layer (borders,
|
|
140
173
|
// backgrounds, hover effects) stays in the same stacking context.
|
|
@@ -143,7 +176,8 @@ export function AtomixGlass({
|
|
|
143
176
|
// layers via --atomix-glass-base-z-index. It must NOT be applied as a
|
|
144
177
|
// real z-index on the root element — that would break the glass effect.
|
|
145
178
|
const { zIndex: customZIndex, ...restStyle } = style;
|
|
146
|
-
const isFixedOrSticky =
|
|
179
|
+
const isFixedOrSticky =
|
|
180
|
+
propsIsFixedOrSticky || restStyle.position === 'fixed' || restStyle.position === 'sticky';
|
|
147
181
|
|
|
148
182
|
// Use composable hook for all state and logic
|
|
149
183
|
const {
|
|
@@ -159,7 +193,6 @@ export function AtomixGlass({
|
|
|
159
193
|
mouseOffset,
|
|
160
194
|
transformStyle,
|
|
161
195
|
getShaderTime,
|
|
162
|
-
applyTimeBasedDistortion,
|
|
163
196
|
handleMouseEnter,
|
|
164
197
|
handleMouseLeave,
|
|
165
198
|
handleMouseDown,
|
|
@@ -168,6 +201,7 @@ export function AtomixGlass({
|
|
|
168
201
|
} = useAtomixGlass({
|
|
169
202
|
glassRef,
|
|
170
203
|
contentRef,
|
|
204
|
+
wrapperRef: internalWrapperRef,
|
|
171
205
|
borderRadius,
|
|
172
206
|
globalMousePosition: externalGlobalMousePosition,
|
|
173
207
|
mouseOffset: externalMouseOffset,
|
|
@@ -204,18 +238,15 @@ export function AtomixGlass({
|
|
|
204
238
|
// Get device preset parameters - memoized to prevent recalculation
|
|
205
239
|
const devicePresetParams = useMemo(() => {
|
|
206
240
|
return getDevicePreset(devicePreset);
|
|
207
|
-
}, [devicePreset]);
|
|
241
|
+
}, [devicePreset]);
|
|
208
242
|
|
|
209
243
|
// Responsive breakpoint system - automatically adjusts parameters based on viewport
|
|
210
|
-
|
|
211
|
-
responsiveParams,
|
|
212
|
-
currentBreakpoint,
|
|
213
|
-
performanceTier,
|
|
214
|
-
isActive: isResponsiveActive
|
|
215
|
-
} = useResponsiveGlass({
|
|
244
|
+
useResponsiveGlass({
|
|
216
245
|
baseParams: {
|
|
217
246
|
...devicePresetParams,
|
|
218
|
-
distortionOctaves: Math.round(
|
|
247
|
+
distortionOctaves: Math.round(
|
|
248
|
+
(displacementScale || ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE) / 25
|
|
249
|
+
),
|
|
219
250
|
displacementScale: displacementScale || ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE,
|
|
220
251
|
blurAmount: blurAmount || ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT,
|
|
221
252
|
saturation: saturation || ATOMIX_GLASS.DEFAULTS.SATURATION,
|
|
@@ -224,30 +255,24 @@ export function AtomixGlass({
|
|
|
224
255
|
chromaticIntensity: aberrationIntensity || ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY,
|
|
225
256
|
},
|
|
226
257
|
breakpoints: MOBILE_OPTIMIZED_BREAKPOINTS,
|
|
227
|
-
enabled: !disableResponsiveBreakpoints && typeof window !== 'undefined',
|
|
228
|
-
debug: false
|
|
258
|
+
enabled: !disableResponsiveBreakpoints && typeof window !== 'undefined',
|
|
259
|
+
debug: false,
|
|
229
260
|
});
|
|
230
261
|
|
|
231
262
|
// Performance monitoring - tracks FPS, frame time, memory usage
|
|
232
|
-
const {
|
|
233
|
-
|
|
234
|
-
recommendedQuality,
|
|
235
|
-
isUnderperforming,
|
|
236
|
-
setQualityLevel,
|
|
237
|
-
toggleMonitoring
|
|
238
|
-
} = usePerformanceMonitor({
|
|
239
|
-
enabled: false, // We'll toggle manually based on prop
|
|
263
|
+
const { metrics: performanceMetrics, toggleMonitoring } = usePerformanceMonitor({
|
|
264
|
+
enabled: debugPerformance, // Enable when debugPerformance is true
|
|
240
265
|
debug: false,
|
|
241
|
-
showOverlay: false
|
|
266
|
+
showOverlay: false,
|
|
242
267
|
});
|
|
243
268
|
|
|
244
|
-
// Auto-start performance monitoring
|
|
269
|
+
// Auto-start performance monitoring when debugPerformance is enabled
|
|
245
270
|
React.useEffect(() => {
|
|
246
|
-
if (
|
|
271
|
+
if (debugPerformance) {
|
|
247
272
|
toggleMonitoring();
|
|
248
273
|
}
|
|
249
274
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
250
|
-
}, []); //
|
|
275
|
+
}, [debugPerformance]); // Re-run when debugPerformance changes
|
|
251
276
|
|
|
252
277
|
const isOverLight = useMemo(() => overLightConfig.isOverLight, [overLightConfig.isOverLight]);
|
|
253
278
|
|
|
@@ -272,14 +297,12 @@ export function AtomixGlass({
|
|
|
272
297
|
const { position: _p, top: _t, left: _l, right: _r, bottom: _b, ...visualStyle } = restStyle;
|
|
273
298
|
return {
|
|
274
299
|
...visualStyle,
|
|
275
|
-
...(!effectiveWithoutEffects && { transform: transformStyle }),
|
|
276
300
|
};
|
|
277
301
|
}
|
|
278
302
|
return {
|
|
279
303
|
...restStyle,
|
|
280
|
-
...(!effectiveWithoutEffects && { transform: transformStyle }),
|
|
281
304
|
};
|
|
282
|
-
}, [isFixedOrSticky, restStyle
|
|
305
|
+
}, [isFixedOrSticky, restStyle]);
|
|
283
306
|
|
|
284
307
|
// Build className with state modifiers
|
|
285
308
|
const componentClassName = [
|
|
@@ -299,10 +322,19 @@ export function AtomixGlass({
|
|
|
299
322
|
position: (isFixedOrSticky
|
|
300
323
|
? 'absolute'
|
|
301
324
|
: restStyle.position || 'absolute') as React.CSSProperties['position'],
|
|
302
|
-
top: isFixedOrSticky ? 0 : restStyle.top
|
|
303
|
-
left: isFixedOrSticky ? 0 : restStyle.left
|
|
325
|
+
top: !isFixedOrSticky ? 0 : (restStyle.top ?? 0),
|
|
326
|
+
left: !isFixedOrSticky ? 0 : (restStyle.left ?? 0),
|
|
327
|
+
right: !isFixedOrSticky ? 'auto' : (restStyle.right ?? 'auto'),
|
|
328
|
+
bottom: !isFixedOrSticky ? 'auto' : (restStyle.bottom ?? 'auto'),
|
|
304
329
|
}),
|
|
305
|
-
[
|
|
330
|
+
[
|
|
331
|
+
isFixedOrSticky,
|
|
332
|
+
restStyle.position,
|
|
333
|
+
restStyle.top,
|
|
334
|
+
restStyle.left,
|
|
335
|
+
restStyle.right,
|
|
336
|
+
restStyle.bottom,
|
|
337
|
+
]
|
|
306
338
|
);
|
|
307
339
|
|
|
308
340
|
const adjustedSize = useMemo(() => {
|
|
@@ -311,12 +343,14 @@ export function AtomixGlass({
|
|
|
311
343
|
const _position = positionStyles.position;
|
|
312
344
|
|
|
313
345
|
const resolveLength = (value: string | number | undefined, measured: number): string => {
|
|
314
|
-
if (value !== undefined) {
|
|
346
|
+
if (value !== undefined && isFixedOrSticky) {
|
|
315
347
|
return typeof value === 'number' ? `${value}px` : value;
|
|
316
348
|
}
|
|
317
|
-
|
|
349
|
+
|
|
350
|
+
if (measured > 0 && isFixedOrSticky) {
|
|
318
351
|
return `${measured}px`;
|
|
319
352
|
}
|
|
353
|
+
|
|
320
354
|
return '100%';
|
|
321
355
|
};
|
|
322
356
|
|
|
@@ -335,6 +369,7 @@ export function AtomixGlass({
|
|
|
335
369
|
positionStyles.position,
|
|
336
370
|
glassSize.width,
|
|
337
371
|
glassSize.height,
|
|
372
|
+
isFixedOrSticky,
|
|
338
373
|
]);
|
|
339
374
|
|
|
340
375
|
// Memoize expensive gradient calculations
|
|
@@ -386,9 +421,14 @@ export function AtomixGlass({
|
|
|
386
421
|
};
|
|
387
422
|
}, [mouseOffset.x, mouseOffset.y]);
|
|
388
423
|
|
|
424
|
+
// Clamp overLight opacities to [0,1]
|
|
425
|
+
const clampedOverLightOpacity = Math.max(0, Math.min(1, overLightConfig?.opacity ?? 0.4));
|
|
426
|
+
const clampedBorderOpacity = Math.max(0, Math.min(1, overLightConfig?.borderOpacity ?? 1));
|
|
427
|
+
|
|
389
428
|
// Memoize opacity calculations
|
|
390
429
|
const opacityValues = useMemo(() => {
|
|
391
|
-
|
|
430
|
+
// Use clamped opacity value here
|
|
431
|
+
const overLightOpacity = clampedOverLightOpacity;
|
|
392
432
|
const BASE_OVER_LIGHT_OPACITY = 0.4;
|
|
393
433
|
const OVER_OPACITY_MULTIPLIER = 1.1;
|
|
394
434
|
|
|
@@ -401,7 +441,7 @@ export function AtomixGlass({
|
|
|
401
441
|
? (overLightOpacity || BASE_OVER_LIGHT_OPACITY) * OVER_OPACITY_MULTIPLIER
|
|
402
442
|
: 0,
|
|
403
443
|
};
|
|
404
|
-
}, [isHovered, isActive, isOverLight,
|
|
444
|
+
}, [isHovered, isActive, isOverLight, clampedOverLightOpacity]);
|
|
405
445
|
|
|
406
446
|
// Memoize CSS variables object
|
|
407
447
|
const glassVars = useMemo(() => {
|
|
@@ -420,22 +460,22 @@ export function AtomixGlass({
|
|
|
420
460
|
absMy,
|
|
421
461
|
} = gradientValues;
|
|
422
462
|
|
|
423
|
-
const configBorderOpacity = overLightConfig?.borderOpacity ?? 1;
|
|
424
|
-
|
|
425
463
|
return {
|
|
426
464
|
...(customZIndex !== undefined && { '--atomix-glass-base-z-index': customZIndex }),
|
|
427
465
|
'--atomix-glass-radius': `${effectiveBorderRadius}px`,
|
|
428
466
|
'--atomix-glass-transform': transformStyle || 'none',
|
|
429
|
-
|
|
430
|
-
'--atomix-glass-position': rootLayoutStyle.position
|
|
431
|
-
'--atomix-glass-top': `${isFixedOrSticky ?
|
|
432
|
-
'--atomix-glass-left': `${isFixedOrSticky ?
|
|
467
|
+
'--atomix-glass-container-position': `${!isFixedOrSticky ? positionStyles.position : rootLayoutStyle.position}`,
|
|
468
|
+
'--atomix-glass-position': `${!isFixedOrSticky ? positionStyles.position : rootLayoutStyle.position}`,
|
|
469
|
+
'--atomix-glass-top': `${!isFixedOrSticky ? 0 : (restStyle.top ?? 0)}px`,
|
|
470
|
+
'--atomix-glass-left': `${!isFixedOrSticky ? 0 : (restStyle.left ?? 0)}px`,
|
|
471
|
+
'--atomix-glass-right': !isFixedOrSticky ? 'auto' : (restStyle.right ?? 'auto'),
|
|
472
|
+
'--atomix-glass-bottom': !isFixedOrSticky ? 'auto' : (restStyle.bottom ?? 'auto'),
|
|
433
473
|
'--atomix-glass-width': adjustedSize.width,
|
|
434
474
|
'--atomix-glass-height': adjustedSize.height,
|
|
435
|
-
'--atomix-glass-border-width': 'var(--atomix-spacing-0-5, 0.
|
|
475
|
+
'--atomix-glass-border-width': 'var(--atomix-spacing-0-5, 0.125rem)',
|
|
436
476
|
'--atomix-glass-blend-mode': isOverLight ? 'multiply' : 'overlay',
|
|
437
|
-
'--atomix-glass-border-gradient-1': `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[0] ?? 1) *
|
|
438
|
-
'--atomix-glass-border-gradient-2': `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[2] ?? 1) *
|
|
477
|
+
'--atomix-glass-border-gradient-1': `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[0] ?? 1) * clampedBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[1] ?? 1) * clampedBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
|
|
478
|
+
'--atomix-glass-border-gradient-2': `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[2] ?? 1) * clampedBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[3] ?? 1) * clampedBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
|
|
439
479
|
'--atomix-glass-hover-1-opacity': opacityValues.hover1,
|
|
440
480
|
'--atomix-glass-hover-1-gradient': isOverLight
|
|
441
481
|
? `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_END}%)`
|
|
@@ -467,13 +507,28 @@ export function AtomixGlass({
|
|
|
467
507
|
transformStyle,
|
|
468
508
|
adjustedSize,
|
|
469
509
|
isOverLight,
|
|
470
|
-
|
|
510
|
+
clampedBorderOpacity,
|
|
471
511
|
customZIndex,
|
|
472
|
-
rootLayoutStyle,
|
|
473
512
|
isFixedOrSticky,
|
|
513
|
+
positionStyles.position,
|
|
514
|
+
rootLayoutStyle.position,
|
|
515
|
+
restStyle.top,
|
|
516
|
+
restStyle.left,
|
|
517
|
+
restStyle.right,
|
|
518
|
+
restStyle.bottom,
|
|
474
519
|
]);
|
|
475
520
|
|
|
476
|
-
//
|
|
521
|
+
// ─── Render helpers ──────────────────────────────────────────────────────
|
|
522
|
+
|
|
523
|
+
const renderHoverLayers = () => (
|
|
524
|
+
<>
|
|
525
|
+
{/* Hover layers - opacity and background set via CSS variables in SCSS */}
|
|
526
|
+
<div className={ATOMIX_GLASS.HOVER_1_CLASS} />
|
|
527
|
+
<div className={ATOMIX_GLASS.HOVER_2_CLASS} />
|
|
528
|
+
<div className={ATOMIX_GLASS.HOVER_3_CLASS} />
|
|
529
|
+
</>
|
|
530
|
+
);
|
|
531
|
+
|
|
477
532
|
const renderBackgroundLayer = (layerType: 'dark' | 'black') => (
|
|
478
533
|
<div
|
|
479
534
|
className={[
|
|
@@ -490,9 +545,30 @@ export function AtomixGlass({
|
|
|
490
545
|
/>
|
|
491
546
|
);
|
|
492
547
|
|
|
548
|
+
const renderOverLightLayers = () => (
|
|
549
|
+
<>
|
|
550
|
+
{/* Base and overlay layers - opacity and background set via CSS variables in SCSS */}
|
|
551
|
+
<div className={ATOMIX_GLASS.BASE_LAYER_CLASS} />
|
|
552
|
+
<div className={ATOMIX_GLASS.OVERLAY_LAYER_CLASS} />
|
|
553
|
+
{/* Overlay highlight - opacity and background are dynamic, calculated inline */}
|
|
554
|
+
<div className={ATOMIX_GLASS.OVERLAY_HIGHLIGHT_CLASS} />
|
|
555
|
+
</>
|
|
556
|
+
);
|
|
557
|
+
|
|
558
|
+
const renderBorderElements = () => (
|
|
559
|
+
<>
|
|
560
|
+
{/* Border elements - all styles (static and dynamic via CSS variables) are in SCSS */}
|
|
561
|
+
{/* Position, size, transform, transition, border-radius all use CSS variables set in glassVars */}
|
|
562
|
+
<span className={ATOMIX_GLASS.BORDER_BACKDROP_CLASS} />
|
|
563
|
+
<span className={ATOMIX_GLASS.BORDER_1_CLASS} />
|
|
564
|
+
<span className={ATOMIX_GLASS.BORDER_2_CLASS} />
|
|
565
|
+
</>
|
|
566
|
+
);
|
|
567
|
+
|
|
493
568
|
return (
|
|
494
569
|
<div
|
|
495
570
|
{...rest}
|
|
571
|
+
ref={mergedRef}
|
|
496
572
|
className={componentClassName}
|
|
497
573
|
style={{ ...glassVars }}
|
|
498
574
|
role={role || (onClick ? 'button' : undefined)}
|
|
@@ -500,19 +576,14 @@ export function AtomixGlass({
|
|
|
500
576
|
aria-label={ariaLabel}
|
|
501
577
|
aria-describedby={ariaDescribedBy}
|
|
502
578
|
aria-disabled={onClick && effectiveWithoutEffects ? true : onClick ? false : undefined}
|
|
503
|
-
aria-pressed={
|
|
504
|
-
onKeyDown={onClick ? handleKeyDown : undefined}
|
|
579
|
+
aria-pressed={undefined}
|
|
580
|
+
onKeyDown={onClick ? handleKeyDown : undefined}
|
|
505
581
|
>
|
|
506
582
|
<AtomixGlassContainer
|
|
507
583
|
ref={glassRef}
|
|
508
584
|
contentRef={contentRef}
|
|
509
585
|
className={className}
|
|
510
|
-
style={{
|
|
511
|
-
...restStyle,
|
|
512
|
-
...(!isFixedOrSticky && {
|
|
513
|
-
position: 'relative',
|
|
514
|
-
}),
|
|
515
|
-
}}
|
|
586
|
+
style={{ ...restStyle } as React.CSSProperties}
|
|
516
587
|
borderRadius={effectiveBorderRadius}
|
|
517
588
|
displacementScale={
|
|
518
589
|
effectiveWithoutEffects
|
|
@@ -561,6 +632,7 @@ export function AtomixGlass({
|
|
|
561
632
|
effectiveReducedMotion={effectiveReducedMotion}
|
|
562
633
|
shaderVariant={shaderVariant}
|
|
563
634
|
withLiquidBlur={withLiquidBlur}
|
|
635
|
+
isFixedOrSticky={isFixedOrSticky}
|
|
564
636
|
// Phase 1: Animation System props
|
|
565
637
|
shaderTime={getShaderTime()}
|
|
566
638
|
withTimeAnimation={withTimeAnimation}
|
|
@@ -573,40 +645,20 @@ export function AtomixGlass({
|
|
|
573
645
|
>
|
|
574
646
|
{children}
|
|
575
647
|
</AtomixGlassContainer>
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
{/* Hover layers - opacity and background set via CSS variables in SCSS */}
|
|
579
|
-
<div className={ATOMIX_GLASS.HOVER_1_CLASS} />
|
|
580
|
-
<div className={ATOMIX_GLASS.HOVER_2_CLASS} />
|
|
581
|
-
<div className={ATOMIX_GLASS.HOVER_3_CLASS} />
|
|
582
|
-
</>
|
|
583
|
-
)}
|
|
648
|
+
|
|
649
|
+
{Boolean(onClick) && renderHoverLayers()}
|
|
584
650
|
|
|
585
651
|
{/* Background layers for over-light mode */}
|
|
586
652
|
{/* Static styles (pointer-events) are in SCSS; will-change is managed via .u-glass-clean-root utility for backdrop-filter stability */}
|
|
587
653
|
{renderBackgroundLayer('dark')}
|
|
588
654
|
{renderBackgroundLayer('black')}
|
|
589
|
-
{shouldRenderOverLightLayers && (
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
<div className={ATOMIX_GLASS.OVERLAY_LAYER_CLASS} />
|
|
594
|
-
{/* Overlay highlight - opacity and background are dynamic, calculated inline */}
|
|
595
|
-
<div className={ATOMIX_GLASS.OVERLAY_HIGHLIGHT_CLASS} />
|
|
596
|
-
</>
|
|
597
|
-
)}
|
|
598
|
-
{withBorder && (
|
|
599
|
-
<>
|
|
600
|
-
{/* Border elements - all styles (static and dynamic via CSS variables) are in SCSS */}
|
|
601
|
-
{/* Position, size, transform, transition, border-radius all use CSS variables set in glassVars */}
|
|
602
|
-
<span className={ATOMIX_GLASS.BORDER_1_CLASS} />
|
|
603
|
-
<span className={ATOMIX_GLASS.BORDER_2_CLASS} />
|
|
604
|
-
</>
|
|
605
|
-
)}
|
|
606
|
-
|
|
655
|
+
{shouldRenderOverLightLayers && renderOverLightLayers()}
|
|
656
|
+
|
|
657
|
+
{withBorder && renderBorderElements()}
|
|
658
|
+
|
|
607
659
|
{/* Phase 3: Performance Monitoring Dashboard - Only in development with debugPerformance enabled */}
|
|
608
660
|
{debugPerformance && performanceMetrics && (
|
|
609
|
-
<PerformanceDashboard
|
|
661
|
+
<PerformanceDashboard
|
|
610
662
|
metrics={performanceMetrics}
|
|
611
663
|
isVisible={true}
|
|
612
664
|
onClose={() => {}} // No-op, dashboard always visible when debugPerformance is true
|
|
@@ -614,6 +666,14 @@ export function AtomixGlass({
|
|
|
614
666
|
)}
|
|
615
667
|
</div>
|
|
616
668
|
);
|
|
617
|
-
}
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
AtomixGlassInner.displayName = 'AtomixGlass';
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* AtomixGlass - wrapped with React.memo to prevent unnecessary re-renders.
|
|
675
|
+
* Ref is forwarded to the root `<div>` element.
|
|
676
|
+
*/
|
|
677
|
+
export const AtomixGlass = memo(AtomixGlassInner);
|
|
618
678
|
|
|
619
679
|
export default AtomixGlass;
|