@shohojdhara/atomix 0.6.1 → 0.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shohojdhara/atomix",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "Atomix Design System - A modern component library for web applications",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -0,0 +1,390 @@
1
+ import React, { useId, useMemo, useRef } from 'react';
2
+ import type { AtomixGlassProps } from '../../../lib/types/components';
3
+ import { ATOMIX_GLASS } from '../../../lib/constants/components';
4
+ import { AtomixGlassContainer } from '../AtomixGlassContainer';
5
+ import { useAtomixGlass } from '../../../lib/composables/useAtomixGlass';
6
+
7
+ /**
8
+ * AtomixGlass - A high-performance glass morphism component with liquid distortion effects
9
+ *
10
+ * Features:
11
+ * - Hardware-accelerated glass effects with SVG filters
12
+ * - Mouse-responsive liquid distortion
13
+ * - Dynamic border-radius extraction from children CSS properties
14
+ * - Automatic light/dark theme detection
15
+ * - Accessibility and performance optimizations
16
+ * - Multiple displacement modes (standard, polar, prominent, shader)
17
+ *
18
+ * @example
19
+ * // Dynamic border-radius extraction
20
+ * <AtomixGlass>
21
+ * <div style={{ borderRadius: '12px' }}>Content with 12px radius</div>
22
+ * </AtomixGlass>
23
+ *
24
+ * @example
25
+ * // Manual border-radius override
26
+ * <AtomixGlass cornerRadius={20}>
27
+ * <div>Content with 20px glass radius</div>
28
+ * </AtomixGlass>
29
+ */
30
+ export function AtomixGlass({
31
+ children,
32
+ displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE,
33
+ blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT,
34
+ saturation = ATOMIX_GLASS.DEFAULTS.SATURATION,
35
+ aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY,
36
+ elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY,
37
+ borderRadius,
38
+ globalMousePosition: externalGlobalMousePosition,
39
+ mouseOffset: externalMouseOffset,
40
+ mouseContainer = null,
41
+ className = '',
42
+ padding = ATOMIX_GLASS.DEFAULTS.PADDING,
43
+ overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT,
44
+ style = {},
45
+ mode = ATOMIX_GLASS.DEFAULTS.MODE,
46
+ onClick,
47
+ shaderVariant = 'liquidGlass',
48
+ 'aria-label': ariaLabel,
49
+ 'aria-describedby': ariaDescribedBy,
50
+ role,
51
+ tabIndex,
52
+ reducedMotion = false,
53
+ highContrast = false,
54
+ withoutEffects = false,
55
+ withLiquidBlur = false,
56
+ withBorder = true,
57
+ withOverLightLayers = false,
58
+ debugBorderRadius = false,
59
+ }: AtomixGlassProps) {
60
+ const glassRef = useRef<HTMLDivElement>(null);
61
+ const contentRef = useRef<HTMLDivElement>(null);
62
+
63
+ // Use composable hook for all state and logic
64
+ const {
65
+ isHovered,
66
+ isActive,
67
+ glassSize,
68
+ effectiveBorderRadius,
69
+ effectiveReducedMotion,
70
+ effectiveHighContrast,
71
+ effectiveWithoutEffects,
72
+ overLightConfig,
73
+ globalMousePosition,
74
+ mouseOffset,
75
+ transformStyle,
76
+ handleMouseEnter,
77
+ handleMouseLeave,
78
+ handleMouseDown,
79
+ handleMouseUp,
80
+ handleKeyDown,
81
+ } = useAtomixGlass({
82
+ glassRef,
83
+ contentRef,
84
+ borderRadius,
85
+ globalMousePosition: externalGlobalMousePosition,
86
+ mouseOffset: externalMouseOffset,
87
+ mouseContainer,
88
+ overLight,
89
+ reducedMotion,
90
+ highContrast,
91
+ withoutEffects,
92
+ elasticity,
93
+ onClick,
94
+ debugBorderRadius,
95
+ children,
96
+ });
97
+
98
+ // Calculate base style with transforms
99
+ const baseStyle = useMemo(
100
+ () => ({
101
+ ...style,
102
+ ...(elasticity !== 0 && {
103
+ transform: transformStyle,
104
+ transition: effectiveReducedMotion ? 'none' : 'all ease-out 0.2s',
105
+ willChange: effectiveWithoutEffects ? 'auto' : 'transform',
106
+ }),
107
+ ...(effectiveHighContrast && {
108
+ border: '2px solid currentColor',
109
+ outline: '2px solid transparent',
110
+ outlineOffset: '2px',
111
+ }),
112
+ }),
113
+ [
114
+ style,
115
+ transformStyle,
116
+ effectiveReducedMotion,
117
+ effectiveWithoutEffects,
118
+ effectiveHighContrast,
119
+ elasticity,
120
+ ]
121
+ );
122
+
123
+ // Calculate position and size styles
124
+ const positionStyles = useMemo(
125
+ () => ({
126
+ position: (baseStyle.position || 'absolute') as React.CSSProperties['position'],
127
+ top: baseStyle.top || 0,
128
+ left: baseStyle.left || 0,
129
+ }),
130
+ [baseStyle]
131
+ );
132
+
133
+ const adjustedSize = useMemo(
134
+ () => ({
135
+ width:
136
+ baseStyle.position !== 'fixed'
137
+ ? '100%'
138
+ : baseStyle.width
139
+ ? baseStyle.width
140
+ : Math.max(glassSize.width, 0),
141
+ height:
142
+ baseStyle.position !== 'fixed'
143
+ ? '100%'
144
+ : baseStyle.height
145
+ ? baseStyle.height
146
+ : Math.max(glassSize.height, 0),
147
+ }),
148
+ [baseStyle, glassSize]
149
+ );
150
+
151
+ // Generate CSS variables for layers
152
+ const glassId = useId();
153
+ const glassVars = useMemo(() => {
154
+ const isOverLight = overLightConfig?.isOverLight ?? false;
155
+ const mx = mouseOffset.x;
156
+ const my = mouseOffset.y;
157
+ const scopedId = `ag-${glassId.replace(/:/g, '')}`;
158
+
159
+ return {
160
+ [`--${scopedId}-pos`]: positionStyles.position,
161
+ [`--${scopedId}-top`]: positionStyles.top !== 'fixed' ? `${positionStyles.top}px` : '0',
162
+ [`--${scopedId}-left`]: positionStyles.left !== 'fixed' ? `${positionStyles.left}px` : '0',
163
+ [`--${scopedId}-w`]:
164
+ baseStyle.position !== 'fixed' ? adjustedSize.width : `${adjustedSize.width}px`,
165
+ [`--${scopedId}-h`]:
166
+ baseStyle.position !== 'fixed' ? adjustedSize.height : `${adjustedSize.height}px`,
167
+ [`--${scopedId}-r`]: `${effectiveBorderRadius}px`,
168
+ [`--${scopedId}-t`]: baseStyle.transform,
169
+ [`--${scopedId}-tr`]: effectiveReducedMotion ? 'none' : baseStyle.transition,
170
+ [`--${scopedId}-blend`]: isOverLight ? 'multiply' : 'overlay',
171
+ [`--${scopedId}-b1`]: `linear-gradient(${135 + mx * 1.2}deg, rgba(255,255,255,0) 0%, rgba(255,255,255,${0.12 + Math.abs(mx) * 0.008}) ${Math.max(10, 33 + my * 0.3)}%, rgba(255,255,255,${0.4 + Math.abs(mx) * 0.012}) ${Math.min(90, 66 + my * 0.4)}%, rgba(255,255,255,0) 100%)`,
172
+ [`--${scopedId}-b2`]: `linear-gradient(${135 + mx * 1.2}deg, rgba(255,255,255,0) 0%, rgba(255,255,255,${0.32 + Math.abs(mx) * 0.008}) ${Math.max(10, 33 + my * 0.3)}%, rgba(255,255,255,${0.6 + Math.abs(mx) * 0.012}) ${Math.min(90, 66 + my * 0.4)}%, rgba(255,255,255,0) 100%)`,
173
+ [`--${scopedId}-h1-o`]: isHovered || isActive ? (isOverLight ? 0.3 : 0.5) : 0,
174
+ [`--${scopedId}-h1`]: isOverLight
175
+ ? `radial-gradient(circle at ${50 + mx / 2}% ${50 + my / 2}%, rgba(0,0,0,0.2) 0%, rgba(0,0,0,0.05) 30%, rgba(0,0,0,0) 60%)`
176
+ : `radial-gradient(circle at ${50 + mx / 2}% ${50 + my / 2}%, rgba(255,255,255,0.5) 0%, rgba(255,255,255,0) 50%)`,
177
+ [`--${scopedId}-h2-o`]: isActive ? (isOverLight ? 0.4 : 0.5) : 0,
178
+ [`--${scopedId}-h2`]: isOverLight
179
+ ? `radial-gradient(circle at ${50 + mx / 1.5}% ${50 + my / 1.5}%, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.1) 40%, rgba(0,0,0,0) 80%)`
180
+ : `radial-gradient(circle at ${50 + mx / 1.5}% ${50 + my / 1.5}%, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 80%)`,
181
+ [`--${scopedId}-h3-o`]: isHovered
182
+ ? isOverLight
183
+ ? 0.25
184
+ : 0.4
185
+ : isActive
186
+ ? isOverLight
187
+ ? 0.5
188
+ : 0.8
189
+ : 0,
190
+ [`--${scopedId}-h3`]: isOverLight
191
+ ? `radial-gradient(circle at ${50 + mx}% ${50 + my}%, rgba(0,0,0,0.4) 0%, rgba(0,0,0,0.1) 50%, rgba(0,0,0,0) 100%)`
192
+ : `radial-gradient(circle at ${50 + mx}% ${50 + my}%, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%)`,
193
+ [`--${scopedId}-base-o`]: isOverLight ? overLightConfig.opacity : 0,
194
+ [`--${scopedId}-base`]: isOverLight
195
+ ? `linear-gradient(135deg, rgba(0,0,0,${0.12 + mx * 0.002}) 0%, rgba(0,0,0,${0.08 + my * 0.001}) 50%, rgba(0,0,0,${0.15 + Math.abs(mx) * 0.003}) 100%)`
196
+ : 'rgba(255,255,255,0.1)',
197
+ [`--${scopedId}-over-o`]: isOverLight ? overLightConfig.opacity * 0.9 : 0,
198
+ [`--${scopedId}-over`]: isOverLight
199
+ ? `radial-gradient(circle at ${50 + mx * 0.5}% ${50 + my * 0.5}%, rgba(0,0,0,${0.08 + Math.abs(mx) * 0.002}) 0%, rgba(0,0,0,0.04) 40%, rgba(0,0,0,${0.12 + Math.abs(my) * 0.002}) 100%)`
200
+ : 'rgba(255,255,255,0.05)',
201
+ '--ag-scoped-id': scopedId,
202
+ } as React.CSSProperties;
203
+ }, [
204
+ glassId,
205
+ positionStyles,
206
+ adjustedSize,
207
+ effectiveBorderRadius,
208
+ baseStyle,
209
+ effectiveReducedMotion,
210
+ mouseOffset,
211
+ isHovered,
212
+ isActive,
213
+ overLightConfig,
214
+ ]);
215
+
216
+ const scopedId = `ag-${glassId.replace(/:/g, '')}`;
217
+
218
+ return (
219
+ <div
220
+ className={`${ATOMIX_GLASS.BASE_CLASS} ${className}`}
221
+ style={{ ...positionStyles, position: 'relative', ...glassVars }}
222
+ role={role || (onClick ? 'button' : undefined)}
223
+ tabIndex={onClick ? (tabIndex ?? 0) : tabIndex}
224
+ aria-label={ariaLabel}
225
+ aria-describedby={ariaDescribedBy}
226
+ aria-disabled={onClick ? false : undefined}
227
+ onKeyDown={onClick ? handleKeyDown : undefined}
228
+ >
229
+ <AtomixGlassContainer
230
+ ref={glassRef}
231
+ contentRef={contentRef}
232
+ className={className}
233
+ style={baseStyle}
234
+ borderRadius={effectiveBorderRadius}
235
+ displacementScale={
236
+ effectiveWithoutEffects
237
+ ? 0
238
+ : mode === 'shader'
239
+ ? displacementScale * 0.8
240
+ : overLightConfig.isOverLight
241
+ ? displacementScale * 0.6
242
+ : displacementScale
243
+ }
244
+ blurAmount={effectiveWithoutEffects ? 0 : blurAmount}
245
+ saturation={
246
+ effectiveHighContrast
247
+ ? 200
248
+ : overLightConfig.isOverLight
249
+ ? saturation * overLightConfig.saturationBoost
250
+ : saturation
251
+ }
252
+ aberrationIntensity={
253
+ effectiveWithoutEffects
254
+ ? 0
255
+ : mode === 'shader'
256
+ ? aberrationIntensity * 0.7
257
+ : aberrationIntensity
258
+ }
259
+ glassSize={glassSize}
260
+ padding={padding}
261
+ mouseOffset={effectiveWithoutEffects ? { x: 0, y: 0 } : mouseOffset}
262
+ globalMousePosition={effectiveWithoutEffects ? { x: 0, y: 0 } : globalMousePosition}
263
+ onMouseEnter={handleMouseEnter}
264
+ onMouseLeave={handleMouseLeave}
265
+ onMouseDown={handleMouseDown}
266
+ onMouseUp={handleMouseUp}
267
+ isHovered={isHovered}
268
+ isActive={isActive}
269
+ overLight={overLightConfig?.isOverLight || false}
270
+ onClick={onClick}
271
+ mode={mode}
272
+ transform={baseStyle.transform}
273
+ effectiveWithoutEffects={effectiveWithoutEffects}
274
+ effectiveReducedMotion={effectiveReducedMotion}
275
+ shaderVariant={shaderVariant}
276
+ elasticity={elasticity}
277
+ withLiquidBlur={withLiquidBlur}
278
+ >
279
+ {children}
280
+ </AtomixGlassContainer>
281
+ {withBorder && (
282
+ <>
283
+ <span
284
+ className={ATOMIX_GLASS.BORDER_1_CLASS}
285
+ style={{
286
+ position: `var(--${scopedId}-pos)` as any,
287
+ top: `var(--${scopedId}-top)`,
288
+ left: `var(--${scopedId}-left)`,
289
+ width: `var(--${scopedId}-w)`,
290
+ height: `var(--${scopedId}-h)`,
291
+ borderRadius: `var(--${scopedId}-r)`,
292
+ transform: `var(--${scopedId}-t)`,
293
+ transition: `var(--${scopedId}-tr)`,
294
+ background: `var(--${scopedId}-b1)`,
295
+ }}
296
+ />
297
+ <span
298
+ className={ATOMIX_GLASS.BORDER_2_CLASS}
299
+ style={{
300
+ position: `var(--${scopedId}-pos)` as any,
301
+ top: `var(--${scopedId}-top)`,
302
+ left: `var(--${scopedId}-left)`,
303
+ width: `var(--${scopedId}-w)`,
304
+ height: `var(--${scopedId}-h)`,
305
+ borderRadius: `var(--${scopedId}-r)`,
306
+ transform: `var(--${scopedId}-t)`,
307
+ transition: `var(--${scopedId}-tr)`,
308
+ mixBlendMode: `var(--${scopedId}-blend)` as any,
309
+ background: `var(--${scopedId}-b2)`,
310
+ }}
311
+ />
312
+ </>
313
+ )}
314
+ {Boolean(onClick) && (
315
+ <>
316
+ <div
317
+ className={ATOMIX_GLASS.HOVER_1_CLASS}
318
+ style={{
319
+ position: 'absolute',
320
+ inset: 0,
321
+ borderRadius: `var(--${scopedId}-r)`,
322
+ transform: `var(--${scopedId}-t)`,
323
+ transition: `var(--${scopedId}-tr)`,
324
+ mixBlendMode: `var(--${scopedId}-blend)` as any,
325
+ opacity: `var(--${scopedId}-h1-o)`,
326
+ background: `var(--${scopedId}-h1)`,
327
+ }}
328
+ />
329
+ <div
330
+ className={ATOMIX_GLASS.HOVER_2_CLASS}
331
+ style={{
332
+ position: 'absolute',
333
+ inset: 0,
334
+ borderRadius: `var(--${scopedId}-r)`,
335
+ transform: `var(--${scopedId}-t)`,
336
+ transition: `var(--${scopedId}-tr)`,
337
+ mixBlendMode: `var(--${scopedId}-blend)` as any,
338
+ opacity: `var(--${scopedId}-h2-o)`,
339
+ background: `var(--${scopedId}-h2)`,
340
+ }}
341
+ />
342
+ <div
343
+ className={ATOMIX_GLASS.HOVER_3_CLASS}
344
+ style={{
345
+ position: 'absolute',
346
+ inset: 0,
347
+ borderRadius: `var(--${scopedId}-r)`,
348
+ transform: `var(--${scopedId}-t)`,
349
+ transition: `var(--${scopedId}-tr)`,
350
+ mixBlendMode: `var(--${scopedId}-blend)` as any,
351
+ opacity: `var(--${scopedId}-h3-o)`,
352
+ background: `var(--${scopedId}-h3)`,
353
+ }}
354
+ />
355
+ </>
356
+ )}
357
+ {withOverLightLayers && (
358
+ <>
359
+ <div
360
+ className={ATOMIX_GLASS.BASE_LAYER_CLASS}
361
+ style={{
362
+ position: 'absolute',
363
+ inset: 0,
364
+ borderRadius: `var(--${scopedId}-r)`,
365
+ transform: `var(--${scopedId}-t)`,
366
+ transition: `var(--${scopedId}-tr)`,
367
+ opacity: `var(--${scopedId}-base-o)`,
368
+ background: `var(--${scopedId}-base)`,
369
+ }}
370
+ />
371
+ <div
372
+ className={ATOMIX_GLASS.OVERLAY_LAYER_CLASS}
373
+ style={{
374
+ position: 'absolute',
375
+ inset: 0,
376
+ borderRadius: `var(--${scopedId}-r)`,
377
+ transform: `var(--${scopedId}-t)`,
378
+ transition: `var(--${scopedId}-tr)`,
379
+ opacity: `var(--${scopedId}-over-o)`,
380
+ background: `var(--${scopedId}-over)`,
381
+ }}
382
+ />
383
+ </>
384
+ )}
385
+ </div>
386
+ );
387
+ }
388
+
389
+ export default AtomixGlass;
390
+
@@ -1,12 +1,18 @@
1
1
  import type { MousePosition } from '../types/components';
