@shohojdhara/atomix 0.3.10 → 0.3.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -1
- package/dist/atomix.css +9 -6
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +9 -6
- package/dist/atomix.min.css.map +1 -1
- package/dist/charts.js +82 -60
- package/dist/charts.js.map +1 -1
- package/dist/core.js +82 -60
- package/dist/core.js.map +1 -1
- package/dist/forms.js +82 -60
- package/dist/forms.js.map +1 -1
- package/dist/heavy.js +82 -60
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +11 -107
- package/dist/index.esm.js +165 -407
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +169 -412
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/theme.d.ts +1 -32
- package/dist/theme.js +12 -207
- package/dist/theme.js.map +1 -1
- package/package.json +1 -1
- package/src/components/AtomixGlass/AtomixGlass.tsx +124 -127
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +28 -32
- package/src/components/AtomixGlass/GlassFilter.tsx +15 -4
- package/src/components/EdgePanel/EdgePanel.stories.tsx +2 -7
- package/src/components/EdgePanel/EdgePanel.tsx +0 -10
- package/src/components/Form/Radio.stories.tsx +235 -103
- package/src/components/Navigation/Nav/NavDropdown.tsx +8 -4
- package/src/components/Navigation/SideMenu/SideMenu.tsx +2 -22
- package/src/components/Navigation/SideMenu/SideMenuItem.tsx +11 -15
- package/src/lib/config/index.ts +5 -5
- package/src/lib/theme/config/index.ts +1 -1
- package/src/lib/theme/core/createTheme.ts +11 -40
- package/src/lib/theme/generators/index.ts +1 -4
- package/src/lib/theme/index.ts +4 -16
- package/src/lib/theme/runtime/ThemeProvider.tsx +1 -16
- package/src/lib/types/components.ts +2 -26
- package/src/styles/06-components/_components.edge-panel.scss +4 -4
- package/src/styles/06-components/_components.nav.scss +3 -0
- package/src/lib/config/loader.ts +0 -147
- package/src/lib/theme/config/__tests__/configLoader.test.ts +0 -207
- package/src/lib/theme/config/configLoader.ts +0 -113
- package/src/lib/theme/config/loader.ts +0 -293
- package/src/lib/theme/generators/cssFile.ts +0 -79
package/package.json
CHANGED
|
@@ -109,7 +109,7 @@ export function AtomixGlass({
|
|
|
109
109
|
}: AtomixGlassProps) {
|
|
110
110
|
const glassRef = useRef<HTMLDivElement>(null);
|
|
111
111
|
const contentRef = useRef<HTMLDivElement>(null);
|
|
112
|
-
|
|
112
|
+
|
|
113
113
|
// Use composable hook for all state and logic
|
|
114
114
|
const {
|
|
115
115
|
isHovered,
|
|
@@ -192,101 +192,132 @@ export function AtomixGlass({
|
|
|
192
192
|
: Math.max(glassSize.height, 0),
|
|
193
193
|
};
|
|
194
194
|
|
|
195
|
-
//
|
|
196
|
-
const
|
|
197
|
-
|
|
195
|
+
// Memoize expensive gradient calculations
|
|
196
|
+
const gradientValues = useMemo(() => {
|
|
197
|
+
const mx = mouseOffset.x;
|
|
198
|
+
const my = mouseOffset.y;
|
|
199
|
+
const absMx = Math.abs(mx);
|
|
200
|
+
const absMy = Math.abs(my);
|
|
201
|
+
const GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT;
|
|
198
202
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
203
|
+
return {
|
|
204
|
+
borderGradientAngle: GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER,
|
|
205
|
+
borderStop1: Math.max(
|
|
206
|
+
GRADIENT.BORDER_STOP_1.MIN,
|
|
207
|
+
GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER
|
|
208
|
+
),
|
|
209
|
+
borderStop2: Math.min(
|
|
210
|
+
GRADIENT.BORDER_STOP_2.MAX,
|
|
211
|
+
GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER
|
|
212
|
+
),
|
|
213
|
+
borderOpacities: [
|
|
214
|
+
GRADIENT.BORDER_OPACITY.BASE_1 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW,
|
|
215
|
+
GRADIENT.BORDER_OPACITY.BASE_2 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH,
|
|
216
|
+
GRADIENT.BORDER_OPACITY.BASE_3 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW,
|
|
217
|
+
GRADIENT.BORDER_OPACITY.BASE_4 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH,
|
|
218
|
+
],
|
|
219
|
+
hoverPositions: {
|
|
220
|
+
hover1: {
|
|
221
|
+
x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
|
|
222
|
+
y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1,
|
|
223
|
+
},
|
|
224
|
+
hover2: {
|
|
225
|
+
x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_2,
|
|
226
|
+
y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_2,
|
|
227
|
+
},
|
|
228
|
+
hover3: {
|
|
229
|
+
x: GRADIENT.CENTER_POSITION + mx * GRADIENT.HOVER_POSITION.MULTIPLIER_3,
|
|
230
|
+
y: GRADIENT.CENTER_POSITION + my * GRADIENT.HOVER_POSITION.MULTIPLIER_3,
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
basePosition: {
|
|
234
|
+
x: GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER,
|
|
235
|
+
y: GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER,
|
|
236
|
+
},
|
|
237
|
+
mx,
|
|
238
|
+
my,
|
|
239
|
+
absMx,
|
|
240
|
+
absMy,
|
|
241
|
+
};
|
|
242
|
+
}, [mouseOffset.x, mouseOffset.y]);
|
|
222
243
|
|
|
223
|
-
//
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const hover3X = GRADIENT.CENTER_POSITION + mx * GRADIENT.HOVER_POSITION.MULTIPLIER_3;
|
|
229
|
-
const hover3Y = GRADIENT.CENTER_POSITION + my * GRADIENT.HOVER_POSITION.MULTIPLIER_3;
|
|
244
|
+
// Memoize opacity calculations
|
|
245
|
+
const opacityValues = useMemo(() => {
|
|
246
|
+
const overLightOpacity = overLightConfig.opacity;
|
|
247
|
+
const BASE_OVER_LIGHT_OPACITY = 0.4;
|
|
248
|
+
const OVER_OPACITY_MULTIPLIER = 1.1;
|
|
230
249
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
250
|
+
return {
|
|
251
|
+
hover1: isHovered || isActive ? 0.5 : 0,
|
|
252
|
+
hover2: isActive ? 0.5 : 0,
|
|
253
|
+
hover3: isHovered ? 0.4 : isActive ? 0.8 : 0,
|
|
254
|
+
base: isOverLight ? overLightOpacity || BASE_OVER_LIGHT_OPACITY : 0,
|
|
255
|
+
over: isOverLight ? (overLightOpacity || BASE_OVER_LIGHT_OPACITY) * OVER_OPACITY_MULTIPLIER : 0,
|
|
256
|
+
};
|
|
257
|
+
}, [isHovered, isActive, isOverLight, overLightConfig.opacity]);
|
|
234
258
|
|
|
235
|
-
//
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
259
|
+
// Memoize CSS variables object
|
|
260
|
+
const glassVars = useMemo(() => {
|
|
261
|
+
const whiteColor = '255, 255, 255';
|
|
262
|
+
const blackColor = '0, 0, 0';
|
|
263
|
+
const { borderGradientAngle, borderStop1, borderStop2, borderOpacities, hoverPositions, basePosition, mx, my, absMx, absMy } = gradientValues;
|
|
239
264
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
265
|
+
return {
|
|
266
|
+
'--atomix-glass-radius': `${effectiveCornerRadius}px`,
|
|
267
|
+
'--atomix-glass-transform': transformStyle || 'none',
|
|
268
|
+
'--atomix-glass-position': positionStyles.position,
|
|
269
|
+
'--atomix-glass-top': positionStyles.top !== 'fixed' ? `${positionStyles.top}px` : '0',
|
|
270
|
+
'--atomix-glass-left': positionStyles.left !== 'fixed' ? `${positionStyles.left}px` : '0',
|
|
271
|
+
'--atomix-glass-width': style.position !== 'fixed' ? adjustedSize.width : `${adjustedSize.width}px`,
|
|
272
|
+
'--atomix-glass-height': style.position !== 'fixed' ? adjustedSize.height : `${adjustedSize.height}px`,
|
|
273
|
+
'--atomix-glass-border-width': 'var(--atomix-spacing-0-5, 0.09375rem)',
|
|
274
|
+
'--atomix-glass-blend-mode': isOverLight ? 'multiply' : 'overlay',
|
|
275
|
+
'--atomix-glass-border-gradient-1': `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${borderOpacities[0]}) ${borderStop1}%, rgba(${whiteColor}, ${borderOpacities[1]}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
|
|
276
|
+
'--atomix-glass-border-gradient-2': `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${borderOpacities[2]}) ${borderStop1}%, rgba(${whiteColor}, ${borderOpacities[3]}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
|
|
277
|
+
'--atomix-glass-hover-1-opacity': opacityValues.hover1,
|
|
278
|
+
'--atomix-glass-hover-1-gradient': isOverLight
|
|
279
|
+
? `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}%)`
|
|
280
|
+
: `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}%)`,
|
|
281
|
+
'--atomix-glass-hover-2-opacity': opacityValues.hover2,
|
|
282
|
+
'--atomix-glass-hover-2-gradient': isOverLight
|
|
283
|
+
? `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}%)`
|
|
284
|
+
: `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}%)`,
|
|
285
|
+
'--atomix-glass-hover-3-opacity': opacityValues.hover3,
|
|
286
|
+
'--atomix-glass-hover-3-gradient': isOverLight
|
|
287
|
+
? `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}%)`
|
|
288
|
+
: `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}%)`,
|
|
289
|
+
'--atomix-glass-base-opacity': opacityValues.base,
|
|
290
|
+
'--atomix-glass-base-gradient': isOverLight
|
|
291
|
+
? `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%)`
|
|
292
|
+
: `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`,
|
|
293
|
+
'--atomix-glass-overlay-opacity': opacityValues.over,
|
|
294
|
+
'--atomix-glass-overlay-gradient': isOverLight
|
|
295
|
+
? `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%)`
|
|
296
|
+
: `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`,
|
|
297
|
+
} as React.CSSProperties;
|
|
298
|
+
}, [gradientValues, opacityValues, effectiveCornerRadius, transformStyle, positionStyles, adjustedSize, style.position, isOverLight]);
|
|
247
299
|
|
|
248
|
-
//
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
style
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
'--atomix-glass-hover-1-opacity': opacityValues.hover1,
|
|
270
|
-
'--atomix-glass-hover-1-gradient': isOverLight
|
|
271
|
-
? `radial-gradient(circle at ${hover1X}% ${hover1Y}%, 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}%)`
|
|
272
|
-
: `radial-gradient(circle at ${hover1X}% ${hover1Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_STOP}%)`,
|
|
273
|
-
'--atomix-glass-hover-2-opacity': opacityValues.hover2,
|
|
274
|
-
'--atomix-glass-hover-2-gradient': isOverLight
|
|
275
|
-
? `radial-gradient(circle at ${hover2X}% ${hover2Y}%, 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}%)`
|
|
276
|
-
: `radial-gradient(circle at ${hover2X}% ${hover2Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_STOP}%)`,
|
|
277
|
-
'--atomix-glass-hover-3-opacity': opacityValues.hover3,
|
|
278
|
-
'--atomix-glass-hover-3-gradient': isOverLight
|
|
279
|
-
? `radial-gradient(circle at ${hover3X}% ${hover3Y}%, 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}%)`
|
|
280
|
-
: `radial-gradient(circle at ${hover3X}% ${hover3Y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_STOP}%)`,
|
|
281
|
-
'--atomix-glass-base-opacity': opacityValues.base,
|
|
282
|
-
'--atomix-glass-base-gradient': isOverLight
|
|
283
|
-
? `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 + Math.abs(mx) * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)`
|
|
284
|
-
: `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`,
|
|
285
|
-
'--atomix-glass-overlay-opacity': opacityValues.over,
|
|
286
|
-
'--atomix-glass-overlay-gradient': isOverLight
|
|
287
|
-
? `radial-gradient(circle at ${baseX}% ${baseY}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + Math.abs(mx) * 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 + Math.abs(my) * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)`
|
|
288
|
-
: `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`,
|
|
289
|
-
} as React.CSSProperties;
|
|
300
|
+
// Helper function to render background layers
|
|
301
|
+
const renderBackgroundLayer = (layerType: 'dark' | 'black') => (
|
|
302
|
+
<div
|
|
303
|
+
className={[
|
|
304
|
+
ATOMIX_GLASS.BACKGROUND_LAYER_CLASS,
|
|
305
|
+
layerType === 'dark' ? ATOMIX_GLASS.BACKGROUND_LAYER_DARK_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_BLACK_CLASS,
|
|
306
|
+
isOverLight
|
|
307
|
+
? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS
|
|
308
|
+
: ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS,
|
|
309
|
+
]
|
|
310
|
+
.filter(Boolean)
|
|
311
|
+
.join(' ')}
|
|
312
|
+
style={{
|
|
313
|
+
...positionStyles,
|
|
314
|
+
height: adjustedSize.height,
|
|
315
|
+
width: adjustedSize.width,
|
|
316
|
+
borderRadius: `${effectiveCornerRadius}px`,
|
|
317
|
+
transform: baseStyle.transform,
|
|
318
|
+
}}
|
|
319
|
+
/>
|
|
320
|
+
);
|
|
290
321
|
|
|
291
322
|
return (
|
|
292
323
|
<div
|
|
@@ -298,7 +329,7 @@ export function AtomixGlass({
|
|
|
298
329
|
aria-describedby={ariaDescribedBy}
|
|
299
330
|
aria-disabled={onClick && effectiveDisableEffects ? true : onClick ? false : undefined}
|
|
300
331
|
aria-pressed={onClick && isActive ? true : onClick ? false : undefined}
|
|
301
|
-
onKeyDown={onClick ? handleKeyDown : undefined}
|
|
332
|
+
onKeyDown={onClick ? handleKeyDown : undefined} // Dynamic CSS variables cause hydration mismatch due to mouse position calculations
|
|
302
333
|
>
|
|
303
334
|
<AtomixGlassContainer
|
|
304
335
|
ref={glassRef}
|
|
@@ -364,42 +395,8 @@ export function AtomixGlass({
|
|
|
364
395
|
|
|
365
396
|
{/* Background layers for over-light mode */}
|
|
366
397
|
{/* Static styles (pointer-events, will-change) are in SCSS */}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
ATOMIX_GLASS.BACKGROUND_LAYER_CLASS,
|
|
370
|
-
ATOMIX_GLASS.BACKGROUND_LAYER_DARK_CLASS,
|
|
371
|
-
isOverLight
|
|
372
|
-
? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS
|
|
373
|
-
: ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS,
|
|
374
|
-
]
|
|
375
|
-
.filter(Boolean)
|
|
376
|
-
.join(' ')}
|
|
377
|
-
style={{
|
|
378
|
-
...positionStyles,
|
|
379
|
-
height: adjustedSize.height,
|
|
380
|
-
width: adjustedSize.width,
|
|
381
|
-
borderRadius: `${effectiveCornerRadius}px`,
|
|
382
|
-
transform: baseStyle.transform,
|
|
383
|
-
}}
|
|
384
|
-
/>
|
|
385
|
-
<div
|
|
386
|
-
className={[
|
|
387
|
-
ATOMIX_GLASS.BACKGROUND_LAYER_CLASS,
|
|
388
|
-
ATOMIX_GLASS.BACKGROUND_LAYER_BLACK_CLASS,
|
|
389
|
-
isOverLight
|
|
390
|
-
? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS
|
|
391
|
-
: ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS,
|
|
392
|
-
]
|
|
393
|
-
.filter(Boolean)
|
|
394
|
-
.join(' ')}
|
|
395
|
-
style={{
|
|
396
|
-
...positionStyles,
|
|
397
|
-
height: adjustedSize.height,
|
|
398
|
-
width: adjustedSize.width,
|
|
399
|
-
borderRadius: `${effectiveCornerRadius}px`,
|
|
400
|
-
transform: baseStyle.transform,
|
|
401
|
-
}}
|
|
402
|
-
/>
|
|
398
|
+
{renderBackgroundLayer('dark')}
|
|
399
|
+
{renderBackgroundLayer('black')}
|
|
403
400
|
{shouldRenderOverLightLayers && (
|
|
404
401
|
<>
|
|
405
402
|
{/* Base and overlay layers - opacity and background set via CSS variables in SCSS */}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { forwardRef,
|
|
1
|
+
import React, { forwardRef, useRef, useState, useEffect, useMemo } from 'react';
|
|
2
2
|
import type { CSSProperties } from 'react';
|
|
3
3
|
import type { DisplacementMode, MousePosition, GlassSize } from '../../lib/types/components';
|
|
4
4
|
import type { FragmentShaderType } from './shader-utils';
|
|
@@ -51,11 +51,11 @@ const setCachedShader = (key: string, url: string): void => {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
sharedShaderCache.set(key, { url, timestamp: Date.now() });
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
// Development mode: log cache size
|
|
56
56
|
if (typeof process === 'undefined' || process.env?.NODE_ENV !== 'production') {
|
|
57
57
|
if (sharedShaderCache.size >= MAX_CACHE_SIZE * 0.8) {
|
|
58
|
-
console.log(`AtomixGlass: Shader cache size: ${sharedShaderCache.size}/${MAX_CACHE_SIZE}`);
|
|
58
|
+
console.log(`AtomixGlass: Shader cache size: ${String(sharedShaderCache.size).replace(/[\r\n]/g, '')}/${String(MAX_CACHE_SIZE).replace(/[\r\n]/g, '')}`);
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
};
|
|
@@ -131,26 +131,26 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
|
|
|
131
131
|
ref
|
|
132
132
|
) => {
|
|
133
133
|
// Generate a stable, deterministic ID for SSR compatibility
|
|
134
|
-
//
|
|
135
|
-
// component position in the tree. We use useState to ensure the ID is only
|
|
136
|
-
// generated once and remains stable across renders.
|
|
137
|
-
const baseId = useId();
|
|
134
|
+
// Use a counter-based approach to avoid hydration mismatches
|
|
138
135
|
const [filterId] = useState(() => {
|
|
139
|
-
//
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
136
|
+
// Use a simple counter for deterministic IDs
|
|
137
|
+
if (typeof window === 'undefined') {
|
|
138
|
+
// Server-side: use a predictable pattern
|
|
139
|
+
return `atomix-glass-filter-ssr-${Math.random().toString(36).substring(2, 11)}`;
|
|
140
|
+
}
|
|
141
|
+
// Client-side: use timestamp + random for uniqueness
|
|
142
|
+
return `atomix-glass-filter-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
|
|
143
143
|
});
|
|
144
|
-
|
|
144
|
+
|
|
145
145
|
const [shaderMapUrl, setShaderMapUrl] = useState<string>('');
|
|
146
146
|
const shaderGeneratorRef = useRef<any>(null);
|
|
147
147
|
const shaderUtilsRef = useRef<{
|
|
148
148
|
ShaderDisplacementGenerator: any;
|
|
149
149
|
fragmentShaders: any;
|
|
150
150
|
} | null>(null);
|
|
151
|
-
|
|
151
|
+
|
|
152
152
|
// Use shared module-level cache (no per-instance cache needed)
|
|
153
|
-
const shaderDebounceTimeoutRef = useRef<
|
|
153
|
+
const shaderDebounceTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
154
154
|
|
|
155
155
|
// Lazy load shader utilities only when shader mode is needed
|
|
156
156
|
useEffect(() => {
|
|
@@ -162,7 +162,7 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
|
|
|
162
162
|
fragmentShaders: shaderUtils.fragmentShaders,
|
|
163
163
|
};
|
|
164
164
|
}).catch((error) => {
|
|
165
|
-
console.warn('AtomixGlassContainer: Error loading shader utilities', error);
|
|
165
|
+
console.warn('AtomixGlassContainer: Error loading shader utilities', String(error).replace(/[\r\n]/g, ''));
|
|
166
166
|
});
|
|
167
167
|
} else {
|
|
168
168
|
// Clear shader utils when not in shader mode to free memory
|
|
@@ -176,7 +176,7 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
|
|
|
176
176
|
if (mode === 'shader' && glassSize && validateGlassSize(glassSize) && shaderUtilsRef.current) {
|
|
177
177
|
// Create cache key from size and variant
|
|
178
178
|
const cacheKey = `${glassSize.width}x${glassSize.height}-${shaderVariant}`;
|
|
179
|
-
|
|
179
|
+
|
|
180
180
|
// Check shared cache first
|
|
181
181
|
const cachedUrl = getCachedShader(cacheKey);
|
|
182
182
|
if (cachedUrl) {
|
|
@@ -206,7 +206,7 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
|
|
|
206
206
|
height: glassSize.height,
|
|
207
207
|
fragment: selectedShader,
|
|
208
208
|
});
|
|
209
|
-
|
|
209
|
+
|
|
210
210
|
// Use requestIdleCallback if available for non-blocking generation
|
|
211
211
|
const generate = () => {
|
|
212
212
|
const url = shaderGeneratorRef.current?.updateShader() || '';
|
|
@@ -435,11 +435,11 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
|
|
|
435
435
|
'--atomix-glass-container-backdrop': backdropStyle?.backdropFilter || 'none',
|
|
436
436
|
'--atomix-glass-container-shadow': overLight
|
|
437
437
|
? [
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
438
|
+
`inset 0 1px 0 rgba(255, 255, 255, ${0.4 + mx * 0.002})`,
|
|
439
|
+
`inset 0 -1px 0 rgba(0, 0, 0, ${0.2 + Math.abs(my) * 0.001})`,
|
|
440
|
+
`inset 0 0 20px rgba(0, 0, 0, ${0.08 + Math.abs(mx + my) * 0.001})`,
|
|
441
|
+
`0 2px 12px rgba(0, 0, 0, ${0.12 + Math.abs(my) * 0.002})`,
|
|
442
|
+
].join(', ')
|
|
443
443
|
: '0 0 20px rgba(0, 0, 0, 0.15) inset, 0 4px 8px rgba(0, 0, 0, 0.08) inset',
|
|
444
444
|
'--atomix-glass-container-shadow-opacity': effectiveDisableEffects ? 0 : 1,
|
|
445
445
|
// Background and shadow values use design token-aligned RGB values
|
|
@@ -511,25 +511,22 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
|
|
|
511
511
|
shaderMapUrl={shaderMapUrl}
|
|
512
512
|
/>
|
|
513
513
|
{/* Enhanced Apple Liquid Glass Inner Shadow Layer */}
|
|
514
|
-
|
|
515
514
|
<div
|
|
516
515
|
className={ATOMIX_GLASS.FILTER_OVERLAY_CLASS}
|
|
517
|
-
suppressHydrationWarning
|
|
518
516
|
style={{
|
|
519
517
|
filter: `url(#${filterId})`,
|
|
520
518
|
backdropFilter: `var(--atomix-glass-container-backdrop)`,
|
|
521
519
|
borderRadius: `var(--atomix-glass-container-radius)`,
|
|
522
520
|
}}
|
|
523
521
|
/>
|
|
524
|
-
|
|
525
522
|
<div
|
|
526
523
|
className={ATOMIX_GLASS.FILTER_SHADOW_CLASS}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
524
|
+
style={{
|
|
525
|
+
boxShadow: `var(--atomix-glass-container-shadow)`,
|
|
526
|
+
opacity: `var(--atomix-glass-container-shadow-opacity)`,
|
|
527
|
+
background: `var(--atomix-glass-container-bg)`,
|
|
528
|
+
borderRadius: `var(--atomix-glass-container-radius)`,
|
|
529
|
+
}}
|
|
533
530
|
/>
|
|
534
531
|
</div>
|
|
535
532
|
|
|
@@ -538,7 +535,6 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
|
|
|
538
535
|
className={ATOMIX_GLASS.CONTENT_CLASS}
|
|
539
536
|
style={{
|
|
540
537
|
position: 'relative',
|
|
541
|
-
|
|
542
538
|
textShadow: `var(--atomix-glass-container-text-shadow)`,
|
|
543
539
|
...(elasticity > 0 ? { zIndex: 100 } : {}),
|
|
544
540
|
}}
|
|
@@ -33,10 +33,14 @@ const GlassFilterComponent: React.FC<GlassFilterProps> = ({
|
|
|
33
33
|
inset: 0,
|
|
34
34
|
}}
|
|
35
35
|
aria-hidden="true"
|
|
36
|
-
suppressHydrationWarning
|
|
37
36
|
>
|
|
38
37
|
<defs>
|
|
39
|
-
<radialGradient
|
|
38
|
+
<radialGradient
|
|
39
|
+
id={`${id}-edge-mask`}
|
|
40
|
+
cx="50%"
|
|
41
|
+
cy="50%"
|
|
42
|
+
r="50%"
|
|
43
|
+
>
|
|
40
44
|
<stop offset="0%" stopColor="black" stopOpacity="0" />
|
|
41
45
|
<stop
|
|
42
46
|
offset={`${Math.max(30, 80 - aberrationIntensity * 2)}%`}
|
|
@@ -45,9 +49,16 @@ const GlassFilterComponent: React.FC<GlassFilterProps> = ({
|
|
|
45
49
|
/>
|
|
46
50
|
<stop offset="100%" stopColor="white" stopOpacity="1" />
|
|
47
51
|
</radialGradient>
|
|
48
|
-
<filter
|
|
52
|
+
<filter
|
|
53
|
+
id={id}
|
|
54
|
+
x="-35%"
|
|
55
|
+
y="-35%"
|
|
56
|
+
width="170%"
|
|
57
|
+
height="170%"
|
|
58
|
+
colorInterpolationFilters="sRGB"
|
|
59
|
+
>
|
|
49
60
|
<feImage
|
|
50
|
-
id=
|
|
61
|
+
id={`${id}-image`}
|
|
51
62
|
x="0"
|
|
52
63
|
y="0"
|
|
53
64
|
width="100%"
|
|
@@ -504,14 +504,12 @@ export const GlassPremium: Story = {
|
|
|
504
504
|
<Card
|
|
505
505
|
title="Enhanced Visuals"
|
|
506
506
|
text="Premium glass shader provides the most refined appearance."
|
|
507
|
-
glass
|
|
508
507
|
className="u-mb-3"
|
|
509
508
|
/>
|
|
510
509
|
|
|
511
510
|
<Card
|
|
512
511
|
title="Perfect for Modern Apps"
|
|
513
512
|
text="Ideal for applications requiring sophisticated UI design."
|
|
514
|
-
glass
|
|
515
513
|
className="u-mb-3"
|
|
516
514
|
/>
|
|
517
515
|
|
|
@@ -598,7 +596,7 @@ export const GlassShowcase: Story = {
|
|
|
598
596
|
<p className="u-mb-4">
|
|
599
597
|
Classic glass morphism with balanced displacement and blur for general use.
|
|
600
598
|
</p>
|
|
601
|
-
<Card title="Balanced Design" text="Perfect for everyday applications."
|
|
599
|
+
<Card title="Balanced Design" text="Perfect for everyday applications." />
|
|
602
600
|
</div>
|
|
603
601
|
</EdgePanel>
|
|
604
602
|
|
|
@@ -630,7 +628,6 @@ export const GlassShowcase: Story = {
|
|
|
630
628
|
<Card
|
|
631
629
|
title="Radial Distortion"
|
|
632
630
|
text="Creates circular displacement patterns."
|
|
633
|
-
glass
|
|
634
631
|
/>
|
|
635
632
|
</div>
|
|
636
633
|
</EdgePanel>
|
|
@@ -660,7 +657,7 @@ export const GlassShowcase: Story = {
|
|
|
660
657
|
<p className="u-mb-4">
|
|
661
658
|
Stronger displacement and blur for bold, eye-catching interfaces.
|
|
662
659
|
</p>
|
|
663
|
-
<Card title="Bold Appearance" text="Maximum visual impact and depth."
|
|
660
|
+
<Card title="Bold Appearance" text="Maximum visual impact and depth." />
|
|
664
661
|
</div>
|
|
665
662
|
</EdgePanel>
|
|
666
663
|
|
|
@@ -693,7 +690,6 @@ export const GlassShowcase: Story = {
|
|
|
693
690
|
<Card
|
|
694
691
|
title="Premium Quality"
|
|
695
692
|
text="Smooth, flowing distortions powered by WebGL shaders."
|
|
696
|
-
glass
|
|
697
693
|
/>
|
|
698
694
|
</div>
|
|
699
695
|
</EdgePanel>
|
|
@@ -727,7 +723,6 @@ export const GlassShowcase: Story = {
|
|
|
727
723
|
<Card
|
|
728
724
|
title="Elite Design"
|
|
729
725
|
text="The pinnacle of glass morphism for luxury applications."
|
|
730
|
-
glass
|
|
731
726
|
/>
|
|
732
727
|
</div>
|
|
733
728
|
</EdgePanel>
|
|
@@ -127,16 +127,6 @@ export const EdgePanel: React.FC<EdgePanelProps> = ({
|
|
|
127
127
|
{glass ? (
|
|
128
128
|
<AtomixGlass
|
|
129
129
|
{...glassProps}
|
|
130
|
-
className="c-edge-panel__glass-wrapper"
|
|
131
|
-
style={{
|
|
132
|
-
position: 'fixed',
|
|
133
|
-
width: glassContentRef.current?.offsetWidth,
|
|
134
|
-
height: glassContentRef.current?.offsetHeight,
|
|
135
|
-
top: containerRef.current?.offsetTop,
|
|
136
|
-
left: containerRef.current?.offsetLeft,
|
|
137
|
-
bottom: containerRef.current?.style.bottom,
|
|
138
|
-
right: containerRef.current?.style.right,
|
|
139
|
-
}}
|
|
140
130
|
>
|
|
141
131
|
<div
|
|
142
132
|
ref={glassContentRef}
|