@shohojdhara/atomix 0.6.4 → 0.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/atomix.css +117 -38
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +1 -1
- package/dist/atomix.min.css.map +1 -1
- package/dist/atomix.umd.js +1 -1
- package/dist/atomix.umd.js.map +1 -1
- package/dist/atomix.umd.min.js +1 -1
- package/dist/charts.d.ts +30 -1
- package/dist/charts.js +625 -846
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +30 -1
- package/dist/core.js +659 -873
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +30 -1
- package/dist/forms.js +1171 -1402
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +31 -89
- package/dist/heavy.js +975 -1195
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +383 -140
- package/dist/index.esm.js +1567 -1679
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1556 -1667
- 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/Accordion/Accordion.tsx +2 -5
- package/src/components/AtomixGlass/AtomixGlass.test.tsx +14 -16
- package/src/components/AtomixGlass/AtomixGlass.tsx +137 -364
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +32 -251
- package/src/components/AtomixGlass/GlassFilter.tsx +62 -68
- package/src/components/AtomixGlass/README.md +2 -1
- package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +19 -18
- package/src/components/AtomixGlass/glass-border-styles.test.ts +58 -0
- package/src/components/AtomixGlass/glass-border-styles.ts +136 -0
- package/src/components/AtomixGlass/glass-utils.ts +456 -22
- package/src/components/AtomixGlass/shader-utils.ts +19 -77
- package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +158 -537
- package/src/components/AtomixGlass/stories/Border.stories.tsx +149 -0
- package/src/components/AtomixGlass/stories/Examples.stories.tsx +229 -89
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +29 -340
- package/src/components/AtomixGlass/stories/argTypes.ts +30 -13
- package/src/components/AtomixGlass/stories/premium-presets.ts +206 -0
- package/src/components/AtomixGlass/stories/shared-components.tsx +52 -8
- package/src/components/Badge/Badge.tsx +4 -4
- package/src/components/Button/Button.tsx +2 -6
- package/src/components/Callout/Callout.test.tsx +4 -3
- package/src/components/Callout/Callout.tsx +2 -5
- package/src/components/Dropdown/Dropdown.tsx +3 -7
- package/src/components/Form/Checkbox.tsx +2 -8
- package/src/components/Form/Input.tsx +2 -9
- package/src/components/Form/Radio.tsx +2 -9
- package/src/components/Form/Select.test.tsx +6 -6
- package/src/components/Form/Select.tsx +2 -7
- package/src/components/Form/Textarea.stories.tsx +5 -5
- package/src/components/Form/Textarea.tsx +2 -9
- package/src/components/Messages/Messages.tsx +2 -8
- package/src/components/Modal/Modal.tsx +4 -5
- package/src/components/Navigation/Nav/Nav.tsx +2 -6
- package/src/components/Navigation/Navbar/Navbar.tsx +2 -9
- package/src/components/Navigation/SideMenu/SideMenu.tsx +2 -6
- package/src/components/Pagination/Pagination.tsx +2 -10
- package/src/components/Popover/Popover.tsx +2 -9
- package/src/components/Progress/Progress.tsx +2 -7
- package/src/components/Rating/Rating.tsx +2 -10
- package/src/components/Spinner/Spinner.tsx +2 -7
- package/src/components/Steps/Steps.tsx +2 -10
- package/src/components/Tabs/Tabs.tsx +2 -9
- package/src/components/Toggle/Toggle.tsx +2 -10
- package/src/components/Tooltip/Tooltip.tsx +2 -5
- package/src/lib/composables/useAtomixGlass.ts +42 -143
- package/src/lib/composables/useAtomixGlassStyles.ts +61 -77
- package/src/lib/composables/usePerformanceMonitor.ts +5 -66
- package/src/lib/constants/components.ts +363 -46
- package/src/lib/types/components.ts +33 -1
- package/src/styles/01-settings/_settings.atomix-glass.scss +66 -28
- package/src/styles/02-tools/_tools.button.scss +51 -42
- package/src/styles/02-tools/_tools.glass.scss +45 -3
- package/src/styles/06-components/_components.atomix-glass.scss +116 -79
- package/src/components/AtomixGlass/PerformanceDashboard.tsx +0 -171
- package/src/components/AtomixGlass/animation-system.ts +0 -578
- package/src/components/AtomixGlass/deprecated/AtomixGlass.deprecated.tsx +0 -390
|
@@ -1,12 +1,19 @@
|
|
|
1
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
|
+
import { mergeClassNames } from '../../lib/utils/componentUtils';
|
|
5
|
+
import useForkRef from '../../lib/utils/useForkRef';
|
|
4
6
|
import { AtomixGlassContainer } from './AtomixGlassContainer';
|
|
7
|
+
import {
|
|
8
|
+
buildGlassRootCssVariables,
|
|
9
|
+
getGlassInternalPositionStyles,
|
|
10
|
+
isGlassFixedOrSticky,
|
|
11
|
+
resolveGlassAdjustedSize,
|
|
12
|
+
resolveGlassContainerEffects,
|
|
13
|
+
} from './glass-utils';
|
|
5
14
|
import { useAtomixGlass } from '../../lib/composables/useAtomixGlass';
|
|
6
|
-
// Phase 3: Optimization & Adaptation
|
|
7
15
|
import { useResponsiveGlass } from '../../lib/composables/useResponsiveGlass';
|
|
8
16
|
import { usePerformanceMonitor } from '../../lib/composables/usePerformanceMonitor';
|
|
9
|
-
import { PerformanceDashboard } from './PerformanceDashboard';
|
|
10
17
|
import {
|
|
11
18
|
getDevicePreset,
|
|
12
19
|
MOBILE_OPTIMIZED_BREAKPOINTS,
|
|
@@ -35,6 +42,10 @@ import {
|
|
|
35
42
|
* - Implements focus-ring mixin for accessibility
|
|
36
43
|
* - Supports reduced motion and high contrast preferences
|
|
37
44
|
*
|
|
45
|
+
* Style architecture:
|
|
46
|
+
* - Root (`.c-atomix-glass`): CSS custom properties for layer geometry and motion.
|
|
47
|
+
* - Container (`.c-atomix-glass__container`): layout, z-index, and backdrop-filter.
|
|
48
|
+
*
|
|
38
49
|
* @example
|
|
39
50
|
* // Basic usage with dynamic border-radius extraction
|
|
40
51
|
* <AtomixGlass>
|
|
@@ -92,29 +103,7 @@ import {
|
|
|
92
103
|
* </AtomixGlass>
|
|
93
104
|
*/
|
|
94
105
|
|
|
95
|
-
|
|
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
|
|
106
|
+
/** Internal implementation; ref is forwarded to the root wrapper element. */
|
|
118
107
|
const AtomixGlassInner = forwardRef<HTMLDivElement, AtomixGlassProps>(function AtomixGlass(
|
|
119
108
|
{
|
|
120
109
|
children,
|
|
@@ -128,7 +117,7 @@ const AtomixGlassInner = forwardRef<HTMLDivElement, AtomixGlassProps>(function A
|
|
|
128
117
|
mouseOffset: externalMouseOffset,
|
|
129
118
|
mouseContainer = null,
|
|
130
119
|
className = '',
|
|
131
|
-
|
|
120
|
+
|
|
132
121
|
overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT,
|
|
133
122
|
style = {},
|
|
134
123
|
mode = ATOMIX_GLASS.DEFAULTS.MODE,
|
|
@@ -142,7 +131,9 @@ const AtomixGlassInner = forwardRef<HTMLDivElement, AtomixGlassProps>(function A
|
|
|
142
131
|
highContrast = false,
|
|
143
132
|
withoutEffects = false,
|
|
144
133
|
withLiquidBlur = false,
|
|
134
|
+
border,
|
|
145
135
|
withBorder = true,
|
|
136
|
+
debugBorderRadius = false,
|
|
146
137
|
withOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS,
|
|
147
138
|
debugPerformance = false,
|
|
148
139
|
debugOverLight = false,
|
|
@@ -165,21 +156,18 @@ const AtomixGlassInner = forwardRef<HTMLDivElement, AtomixGlassProps>(function A
|
|
|
165
156
|
const glassRef = useRef<HTMLDivElement>(null);
|
|
166
157
|
const contentRef = useRef<HTMLDivElement>(null);
|
|
167
158
|
const internalWrapperRef = useRef<HTMLDivElement>(null);
|
|
168
|
-
const mergedRef =
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
// real z-index on the root element — that would break the glass effect.
|
|
159
|
+
const mergedRef = useForkRef(ref, internalWrapperRef);
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Style partitioning for backdrop-filter compatibility.
|
|
163
|
+
* - Root (`.c-atomix-glass`): CSS custom properties only (`glassVars`).
|
|
164
|
+
* - Container (`.c-atomix-glass__container`): layout, stacking, and visual styles.
|
|
165
|
+
* Backdrop sampling occurs on `__filter-overlay` inside the container; layout
|
|
166
|
+
* properties must not be applied to the root or the effect will not render correctly.
|
|
167
|
+
*/
|
|
178
168
|
const { zIndex: customZIndex, ...restStyle } = style;
|
|
179
|
-
const isFixedOrSticky =
|
|
180
|
-
propsIsFixedOrSticky || restStyle.position === 'fixed' || restStyle.position === 'sticky';
|
|
169
|
+
const isFixedOrSticky = isGlassFixedOrSticky(propsIsFixedOrSticky, restStyle.position);
|
|
181
170
|
|
|
182
|
-
// Use composable hook for all state and logic
|
|
183
171
|
const {
|
|
184
172
|
isHovered,
|
|
185
173
|
isActive,
|
|
@@ -192,12 +180,12 @@ const AtomixGlassInner = forwardRef<HTMLDivElement, AtomixGlassProps>(function A
|
|
|
192
180
|
globalMousePosition,
|
|
193
181
|
mouseOffset,
|
|
194
182
|
transformStyle,
|
|
195
|
-
getShaderTime,
|
|
196
183
|
handleMouseEnter,
|
|
197
184
|
handleMouseLeave,
|
|
198
185
|
handleMouseDown,
|
|
199
186
|
handleMouseUp,
|
|
200
187
|
handleKeyDown,
|
|
188
|
+
resolvedBorder,
|
|
201
189
|
} = useAtomixGlass({
|
|
202
190
|
glassRef,
|
|
203
191
|
contentRef,
|
|
@@ -218,29 +206,19 @@ const AtomixGlassInner = forwardRef<HTMLDivElement, AtomixGlassProps>(function A
|
|
|
218
206
|
blurAmount,
|
|
219
207
|
saturation,
|
|
220
208
|
withLiquidBlur,
|
|
221
|
-
|
|
209
|
+
border,
|
|
210
|
+
withBorder,
|
|
211
|
+
debugBorderRadius,
|
|
212
|
+
|
|
222
213
|
style,
|
|
223
214
|
isFixedOrSticky,
|
|
224
|
-
// Phase 1: Animation System props
|
|
225
|
-
withTimeAnimation,
|
|
226
|
-
animationSpeed,
|
|
227
|
-
withMultiLayerDistortion,
|
|
228
|
-
distortionOctaves,
|
|
229
|
-
distortionLacunarity,
|
|
230
|
-
distortionGain,
|
|
231
|
-
distortionQuality,
|
|
232
215
|
});
|
|
233
216
|
|
|
234
|
-
// ============================================================================
|
|
235
|
-
// Phase 3: Optimization & Adaptation Systems
|
|
236
|
-
// ============================================================================
|
|
237
217
|
|
|
238
|
-
// Get device preset parameters - memoized to prevent recalculation
|
|
239
218
|
const devicePresetParams = useMemo(() => {
|
|
240
219
|
return getDevicePreset(devicePreset);
|
|
241
220
|
}, [devicePreset]);
|
|
242
221
|
|
|
243
|
-
// Responsive breakpoint system - automatically adjusts parameters based on viewport
|
|
244
222
|
useResponsiveGlass({
|
|
245
223
|
baseParams: {
|
|
246
224
|
...devicePresetParams,
|
|
@@ -259,309 +237,142 @@ const AtomixGlassInner = forwardRef<HTMLDivElement, AtomixGlassProps>(function A
|
|
|
259
237
|
debug: false,
|
|
260
238
|
});
|
|
261
239
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
enabled: debugPerformance, // Enable when debugPerformance is true
|
|
240
|
+
usePerformanceMonitor({
|
|
241
|
+
enabled: debugPerformance,
|
|
265
242
|
debug: false,
|
|
266
243
|
showOverlay: false,
|
|
267
244
|
});
|
|
268
245
|
|
|
269
|
-
// Auto-start performance monitoring when debugPerformance is enabled
|
|
270
|
-
React.useEffect(() => {
|
|
271
|
-
if (debugPerformance) {
|
|
272
|
-
toggleMonitoring();
|
|
273
|
-
}
|
|
274
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
275
|
-
}, [debugPerformance]); // Re-run when debugPerformance changes
|
|
276
|
-
|
|
277
246
|
const isOverLight = useMemo(() => overLightConfig.isOverLight, [overLightConfig.isOverLight]);
|
|
278
247
|
|
|
279
248
|
const shouldRenderOverLightLayers = withOverLightLayers && isOverLight;
|
|
280
249
|
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
const { position: p, top: t, left: l, right: r, bottom: b } = restStyle;
|
|
284
|
-
return {
|
|
285
|
-
...(p && { position: p }),
|
|
286
|
-
...(t !== undefined && { top: t }),
|
|
287
|
-
...(l !== undefined && { left: l }),
|
|
288
|
-
...(r !== undefined && { right: r }),
|
|
289
|
-
...(b !== undefined && { bottom: b }),
|
|
290
|
-
};
|
|
291
|
-
}, [isFixedOrSticky, restStyle]);
|
|
292
|
-
|
|
293
|
-
// Calculate base style with transforms
|
|
294
|
-
// When layout is hoisted to the root, strip those props from the container
|
|
295
|
-
const baseStyle = useMemo(() => {
|
|
296
|
-
if (isFixedOrSticky) {
|
|
297
|
-
const { position: _p, top: _t, left: _l, right: _r, bottom: _b, ...visualStyle } = restStyle;
|
|
298
|
-
return {
|
|
299
|
-
...visualStyle,
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
return {
|
|
250
|
+
const containerStyle = useMemo(
|
|
251
|
+
() => ({
|
|
303
252
|
...restStyle,
|
|
304
|
-
|
|
305
|
-
|
|
253
|
+
...(customZIndex !== undefined && { zIndex: customZIndex }),
|
|
254
|
+
}),
|
|
255
|
+
[restStyle, customZIndex]
|
|
256
|
+
);
|
|
306
257
|
|
|
307
|
-
|
|
308
|
-
const componentClassName = [
|
|
258
|
+
const componentClassName = mergeClassNames(
|
|
309
259
|
ATOMIX_GLASS.BASE_CLASS,
|
|
310
260
|
effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`,
|
|
311
261
|
effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`,
|
|
312
262
|
effectiveWithoutEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`,
|
|
313
|
-
className
|
|
314
|
-
|
|
315
|
-
.filter(Boolean)
|
|
316
|
-
.join(' ');
|
|
263
|
+
className
|
|
264
|
+
);
|
|
317
265
|
|
|
318
|
-
// Calculate position and size styles for internal layers
|
|
319
|
-
// When root is fixed/sticky, internal layers use absolute (relative to root)
|
|
320
266
|
const positionStyles = useMemo(
|
|
321
|
-
() => (
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
267
|
+
() => getGlassInternalPositionStyles(isFixedOrSticky, restStyle),
|
|
268
|
+
[isFixedOrSticky, restStyle]
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const adjustedSize = useMemo(
|
|
272
|
+
() =>
|
|
273
|
+
resolveGlassAdjustedSize({
|
|
274
|
+
width,
|
|
275
|
+
height,
|
|
276
|
+
restStyle,
|
|
277
|
+
glassSize,
|
|
278
|
+
isFixedOrSticky,
|
|
279
|
+
}),
|
|
280
|
+
[width, height, restStyle, glassSize, isFixedOrSticky]
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
const glassVars = useMemo(
|
|
284
|
+
() =>
|
|
285
|
+
buildGlassRootCssVariables({
|
|
286
|
+
effectiveBorderRadius,
|
|
287
|
+
transformStyle,
|
|
288
|
+
adjustedSize,
|
|
289
|
+
isOverLight,
|
|
290
|
+
customZIndex,
|
|
291
|
+
isFixedOrSticky,
|
|
292
|
+
positionStyles,
|
|
293
|
+
restStyle,
|
|
294
|
+
borderWidth: resolvedBorder.width,
|
|
295
|
+
}),
|
|
330
296
|
[
|
|
297
|
+
effectiveBorderRadius,
|
|
298
|
+
transformStyle,
|
|
299
|
+
adjustedSize,
|
|
300
|
+
isOverLight,
|
|
301
|
+
customZIndex,
|
|
331
302
|
isFixedOrSticky,
|
|
332
|
-
|
|
333
|
-
restStyle
|
|
334
|
-
|
|
335
|
-
restStyle.right,
|
|
336
|
-
restStyle.bottom,
|
|
303
|
+
positionStyles,
|
|
304
|
+
restStyle,
|
|
305
|
+
resolvedBorder.width,
|
|
337
306
|
]
|
|
338
307
|
);
|
|
339
308
|
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
positionStyles.position,
|
|
370
|
-
glassSize.width,
|
|
371
|
-
glassSize.height,
|
|
372
|
-
isFixedOrSticky,
|
|
373
|
-
]);
|
|
374
|
-
|
|
375
|
-
// Memoize expensive gradient calculations
|
|
376
|
-
const gradientValues = useMemo(() => {
|
|
377
|
-
const mx = mouseOffset.x;
|
|
378
|
-
const my = mouseOffset.y;
|
|
379
|
-
const absMx = Math.abs(mx);
|
|
380
|
-
const absMy = Math.abs(my);
|
|
381
|
-
const GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT;
|
|
382
|
-
|
|
383
|
-
return {
|
|
384
|
-
borderGradientAngle: GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER,
|
|
385
|
-
borderStop1: Math.max(
|
|
386
|
-
GRADIENT.BORDER_STOP_1.MIN,
|
|
387
|
-
GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER
|
|
388
|
-
),
|
|
389
|
-
borderStop2: Math.min(
|
|
390
|
-
GRADIENT.BORDER_STOP_2.MAX,
|
|
391
|
-
GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER
|
|
392
|
-
),
|
|
393
|
-
borderOpacities: [
|
|
394
|
-
GRADIENT.BORDER_OPACITY.BASE_1 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW,
|
|
395
|
-
GRADIENT.BORDER_OPACITY.BASE_2 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH,
|
|
396
|
-
GRADIENT.BORDER_OPACITY.BASE_3 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW,
|
|
397
|
-
GRADIENT.BORDER_OPACITY.BASE_4 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH,
|
|
398
|
-
],
|
|
399
|
-
hoverPositions: {
|
|
400
|
-
hover1: {
|
|
401
|
-
x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
|
|
402
|
-
y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1,
|
|
403
|
-
},
|
|
404
|
-
hover2: {
|
|
405
|
-
x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_2,
|
|
406
|
-
y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_2,
|
|
407
|
-
},
|
|
408
|
-
hover3: {
|
|
409
|
-
x: GRADIENT.CENTER_POSITION + mx * GRADIENT.HOVER_POSITION.MULTIPLIER_3,
|
|
410
|
-
y: GRADIENT.CENTER_POSITION + my * GRADIENT.HOVER_POSITION.MULTIPLIER_3,
|
|
411
|
-
},
|
|
412
|
-
},
|
|
413
|
-
basePosition: {
|
|
414
|
-
x: GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER,
|
|
415
|
-
y: GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER,
|
|
416
|
-
},
|
|
417
|
-
mx,
|
|
418
|
-
my,
|
|
419
|
-
absMx,
|
|
420
|
-
absMy,
|
|
421
|
-
};
|
|
422
|
-
}, [mouseOffset.x, mouseOffset.y]);
|
|
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
|
-
|
|
428
|
-
// Memoize opacity calculations
|
|
429
|
-
const opacityValues = useMemo(() => {
|
|
430
|
-
// Use clamped opacity value here
|
|
431
|
-
const overLightOpacity = clampedOverLightOpacity;
|
|
432
|
-
const BASE_OVER_LIGHT_OPACITY = 0.4;
|
|
433
|
-
const OVER_OPACITY_MULTIPLIER = 1.1;
|
|
434
|
-
|
|
435
|
-
return {
|
|
436
|
-
hover1: isHovered || isActive ? 0.5 : 0,
|
|
437
|
-
hover2: isActive ? 0.5 : 0,
|
|
438
|
-
hover3: isHovered ? 0.4 : isActive ? 0.8 : 0,
|
|
439
|
-
base: isOverLight ? overLightOpacity || BASE_OVER_LIGHT_OPACITY : 0,
|
|
440
|
-
over: isOverLight
|
|
441
|
-
? (overLightOpacity || BASE_OVER_LIGHT_OPACITY) * OVER_OPACITY_MULTIPLIER
|
|
442
|
-
: 0,
|
|
443
|
-
};
|
|
444
|
-
}, [isHovered, isActive, isOverLight, clampedOverLightOpacity]);
|
|
445
|
-
|
|
446
|
-
// Memoize CSS variables object
|
|
447
|
-
const glassVars = useMemo(() => {
|
|
448
|
-
const whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE;
|
|
449
|
-
const blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK;
|
|
450
|
-
const {
|
|
451
|
-
borderGradientAngle,
|
|
452
|
-
borderStop1,
|
|
453
|
-
borderStop2,
|
|
454
|
-
borderOpacities,
|
|
455
|
-
hoverPositions,
|
|
456
|
-
basePosition,
|
|
457
|
-
mx,
|
|
458
|
-
my,
|
|
459
|
-
absMx,
|
|
460
|
-
absMy,
|
|
461
|
-
} = gradientValues;
|
|
462
|
-
|
|
463
|
-
return {
|
|
464
|
-
...(customZIndex !== undefined && { '--atomix-glass-base-z-index': customZIndex }),
|
|
465
|
-
'--atomix-glass-radius': `${effectiveBorderRadius}px`,
|
|
466
|
-
'--atomix-glass-transform': transformStyle || 'none',
|
|
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'),
|
|
473
|
-
'--atomix-glass-width': adjustedSize.width,
|
|
474
|
-
'--atomix-glass-height': adjustedSize.height,
|
|
475
|
-
'--atomix-glass-border-width': 'var(--atomix-spacing-0-5, 0.125rem)',
|
|
476
|
-
'--atomix-glass-blend-mode': isOverLight ? 'multiply' : 'overlay',
|
|
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%)`,
|
|
479
|
-
'--atomix-glass-hover-1-opacity': opacityValues.hover1,
|
|
480
|
-
'--atomix-glass-hover-1-gradient': isOverLight
|
|
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}%)`
|
|
482
|
-
: `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_STOP}%)`,
|
|
483
|
-
'--atomix-glass-hover-2-opacity': opacityValues.hover2,
|
|
484
|
-
'--atomix-glass-hover-2-gradient': isOverLight
|
|
485
|
-
? `radial-gradient(circle at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_END}%)`
|
|
486
|
-
: `radial-gradient(circle at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_STOP}%)`,
|
|
487
|
-
'--atomix-glass-hover-3-opacity': opacityValues.hover3,
|
|
488
|
-
'--atomix-glass-hover-3-gradient': isOverLight
|
|
489
|
-
? `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_END}%)`
|
|
490
|
-
: `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_STOP}%)`,
|
|
491
|
-
'--atomix-glass-base-opacity': opacityValues.base,
|
|
492
|
-
'--atomix-glass-base-gradient': isOverLight
|
|
493
|
-
? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + mx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + my * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + absMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)`
|
|
494
|
-
: `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`,
|
|
495
|
-
'--atomix-glass-overlay-opacity': opacityValues.over,
|
|
496
|
-
'--atomix-glass-overlay-gradient': isOverLight
|
|
497
|
-
? `radial-gradient(circle at ${basePosition.x}% ${basePosition.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + absMx * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + absMy * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)`
|
|
498
|
-
: `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`,
|
|
499
|
-
'--atomix-glass-overlay-highlight-opacity':
|
|
500
|
-
opacityValues.over * ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER,
|
|
501
|
-
'--atomix-glass-overlay-highlight-bg': `radial-gradient(circle at ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_X}% ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_Y}%, rgba(255, 255, 255, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.WHITE_OPACITY}) 0%, transparent ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.STOP}%)`,
|
|
502
|
-
} as React.CSSProperties;
|
|
503
|
-
}, [
|
|
504
|
-
gradientValues,
|
|
505
|
-
opacityValues,
|
|
506
|
-
effectiveBorderRadius,
|
|
507
|
-
transformStyle,
|
|
508
|
-
adjustedSize,
|
|
509
|
-
isOverLight,
|
|
510
|
-
clampedBorderOpacity,
|
|
511
|
-
customZIndex,
|
|
512
|
-
isFixedOrSticky,
|
|
513
|
-
positionStyles.position,
|
|
514
|
-
rootLayoutStyle.position,
|
|
515
|
-
restStyle.top,
|
|
516
|
-
restStyle.left,
|
|
517
|
-
restStyle.right,
|
|
518
|
-
restStyle.bottom,
|
|
519
|
-
]);
|
|
520
|
-
|
|
521
|
-
// ─── Render helpers ──────────────────────────────────────────────────────
|
|
309
|
+
const containerEffects = useMemo(
|
|
310
|
+
() =>
|
|
311
|
+
resolveGlassContainerEffects({
|
|
312
|
+
displacementScale,
|
|
313
|
+
blurAmount,
|
|
314
|
+
saturation,
|
|
315
|
+
aberrationIntensity,
|
|
316
|
+
mode,
|
|
317
|
+
effectiveWithoutEffects,
|
|
318
|
+
effectiveHighContrast,
|
|
319
|
+
isOverLight,
|
|
320
|
+
saturationBoost: overLightConfig.saturationBoost,
|
|
321
|
+
mouseOffset,
|
|
322
|
+
globalMousePosition,
|
|
323
|
+
}),
|
|
324
|
+
[
|
|
325
|
+
displacementScale,
|
|
326
|
+
blurAmount,
|
|
327
|
+
saturation,
|
|
328
|
+
aberrationIntensity,
|
|
329
|
+
mode,
|
|
330
|
+
effectiveWithoutEffects,
|
|
331
|
+
effectiveHighContrast,
|
|
332
|
+
isOverLight,
|
|
333
|
+
overLightConfig.saturationBoost,
|
|
334
|
+
mouseOffset,
|
|
335
|
+
globalMousePosition,
|
|
336
|
+
]
|
|
337
|
+
);
|
|
522
338
|
|
|
523
339
|
const renderHoverLayers = () => (
|
|
524
340
|
<>
|
|
525
|
-
|
|
526
|
-
<div className={ATOMIX_GLASS.
|
|
527
|
-
<div className={ATOMIX_GLASS.
|
|
528
|
-
<div className={ATOMIX_GLASS.HOVER_3_CLASS} />
|
|
341
|
+
<div aria-hidden="true" className={ATOMIX_GLASS.HOVER_1_CLASS} />
|
|
342
|
+
<div aria-hidden="true" className={ATOMIX_GLASS.HOVER_2_CLASS} />
|
|
343
|
+
<div aria-hidden="true" className={ATOMIX_GLASS.HOVER_3_CLASS} />
|
|
529
344
|
</>
|
|
530
345
|
);
|
|
531
346
|
|
|
532
|
-
const
|
|
347
|
+
const backgroundLayerTypes = ['dark', 'black'] as const;
|
|
348
|
+
const renderBackgroundLayer = (layerType: (typeof backgroundLayerTypes)[number]) => (
|
|
533
349
|
<div
|
|
534
|
-
|
|
350
|
+
aria-hidden="true"
|
|
351
|
+
className={mergeClassNames(
|
|
535
352
|
ATOMIX_GLASS.BACKGROUND_LAYER_CLASS,
|
|
536
353
|
layerType === 'dark'
|
|
537
354
|
? ATOMIX_GLASS.BACKGROUND_LAYER_DARK_CLASS
|
|
538
355
|
: ATOMIX_GLASS.BACKGROUND_LAYER_BLACK_CLASS,
|
|
539
356
|
isOverLight
|
|
540
357
|
? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS
|
|
541
|
-
: ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS
|
|
542
|
-
|
|
543
|
-
.filter(Boolean)
|
|
544
|
-
.join(' ')}
|
|
358
|
+
: ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS
|
|
359
|
+
)}
|
|
545
360
|
/>
|
|
546
361
|
);
|
|
547
362
|
|
|
548
363
|
const renderOverLightLayers = () => (
|
|
549
364
|
<>
|
|
550
|
-
|
|
551
|
-
<div className={ATOMIX_GLASS.
|
|
552
|
-
<div className={ATOMIX_GLASS.
|
|
553
|
-
{/* Overlay highlight - opacity and background are dynamic, calculated inline */}
|
|
554
|
-
<div className={ATOMIX_GLASS.OVERLAY_HIGHLIGHT_CLASS} />
|
|
365
|
+
<div aria-hidden="true" className={ATOMIX_GLASS.BASE_LAYER_CLASS} />
|
|
366
|
+
<div aria-hidden="true" className={ATOMIX_GLASS.OVERLAY_LAYER_CLASS} />
|
|
367
|
+
<div aria-hidden="true" className={ATOMIX_GLASS.OVERLAY_HIGHLIGHT_CLASS} />
|
|
555
368
|
</>
|
|
556
369
|
);
|
|
557
370
|
|
|
558
371
|
const renderBorderElements = () => (
|
|
559
372
|
<>
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
<span className={ATOMIX_GLASS.
|
|
563
|
-
<span className={ATOMIX_GLASS.BORDER_1_CLASS} />
|
|
564
|
-
<span className={ATOMIX_GLASS.BORDER_2_CLASS} />
|
|
373
|
+
<span aria-hidden="true" className={ATOMIX_GLASS.BORDER_BACKDROP_CLASS} />
|
|
374
|
+
<span aria-hidden="true" className={ATOMIX_GLASS.BORDER_1_CLASS} />
|
|
375
|
+
<span aria-hidden="true" className={ATOMIX_GLASS.BORDER_2_CLASS} />
|
|
565
376
|
</>
|
|
566
377
|
);
|
|
567
378
|
|
|
@@ -570,54 +381,31 @@ const AtomixGlassInner = forwardRef<HTMLDivElement, AtomixGlassProps>(function A
|
|
|
570
381
|
{...rest}
|
|
571
382
|
ref={mergedRef}
|
|
572
383
|
className={componentClassName}
|
|
573
|
-
style={
|
|
384
|
+
style={glassVars}
|
|
574
385
|
role={role || (onClick ? 'button' : undefined)}
|
|
575
386
|
tabIndex={onClick ? (tabIndex ?? 0) : tabIndex}
|
|
576
387
|
aria-label={ariaLabel}
|
|
577
388
|
aria-describedby={ariaDescribedBy}
|
|
578
389
|
aria-disabled={onClick && effectiveWithoutEffects ? true : onClick ? false : undefined}
|
|
579
|
-
aria-pressed={onClick ? isActive : undefined}
|
|
580
390
|
onKeyDown={onClick ? handleKeyDown : undefined}
|
|
581
391
|
>
|
|
582
392
|
<AtomixGlassContainer
|
|
583
393
|
ref={glassRef}
|
|
584
394
|
contentRef={contentRef}
|
|
585
395
|
className={className}
|
|
586
|
-
style={
|
|
396
|
+
style={containerStyle as React.CSSProperties}
|
|
587
397
|
borderRadius={effectiveBorderRadius}
|
|
588
|
-
displacementScale={
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_DISPLACEMENT
|
|
593
|
-
: isOverLight
|
|
594
|
-
? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.OVER_LIGHT_DISPLACEMENT
|
|
595
|
-
: displacementScale
|
|
596
|
-
}
|
|
597
|
-
blurAmount={effectiveWithoutEffects ? 0 : blurAmount}
|
|
598
|
-
saturation={
|
|
599
|
-
effectiveHighContrast
|
|
600
|
-
? ATOMIX_GLASS.CONSTANTS.SATURATION.HIGH_CONTRAST
|
|
601
|
-
: isOverLight
|
|
602
|
-
? saturation * overLightConfig.saturationBoost
|
|
603
|
-
: saturation
|
|
604
|
-
}
|
|
605
|
-
aberrationIntensity={
|
|
606
|
-
effectiveWithoutEffects
|
|
607
|
-
? 0
|
|
608
|
-
: mode === 'shader'
|
|
609
|
-
? aberrationIntensity * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_ABERRATION
|
|
610
|
-
: aberrationIntensity
|
|
611
|
-
}
|
|
398
|
+
displacementScale={containerEffects.displacementScale}
|
|
399
|
+
blurAmount={containerEffects.blurAmount}
|
|
400
|
+
saturation={containerEffects.saturation}
|
|
401
|
+
aberrationIntensity={containerEffects.aberrationIntensity}
|
|
612
402
|
glassSize={glassSize}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
globalMousePosition={effectiveWithoutEffects ? { x: 0, y: 0 } : globalMousePosition}
|
|
403
|
+
mouseOffset={containerEffects.mouseOffset}
|
|
404
|
+
globalMousePosition={containerEffects.globalMousePosition}
|
|
616
405
|
onMouseEnter={handleMouseEnter}
|
|
617
406
|
onMouseLeave={handleMouseLeave}
|
|
618
407
|
onMouseDown={handleMouseDown}
|
|
619
408
|
onMouseUp={handleMouseUp}
|
|
620
|
-
isHovered={isHovered}
|
|
621
409
|
isActive={isActive}
|
|
622
410
|
overLight={isOverLight}
|
|
623
411
|
overLightConfig={{
|
|
@@ -633,8 +421,6 @@ const AtomixGlassInner = forwardRef<HTMLDivElement, AtomixGlassProps>(function A
|
|
|
633
421
|
shaderVariant={shaderVariant}
|
|
634
422
|
withLiquidBlur={withLiquidBlur}
|
|
635
423
|
isFixedOrSticky={isFixedOrSticky}
|
|
636
|
-
// Phase 1: Animation System props
|
|
637
|
-
shaderTime={getShaderTime()}
|
|
638
424
|
withTimeAnimation={withTimeAnimation}
|
|
639
425
|
animationSpeed={animationSpeed}
|
|
640
426
|
withMultiLayerDistortion={withMultiLayerDistortion}
|
|
@@ -648,32 +434,19 @@ const AtomixGlassInner = forwardRef<HTMLDivElement, AtomixGlassProps>(function A
|
|
|
648
434
|
|
|
649
435
|
{Boolean(onClick) && renderHoverLayers()}
|
|
650
436
|
|
|
651
|
-
{
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
{renderBackgroundLayer('black')}
|
|
437
|
+
{backgroundLayerTypes.map(layerType => (
|
|
438
|
+
<React.Fragment key={layerType}>{renderBackgroundLayer(layerType)}</React.Fragment>
|
|
439
|
+
))}
|
|
655
440
|
{shouldRenderOverLightLayers && renderOverLightLayers()}
|
|
656
441
|
|
|
657
|
-
{
|
|
658
|
-
|
|
659
|
-
{/* Phase 3: Performance Monitoring Dashboard - Only in development with debugPerformance enabled */}
|
|
660
|
-
{debugPerformance && performanceMetrics && (
|
|
661
|
-
<PerformanceDashboard
|
|
662
|
-
metrics={performanceMetrics}
|
|
663
|
-
isVisible={true}
|
|
664
|
-
onClose={() => {}} // No-op, dashboard always visible when debugPerformance is true
|
|
665
|
-
/>
|
|
666
|
-
)}
|
|
442
|
+
{resolvedBorder.enabled && renderBorderElements()}
|
|
667
443
|
</div>
|
|
668
444
|
);
|
|
669
445
|
});
|
|
670
446
|
|
|
671
447
|
AtomixGlassInner.displayName = 'AtomixGlass';
|
|
672
448
|
|
|
673
|
-
/**
|
|
674
|
-
* AtomixGlass - wrapped with React.memo to prevent unnecessary re-renders.
|
|
675
|
-
* Ref is forwarded to the root `<div>` element.
|
|
676
|
-
*/
|
|
449
|
+
/** Memoized public export. Ref targets the root `.c-atomix-glass` wrapper. */
|
|
677
450
|
export const AtomixGlass = memo(AtomixGlassInner);
|
|
678
451
|
|
|
679
452
|
export default AtomixGlass;
|