2
2
 
3
+ interface MouseTrackerListener {
4
+ callback: (pos: MousePosition) => void;
5
+ element?: HTMLElement; // Optional element for distance-based attenuation
6
+ maxDistance?: number; // Maximum distance for full effect
7
+ }
8
+
3
9
  /**
4
10
  * Global mouse tracker singleton
5
11
  * Tracks mouse position at document level and distributes to subscribers
6
12
  * Reduces event processing overhead when multiple AtomixGlass instances are present
7
13
  */
8
14
  class GlobalMouseTracker {
9
- private listeners = new Set<(pos: MousePosition) => void>();
15
+ private listeners = new Set<MouseTrackerListener>();
10
16
  private position: MousePosition = { x: 0, y: 0 };
11
17
  private rafId: number | null = null;
12
18
  private lastEvent: MouseEvent | null = null;
@@ -15,10 +21,17 @@ class GlobalMouseTracker {
15
21
  /**
16
22
  * Subscribe to mouse position updates
17
23
  * @param callback Function to call when mouse position changes
24
+ * @param element Optional element for distance-based attenuation
25
+ * @param maxDistance Optional maximum distance for full effect
18
26
  * @returns Unsubscribe function
19
27
  */
20
- subscribe(callback: (pos: MousePosition) => void): () => void {
21
- this.listeners.add(callback);
28
+ subscribe(
29
+ callback: (pos: MousePosition) => void,
30
+ element?: HTMLElement,
31
+ maxDistance?: number
32
+ ): () => void {
33
+ const listener: MouseTrackerListener = { callback, element, maxDistance };
34
+ this.listeners.add(listener);
22
35
 
23
36
  // Start tracking if this is the first subscriber
24
37
  if (this.listeners.size === 1) {
@@ -38,7 +51,13 @@ class GlobalMouseTracker {
38
51
  * Unsubscribe from mouse position updates
39
52
  */
40
53
  private unsubscribe(callback: (pos: MousePosition) => void): void {
41
- this.listeners.delete(callback);
54
+ // Find and remove the listener with the given callback
55
+ for (const listener of this.listeners) {
56
+ if (listener.callback === callback) {
57
+ this.listeners.delete(listener);
58
+ break;
59
+ }
60
+ }
42
61
 
43
62
  // Stop tracking if no more subscribers
44
63
  if (this.listeners.size === 0) {
@@ -80,6 +99,15 @@ class GlobalMouseTracker {
80
99
  this.lastEvent = null;
81
100
  }
82
101
 
102
+ /**
103
+ * Calculate distance between two points
104
+ */
105
+ private calculateDistance(point1: MousePosition, point2: MousePosition): number {
106
+ const dx = point1.x - point2.x;
107
+ const dy = point1.y - point2.y;
108
+ return Math.sqrt(dx * dx + dy * dy);
109
+ }
110
+
83
111
  /**
84
112
  * Handle mouse move event
85
113
  */
@@ -96,9 +124,37 @@ class GlobalMouseTracker {
96
124
  };
97
125
 
98
126
  // Notify all subscribers
99
- this.listeners.forEach(callback => {
127
+ this.listeners.forEach(listener => {
100
128
  try {
101
- callback(this.position);
129
+ // If the listener has an element, calculate distance-based attenuation
130
+ if (listener.element) {
131
+ const elementRect = listener.element.getBoundingClientRect();
132
+ const elementCenter = {
133
+ x: elementRect.left + elementRect.width / 2,
134
+ y: elementRect.top + elementRect.height / 2,
135
+ };
136
+
137
+ const distance = this.calculateDistance(this.position, elementCenter);
138
+ const maxDistance = listener.maxDistance || 300; // Default to 300px
139
+
140
+ // Calculate attenuation factor (0 to 1)
141
+ const attenuation = Math.max(0, 1 - (distance / maxDistance));
142
+
143
+ // Calculate relative mouse position for this specific element
144
+ const relativeX = (this.position.x - elementCenter.x) / elementRect.width * 100;
145
+ const relativeY = (this.position.y - elementCenter.y) / elementRect.height * 100;
146
+
147
+ // Apply attenuation to the relative position
148
+ const attenuatedRelativePosition = {
149
+ x: relativeX * attenuation,
150
+ y: relativeY * attenuation,
151
+ };
152
+
153
+ listener.callback(attenuatedRelativePosition);
154
+ } else {
155
+ // Send original position for listeners without distance-based attenuation
156
+ listener.callback(this.position);
157
+ }
102
158
  } catch (error) {
103
159
  console.error('GlobalMouseTracker: Error in subscriber callback', error);
104
160
  }
@@ -158,6 +158,7 @@ interface UseAtomixGlassOptions extends Omit<AtomixGlassProps, 'children'> {
158
158
  wrapperRef?: React.RefObject<HTMLDivElement | null>;
159
159
  children?: React.ReactNode;
160
160
  isFixedOrSticky?: boolean;
161
+ priority?: number; // Priority for z-index ordering
161
162
  // Phase 1: Time-Based Animation System
162
163
  withLiquidBlur?: boolean;
163
164
  animationQuality?: 'low' | 'medium' | 'high';
@@ -226,7 +227,7 @@ export function useAtomixGlass({
226
227
  reducedMotion = false,
227
228
  highContrast = false,
228
229
  withoutEffects = false,
229
- elasticity = 0.05,
230
+ elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY,
230
231
  onClick,
231
232
  debugBorderRadius = false,
232
233
  debugOverLight = false,
@@ -236,6 +237,7 @@ export function useAtomixGlass({
236
237
  padding,
237
238
  withLiquidBlur,
238
239
  isFixedOrSticky = false,
240
+ priority = 1, // Default priority
239
241
  // Phase 1: Animation System Props
240
242
  withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION,
241
243
  animationSpeed = ATOMIX_GLASS.DEFAULTS.ANIMATION_SPEED,
@@ -965,7 +967,7 @@ export function useAtomixGlass({
965
967
  return undefined;
966
968
  }
967
969
 
968
- const unsubscribe = globalMouseTracker.subscribe(handleGlobalMousePosition);
970
+ const unsubscribe = globalMouseTracker.subscribe(handleGlobalMousePosition, glassRef.current || undefined, 300); // 300px max distance for full effect
969
971
 
970
972
  // Initial start
971
973
  startLerpLoop();
@@ -1689,6 +1689,10 @@ export const ATOMIX_GLASS = {
1689
1689
  MIN_BLUR: 0.1,
1690
1690
  MOUSE_INFLUENCE_DIVISOR: 100,
1691
1691
  EDGE_FADE_PIXELS: 2,
1692
+ // Elasticity physics constants
1693
+ ELASTICITY_TRANSLATION_FACTOR: 0.1,
1694
+ ELASTICITY_DISTANCE_THRESHOLD: 200,
1695
+ ELASTICITY_COMPRESSION_FACTOR: 0.3,
1692
1696
  // Note: This default must match the SCSS variable --atomix-radius-md
1693
1697
  // @see src/styles/01-settings/_settings.global.scss
1694
1698
  DEFAULT_CORNER_RADIUS: 16,
@@ -321,6 +321,16 @@ export interface AtomixGlassProps extends React.HTMLAttributes<HTMLDivElement> {
321
321
  * @default false
322
322
  */
323
323
  disableResponsiveBreakpoints?: boolean;
324
+
325
+ /**
326
+ * Priority level for rendering and performance scheduling
327
+ *
328
+ * Controls the rendering priority of the glass effect, allowing for performance
329
+ * optimization in complex scenes. Higher priority elements are rendered first.
330
+ *
331
+ * @default undefined
332
+ */
333
+ priority?: number;
324
334
  }
325
335
 
326
336
  /**
@@ -1207,10 +1217,6 @@ export interface SpinnerProps extends BaseComponentProps {
1207
1217
  glass?: AtomixGlassProps | boolean;
1208
1218
  }
1209
1219
 
1210
- /**
1211
- * Icon size options
1212
- */
1213
- export type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
1214
1220
 
1215
1221
  /**
1216
1222
  * Icon weight/style options
@@ -252,6 +252,8 @@
252
252
  &--glass {
253
253
  position: relative;
254
254
  background-color: transparent;
255
+ display: flex;
256
+ height: 100%;
255
257
  @include dynamic-background(var(--#{$prefix}navbar-bg), $enable-transparency: true);
256
258
  }
257
259