@shohojdhara/atomix 0.6.2 → 0.6.3

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.
Files changed (62) hide show
  1. package/README.md +510 -106
  2. package/dist/atomix.css +28 -24
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +5 -5
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/atomix.umd.js +1 -1
  7. package/dist/atomix.umd.js.map +1 -1
  8. package/dist/atomix.umd.min.js +1 -1
  9. package/dist/charts.d.ts +2 -2
  10. package/dist/charts.js +251 -131
  11. package/dist/charts.js.map +1 -1
  12. package/dist/core.d.ts +5 -39
  13. package/dist/core.js +254 -137
  14. package/dist/core.js.map +1 -1
  15. package/dist/forms.d.ts +2 -1
  16. package/dist/forms.js +342 -177
  17. package/dist/forms.js.map +1 -1
  18. package/dist/heavy.js +254 -135
  19. package/dist/heavy.js.map +1 -1
  20. package/dist/index.d.ts +141 -159
  21. package/dist/index.esm.js +348 -195
  22. package/dist/index.esm.js.map +1 -1
  23. package/dist/index.js +348 -195
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.min.js +1 -1
  26. package/dist/index.min.js.map +1 -1
  27. package/dist/theme.d.ts +14 -6
  28. package/dist/theme.js +2 -9
  29. package/dist/theme.js.map +1 -1
  30. package/package.json +26 -26
  31. package/src/components/AtomixGlass/AtomixGlass.tsx +1 -1
  32. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +8 -1
  33. package/src/components/AtomixGlass/glass-utils.ts +29 -0
  34. package/src/components/AtomixGlass/stories/Playground.stories.tsx +32 -1
  35. package/src/components/Button/Button.stories.tsx +1 -1
  36. package/src/components/Button/Button.tsx +6 -5
  37. package/src/components/Card/Card.tsx +2 -2
  38. package/src/components/Dropdown/Dropdown.tsx +1 -0
  39. package/src/components/EdgePanel/EdgePanel.tsx +1 -3
  40. package/src/components/Form/Select.test.tsx +75 -0
  41. package/src/components/Form/Select.tsx +348 -252
  42. package/src/components/Form/SelectOption.tsx +16 -10
  43. package/src/components/index.ts +1 -1
  44. package/src/layouts/CssGrid/index.ts +1 -0
  45. package/src/lib/composables/useAtomixGlass.ts +238 -138
  46. package/src/lib/composables/useAtomixGlassStyles.ts +201 -149
  47. package/src/lib/constants/components.ts +50 -35
  48. package/src/lib/theme/config/configLoader.ts +1 -1
  49. package/src/lib/theme/test/testTheme.ts +2 -2
  50. package/src/lib/theme/utils/themeUtils.ts +98 -110
  51. package/src/lib/types/components.ts +21 -63
  52. package/src/styles/01-settings/_settings.spacing.scss +6 -1
  53. package/src/styles/03-generic/_generic.reset.scss +1 -1
  54. package/src/styles/06-components/_components.atomix-glass.scss +20 -29
  55. package/src/styles/06-components/_components.data-table.scss +5 -4
  56. package/src/styles/06-components/_components.dynamic-background.scss +9 -8
  57. package/src/styles/06-components/_components.footer.scss +8 -7
  58. package/src/styles/06-components/_components.hero.scss +2 -2
  59. package/src/styles/06-components/_components.messages.scss +16 -16
  60. package/src/styles/06-components/_components.select.scss +15 -2
  61. package/src/styles/06-components/_components.upload.scss +3 -3
  62. package/CHANGELOG.md +0 -165
package/dist/heavy.js CHANGED
@@ -65,12 +65,23 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
65
65
  },
66
66
  DEFAULTS: {
67
67
  DISPLACEMENT_SCALE: 70,
68
- BLUR_AMOUNT: 0,
69
- SATURATION: 140,
70
- ABERRATION_INTENSITY: 2,
68
+ get BLUR_AMOUNT() {
69
+ return .15 * this.DISPLACEMENT_SCALE;
70
+ // Dynamically computed based on displacement
71
+ },
72
+ get SATURATION() {
73
+ return 100 + .5 * this.DISPLACEMENT_SCALE;
74
+ // Saturate relative to intensity
75
+ },
76
+ get ABERRATION_INTENSITY() {
77
+ return .03 * this.DISPLACEMENT_SCALE;
78
+ // Scale aberration with displacement
79
+ },
71
80
  ELASTICITY: .15,
72
- CORNER_RADIUS: 20,
73
- // Default border-radius matching design system
81
+ get CORNER_RADIUS() {
82
+ return 16;
83
+ // Use 16 to match SCSS design system (was 20)
84
+ },
74
85
  PADDING: "0",
75
86
  MODE: "standard",
76
87
  OVER_LIGHT: !1,
@@ -96,6 +107,11 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
96
107
  ELASTICITY_TRANSLATION_FACTOR: .1,
97
108
  ELASTICITY_DISTANCE_THRESHOLD: 200,
98
109
  ELASTICITY_COMPRESSION_FACTOR: .3,
110
+ ELASTICITY_STIFFNESS: .1,
111
+ ELASTICITY_DAMPING: .76,
112
+ ELASTICITY_VELOCITY_FACTOR: .65,
113
+ ELASTICITY_STRETCH_RATIO: .45,
114
+ ELASTICITY_MAGNIFICATION_BASE: 1.02,
99
115
  // Note: This default must match the SCSS variable --atomix-radius-md
100
116
  // @see src/styles/01-settings/_settings.global.scss
101
117
  DEFAULT_CORNER_RADIUS: 16,
@@ -112,84 +128,126 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
112
128
  // Base angle for border gradients (degrees)
113
129
  ANGLE_MULTIPLIER: 1.2,
114
130
  // Multiplier for mouse influence on angle
131
+ VELOCITY_ANGLE_MULTIPLIER: 2.5,
132
+ // How much velocity affects gradient rotation
133
+ CHROMATIC_OFFSET: 1.5,
134
+ // Degree offset for chromatic rim layers
115
135
  BORDER_STOP_1: {
116
136
  MIN: 10,
117
137
  // Minimum percentage for border stop 1
118
138
  BASE: 33,
119
139
  // Base percentage for border stop 1
120
- MULTIPLIER: .3
140
+ get MULTIPLIER() {
141
+ return .009 * this.BASE;
142
+ }
121
143
  },
122
144
  BORDER_STOP_2: {
123
145
  MAX: 90,
124
146
  // Maximum percentage for border stop 2
125
147
  BASE: 66,
126
148
  // Base percentage for border stop 2
127
- MULTIPLIER: .4
149
+ get MULTIPLIER() {
150
+ return .006 * this.BASE;
151
+ }
128
152
  },
129
153
  BORDER_OPACITY: {
130
154
  BASE_1: .12,
131
155
  // Base opacity for border gradient 1
132
- BASE_2: .4,
156
+ get BASE_2() {
157
+ return 3.33 * this.BASE_1;
158
+ },
133
159
  // Base opacity for border gradient 2
134
- BASE_3: .32,
160
+ get BASE_3() {
161
+ return 2.66 * this.BASE_1;
162
+ },
135
163
  // Base opacity for border gradient 3
136
- BASE_4: .6,
164
+ get BASE_4() {
165
+ return 5 * this.BASE_1;
166
+ },
137
167
  // Base opacity for border gradient 4
138
- MULTIPLIER_LOW: .008,
168
+ get MULTIPLIER_LOW() {
169
+ return .066 * this.BASE_1;
170
+ },
139
171
  // Low multiplier for mouse influence on opacity
140
- MULTIPLIER_HIGH: .012
172
+ get MULTIPLIER_HIGH() {
173
+ return .1 * this.BASE_1;
174
+ }
141
175
  },
142
176
  CENTER_POSITION: 50,
143
177
  // Center position percentage (50%)
144
178
  HOVER_POSITION: {
145
179
  DIVISOR_1: 2,
146
180
  // Divisor for hover 1 position calculation
147
- DIVISOR_2: 1.5,
181
+ get DIVISOR_2() {
182
+ return .75 * this.DIVISOR_1;
183
+ },
148
184
  // Divisor for hover 2 position calculation
149
- MULTIPLIER_3: 1
185
+ get MULTIPLIER_3() {
186
+ return .5 * this.DIVISOR_1;
187
+ }
150
188
  },
151
- BASE_LAYER_MULTIPLIER: .5
189
+ get BASE_LAYER_MULTIPLIER() {
190
+ return .5;
191
+ }
152
192
  },
153
193
  // Gradient opacity values for hover effects
154
194
  GRADIENT_OPACITY: {
155
195
  HOVER_1: {
156
196
  BLACK_START: .3,
157
197
  // Start opacity for black hover 1
158
- BLACK_MID: .1,
198
+ get BLACK_MID() {
199
+ return this.BLACK_START / 3;
200
+ },
159
201
  // Mid opacity for black hover 1
160
202
  BLACK_STOP: 30,
161
203
  // Stop percentage for black hover 1
162
- BLACK_END: 60,
204
+ get BLACK_END() {
205
+ return 2 * this.BLACK_STOP;
206
+ },
163
207
  // End percentage for black hover 1
164
208
  WHITE_START: .5,
165
209
  // Start opacity for white hover 1
166
- WHITE_STOP: 50
210
+ get WHITE_STOP() {
211
+ return this.BLACK_END - 10;
212
+ }
167
213
  },
168
214
  HOVER_2: {
169
215
  BLACK_START: .4,
170
216
  // Start opacity for black hover 2
171
- BLACK_MID: .15,
217
+ get BLACK_MID() {
218
+ return .375 * this.BLACK_START;
219
+ },
172
220
  // Mid opacity for black hover 2
173
221
  BLACK_STOP: 40,
174
222
  // Stop percentage for black hover 2
175
- BLACK_END: 80,
223
+ get BLACK_END() {
224
+ return 2 * this.BLACK_STOP;
225
+ },
176
226
  // End percentage for black hover 2
177
227
  WHITE_START: 1,
178
228
  // Start opacity for white hover 2
179
- WHITE_STOP: 80
229
+ get WHITE_STOP() {
230
+ return this.BLACK_END;
231
+ }
180
232
  },
181
233
  HOVER_3: {
182
234
  BLACK_START: .5,
183
235
  // Start opacity for black hover 3
184
- BLACK_MID: .2,
236
+ get BLACK_MID() {
237
+ return .4 * this.BLACK_START;
238
+ },
185
239
  // Mid opacity for black hover 3
186
240
  BLACK_STOP: 50,
187
241
  // Stop percentage for black hover 3
188
- BLACK_END: 100,
242
+ get BLACK_END() {
243
+ return 2 * this.BLACK_STOP;
244
+ },
189
245
  // End percentage for black hover 3
190
246
  WHITE_START: 1,
191
247
  // Start opacity for white hover 3
192
- WHITE_STOP: 100
248
+ get WHITE_STOP() {
249
+ return this.BLACK_END;
250
+ }
193
251
  }
194
252
  },
195
253
  // Base and overlay gradient constants
@@ -198,34 +256,54 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
198
256
  // Gradient angle in degrees
199
257
  BLACK_START_BASE: .15,
200
258
  // Base start opacity for black
201
- BLACK_START_MULTIPLIER: .003,
259
+ get BLACK_START_MULTIPLIER() {
260
+ return .02 * this.BLACK_START_BASE;
261
+ },
202
262
  // Multiplier for mouse X influence on start
203
263
  BLACK_MID_BASE: .1,
204
264
  // Base mid opacity for black
205
- BLACK_MID_MULTIPLIER: .002,
265
+ get BLACK_MID_MULTIPLIER() {
266
+ return .02 * this.BLACK_MID_BASE;
267
+ },
206
268
  // Multiplier for mouse Y influence on mid
207
269
  BLACK_MID_STOP: 50,
208
270
  // Mid stop percentage
209
- BLACK_END_BASE: .18,
271
+ get BLACK_END_BASE() {
272
+ return 1.2 * this.BLACK_START_BASE;
273
+ },
210
274
  // Base end opacity for black
211
- BLACK_END_MULTIPLIER: .004,
275
+ get BLACK_END_MULTIPLIER() {
276
+ return .022 * this.BLACK_END_BASE;
277
+ },
212
278
  // Multiplier for mouse X influence on end
213
- WHITE_OPACITY: .1
279
+ get WHITE_OPACITY() {
280
+ return .666 * this.BLACK_START_BASE;
281
+ }
214
282
  },
215
283
  OVERLAY_GRADIENT: {
216
284
  BLACK_START_BASE: .12,
217
285
  // Base start opacity for black overlay
218
- BLACK_START_MULTIPLIER: .003,
286
+ get BLACK_START_MULTIPLIER() {
287
+ return .025 * this.BLACK_START_BASE;
288
+ },
219
289
  // Multiplier for mouse X influence on start
220
- BLACK_MID: .06,
290
+ get BLACK_MID() {
291
+ return .5 * this.BLACK_START_BASE;
292
+ },
221
293
  // Mid opacity for black overlay
222
294
  BLACK_MID_STOP: 40,
223
295
  // Mid stop percentage
224
- BLACK_END_BASE: .15,
296
+ get BLACK_END_BASE() {
297
+ return 1.25 * this.BLACK_START_BASE;
298
+ },
225
299
  // Base end opacity for black overlay
226
- BLACK_END_MULTIPLIER: .003,
300
+ get BLACK_END_MULTIPLIER() {
301
+ return .02 * this.BLACK_END_BASE;
302
+ },
227
303
  // Multiplier for mouse Y influence on end
228
- WHITE_OPACITY: .05
304
+ get WHITE_OPACITY() {
305
+ return .416 * this.BLACK_START_BASE;
306
+ }
229
307
  },
230
308
  // Overlay highlight constants
231
309
  OVERLAY_HIGHLIGHT: {
@@ -235,9 +313,13 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
235
313
  // Y position percentage
236
314
  WHITE_OPACITY: .4,
237
315
  // White opacity in gradient
238
- STOP: 60,
316
+ get STOP() {
317
+ return 150 * this.WHITE_OPACITY;
318
+ },
239
319
  // Stop percentage
240
- OPACITY_MULTIPLIER: .7
320
+ get OPACITY_MULTIPLIER() {
321
+ return 1.75 * this.WHITE_OPACITY;
322
+ }
241
323
  },
242
324
  // Displacement and aberration multipliers
243
325
  MULTIPLIERS: {
@@ -290,11 +372,7 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
290
372
  }
291
373
  }
292
374
  }
293
- }, {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateDistance = (pos1, pos2) => {
294
- if (!pos1 || !pos2 || "number" != typeof pos1.x || "number" != typeof pos1.y || "number" != typeof pos2.x || "number" != typeof pos2.y) return 0;
295
- const deltaX = pos1.x - pos2.x, deltaY = pos1.y - pos2.y;
296
- return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
297
- }, calculateElementCenter = rect => rect ? {
375
+ }, {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect => rect ? {
298
376
  x: rect.left + rect.width / 2,
299
377
  y: rect.top + rect.height / 2
300
378
  } : {
@@ -366,7 +444,16 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
366
444
  // Silently handle errors
367
445
  }
368
446
  return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
369
- }, lerp$1 = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
447
+ }, smoothstep = t => {
448
+ const clamped = Math.max(0, Math.min(1, t));
449
+ return clamped * clamped * (3 - 2 * clamped);
450
+ }, lerp$1 = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), calculateSpring = (current, target, velocity, stiffness = .1, damping = .8) => {
451
+ const newVelocity = (velocity + (target - current) * stiffness) * damping;
452
+ return {
453
+ value: current + newVelocity,
454
+ velocity: newVelocity
455
+ };
456
+ }, getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
370
457
  switch (mode) {
371
458
  case "standard":
372
459
  return displacementMap;
@@ -755,6 +842,9 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
755
842
  }), jsx("div", {
756
843
  ref: contentRef,
757
844
  className: ATOMIX_GLASS.CONTENT_CLASS,
845
+ style: {
846
+ transform: "var(--atomix-glass-child-parallax, none)"
847
+ },
758
848
  children: children
759
849
  }) ]
760
850
  })
@@ -879,51 +969,26 @@ class {
879
969
  }
880
970
  }, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
881
971
  if (!wrapperElement && !containerElement) return;
882
- const {mouseOffset: mouseOffset, globalMousePosition: globalMousePosition, glassSize: glassSize, isHovered: isHovered, isActive: isActive, isOverLight: isOverLight, baseOverLightConfig: baseOverLightConfig, effectiveBorderRadius: effectiveBorderRadius, effectiveWithoutEffects: effectiveWithoutEffects, effectiveReducedMotion: effectiveReducedMotion, elasticity: elasticity, directionalScale: directionalScale, onClick: onClick, withLiquidBlur: withLiquidBlur, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, isFixedOrSticky: isFixedOrSticky = !1} = params, mouseInfluence = calculateMouseInfluence(mouseOffset), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1, overLightConfig = {
972
+ if (!validateGlassSize(params.glassSize)) return;
973
+ const {mouseOffset: mouseOffset, globalMousePosition: globalMousePosition, glassSize: glassSize, isHovered: isHovered, isActive: isActive, isOverLight: isOverLight, baseOverLightConfig: baseOverLightConfig, effectiveBorderRadius: effectiveBorderRadius, effectiveWithoutEffects: effectiveWithoutEffects, effectiveReducedMotion: effectiveReducedMotion, elasticity: elasticity, elasticTranslation: elasticTranslation, elasticVelocity: elasticVelocity, mouseVelocity: mouseVelocity, directionalScale: directionalScale, scaleBase: scaleBase, onClick: onClick, withLiquidBlur: withLiquidBlur, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, isFixedOrSticky: isFixedOrSticky = !1} = params, mouseInfluence = calculateMouseInfluence(mouseOffset), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1, overLightConfig = {
883
974
  opacity: baseOverLightConfig.opacity * hoverIntensity * activeIntensity,
884
975
  contrast: Math.min(1.6, baseOverLightConfig.contrast + .1 * mouseInfluence),
885
976
  brightness: Math.min(1.1, baseOverLightConfig.brightness + .05 * mouseInfluence),
886
977
  shadowIntensity: Math.min(1.2, Math.max(.5, baseOverLightConfig.shadowIntensity + .2 * mouseInfluence)),
887
978
  borderOpacity: Math.min(1, Math.max(.3, baseOverLightConfig.borderOpacity + .1 * mouseInfluence)),
888
979
  saturationBoost: baseOverLightConfig.saturationBoost
889
- };
890
- // Calculate mouse influence
891
- let computedDirectionalScale = directionalScale, elasticTranslation = {
980
+ }, scaleX = directionalScale.x * scaleBase, scaleY = directionalScale.y * scaleBase, transformStyle = effectiveWithoutEffects ? `scale(${scaleBase})` : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) scaleX(${scaleX}) scaleY(${scaleY})`, stretchMagnitude = ((pos1, pos2) => {
981
+ if (!pos1 || !pos2 || "number" != typeof pos1.x || "number" != typeof pos1.y || "number" != typeof pos2.x || "number" != typeof pos2.y) return 0;
982
+ const deltaX = pos1.x - pos2.x, deltaY = pos1.y - pos2.y;
983
+ return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
984
+ })({
892
985
  x: 0,
893
986
  y: 0
894
- };
895
- // Calculate elastic translation and directional scale
896
- if (!effectiveWithoutEffects && wrapperElement) {
897
- const rect = wrapperElement.getBoundingClientRect(), center = calculateElementCenter(rect);
898
- // Mouse presence and edge distance logic
899
- if (globalMousePosition.x && globalMousePosition.y && validateGlassSize(glassSize)) {
900
- const deltaX = globalMousePosition.x - center.x, deltaY = globalMousePosition.y - center.y, edgeDistanceX = Math.max(0, Math.abs(deltaX) - glassSize.width / 2), edgeDistanceY = Math.max(0, Math.abs(deltaY) - glassSize.height / 2), edgeDistance = calculateDistance({
901
- x: edgeDistanceX,
902
- y: edgeDistanceY
903
- }, {
904
- x: 0,
905
- y: 0
906
- }), rawT = edgeDistance > ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE ? 0 : 1 - edgeDistance / ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE, fadeInFactor = (t => {
907
- const clamped = Math.max(0, Math.min(1, t));
908
- return clamped * clamped * (3 - 2 * clamped);
909
- })(rawT);
910
- // Directional scale
911
- if (elasticTranslation = {
912
- x: deltaX * elasticity * .1 * fadeInFactor,
913
- y: deltaY * elasticity * .1 * fadeInFactor
914
- }, !isOverLight && edgeDistance <= ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE) {
915
- const centerDistance = calculateDistance(globalMousePosition, center);
916
- if (centerDistance > 0) {
917
- const normalizedX = deltaX / centerDistance, normalizedY = deltaY / centerDistance, stretchIntensity = Math.min(centerDistance / 300, 1) * elasticity * rawT, scaleX = 1 + Math.abs(normalizedX) * stretchIntensity * .3 - Math.abs(normalizedY) * stretchIntensity * .15, scaleY = 1 + Math.abs(normalizedY) * stretchIntensity * .3 - Math.abs(normalizedX) * stretchIntensity * .15, softScaleX = 1 - softClamp(Math.max(0, 1 - scaleX), .2), softScaleY = 1 - softClamp(Math.max(0, 1 - scaleY), .2);
918
- computedDirectionalScale = `scaleX(${Math.max(.85, softScaleX)}) scaleY(${Math.max(.85, softScaleY)})`;
919
- }
920
- }
921
- }
922
- }
923
- const transformStyle = effectiveWithoutEffects ? isActive && Boolean(onClick) ? "scale(0.98)" : "scale(1)" : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) ${isActive && Boolean(onClick) ? "scale(0.96)" : computedDirectionalScale}`;
924
- // Update Wrapper Styles (glassVars)
925
- if (wrapperElement) {
926
- const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, borderGradientAngle = GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER, borderStop1 = Math.max(GRADIENT.BORDER_STOP_1.MIN, GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER), borderStop2 = Math.min(GRADIENT.BORDER_STOP_2.MAX, GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER), borderOpacities = [ GRADIENT.BORDER_OPACITY.BASE_1 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, GRADIENT.BORDER_OPACITY.BASE_2 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH, GRADIENT.BORDER_OPACITY.BASE_3 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, GRADIENT.BORDER_OPACITY.BASE_4 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH ], configBorderOpacity = overLightConfig.borderOpacity, whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, hoverPositions = {
987
+ }, elasticTranslation), tensionFactor = smoothstep(stretchMagnitude / 80), lightingContrast = Math.min(1.8, overLightConfig.contrast + .2 * tensionFactor), lightingBrightness = Math.min(1.2, overLightConfig.brightness + .1 * tensionFactor);
988
+ // Calculate mouse influence
989
+ // Update Wrapper Styles (glassVars)
990
+ if (wrapperElement) {
991
+ const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, velocityRotation = (mouseVelocity.x + elasticVelocity.x) * (GRADIENT.VELOCITY_ANGLE_MULTIPLIER || 2.5), borderGradientAngle = GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER + velocityRotation, chromaticOffset = GRADIENT.CHROMATIC_OFFSET || 1.5, angleR = borderGradientAngle - chromaticOffset, angleB = borderGradientAngle + chromaticOffset, borderStop1 = Math.max(GRADIENT.BORDER_STOP_1.MIN, GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER), borderStop2 = Math.min(GRADIENT.BORDER_STOP_2.MAX, GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER), tensionGlow = 1 + .5 * tensionFactor, borderOpacities = [ (GRADIENT.BORDER_OPACITY.BASE_1 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW) * tensionGlow, (GRADIENT.BORDER_OPACITY.BASE_2 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH) * tensionGlow, (GRADIENT.BORDER_OPACITY.BASE_3 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW) * tensionGlow, (GRADIENT.BORDER_OPACITY.BASE_4 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH) * tensionGlow ], configBorderOpacity = overLightConfig.borderOpacity, whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, hoverPositions = {
927
992
  hover1: {
928
993
  x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
929
994
  y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1
@@ -946,10 +1011,16 @@ class {
946
1011
  base: isOverLight ? overLightConfig.opacity : 0,
947
1012
  over: isOverLight ? 1.1 * overLightConfig.opacity : 0
948
1013
  }, style = wrapperElement.style;
949
- style.setProperty("--atomix-glass-transform", transformStyle || "none"),
950
- // Gradients
951
- style.setProperty("--atomix-glass-border-gradient-1", `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[0] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[1] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`),
952
- style.setProperty("--atomix-glass-border-gradient-2", `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[2] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[3] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`),
1014
+ style.setProperty("--atomix-glass-transform", transformStyle || "none");
1015
+ // Parallax for content (liquid refraction feel)
1016
+ const parallaxFactor = .38 + .12 * tensionFactor;
1017
+ style.setProperty("--atomix-glass-child-parallax", `translate(${elasticTranslation.x * -parallaxFactor}px, ${elasticTranslation.y * -parallaxFactor}px)`),
1018
+ style.setProperty("--atomix-glass-contrast", lightingContrast.toString()), style.setProperty("--atomix-glass-brightness", lightingBrightness.toString()),
1019
+ // ── Chromatic Rim Lighting ──────────────────────────────────────
1020
+ // Layer 1: Core White/Blue highlight
1021
+ style.setProperty("--atomix-glass-border-gradient-1", `linear-gradient(${angleB}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[0] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[1] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`),
1022
+ // Layer 2: Subtle Red/Warm highlight (offset angle)
1023
+ style.setProperty("--atomix-glass-border-gradient-2", `linear-gradient(${angleR}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[2] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[3] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`),
953
1024
  // Hover gradients
954
1025
  style.setProperty("--atomix-glass-hover-1-gradient", isOverLight ? `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}%)` : `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}%)`),
955
1026
  style.setProperty("--atomix-glass-hover-2-gradient", isOverLight ? `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}%)` : `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}%)`),
@@ -977,7 +1048,7 @@ class {
977
1048
  flowBlur: blurAmount * FLOW_BLUR_MULTIPLIER
978
1049
  };
979
1050
  if (withLiquidBlur && rect) {
980
- const mouseInfluence = calculateMouseInfluence(mouseOffset), maxBlur = blurAmount * MAX_BLUR_RELATIVE, baseBlur = Math.min(maxBlur, blurAmount + mouseInfluence * blurAmount * MOUSE_INFLUENCE_BLUR_FACTOR), edgeIntensity = mouseInfluence * EDGE_INTENSITY_MOUSE_FACTOR, edgeBlur = Math.min(maxBlur, baseBlur * (.8 + .4 * edgeIntensity)), centerIntensity = mouseInfluence * CENTER_INTENSITY_MOUSE_FACTOR, centerBlur = Math.min(maxBlur, baseBlur * (.3 + .3 * centerIntensity)), flowBlur = Math.min(maxBlur, baseBlur * FLOW_BLUR_MULTIPLIER);
1051
+ const mouseInfluence = calculateMouseInfluence(mouseOffset), maxBlur = blurAmount * MAX_BLUR_RELATIVE, baseBlur = softClamp(blurAmount + mouseInfluence * blurAmount * MOUSE_INFLUENCE_BLUR_FACTOR, maxBlur), edgeBlur = softClamp(baseBlur * (.8 + mouseInfluence * EDGE_INTENSITY_MOUSE_FACTOR * .4), maxBlur), centerBlur = softClamp(baseBlur * (.3 + mouseInfluence * CENTER_INTENSITY_MOUSE_FACTOR * .3), maxBlur), flowBlur = softClamp(baseBlur * FLOW_BLUR_MULTIPLIER, maxBlur);
981
1052
  liquidBlur = {
982
1053
  baseBlur: clampBlur(baseBlur),
983
1054
  edgeBlur: clampBlur(edgeBlur),
@@ -986,9 +1057,10 @@ class {
986
1057
  };
987
1058
  }
988
1059
  // Backdrop filter
989
- let backdropFilterString = `blur(${blurAmount}px) saturate(${saturation}%) contrast(1.05) brightness(1.05)`;
990
- const dynamicSaturation = saturation + 20 * (liquidBlur.baseBlur || 0), area = rect ? rect.width * rect.height : 0;
991
- backdropFilterString = !withLiquidBlur || effectiveReducedMotion || effectiveWithoutEffects || area > 18e4 ? `blur(${clampBlur(Math.max(liquidBlur.baseBlur, .8 * liquidBlur.edgeBlur, 1.1 * liquidBlur.centerBlur, .9 * liquidBlur.flowBlur))}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig.contrast}) brightness(${overLightConfig.brightness})` : `blur(${clampBlur(.4 * liquidBlur.baseBlur + .25 * liquidBlur.edgeBlur + .15 * liquidBlur.centerBlur + .2 * liquidBlur.flowBlur)}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig.contrast}) brightness(${overLightConfig.brightness})`;
1060
+ const dynamicSaturation = saturation + 40 * tensionFactor + 15 * (liquidBlur.baseBlur || 0);
1061
+ let backdropFilterString = "";
1062
+ const area = rect ? rect.width * rect.height : 0;
1063
+ backdropFilterString = !withLiquidBlur || effectiveReducedMotion || effectiveWithoutEffects || area > 18e4 ? `blur(${clampBlur(Math.max(liquidBlur.baseBlur, .8 * liquidBlur.edgeBlur, 1.1 * liquidBlur.centerBlur, .9 * liquidBlur.flowBlur))}px) saturate(${Math.min(dynamicSaturation, 250)}%) contrast(${lightingContrast}) brightness(${lightingBrightness})` : `blur(${clampBlur(.4 * liquidBlur.baseBlur + .25 * liquidBlur.edgeBlur + .15 * liquidBlur.centerBlur + .2 * liquidBlur.flowBlur)}px) saturate(${Math.min(dynamicSaturation, 250)}%) contrast(${lightingContrast}) brightness(${lightingBrightness})`;
992
1064
  // Container variables
993
1065
  const style = containerElement.style;
994
1066
  style.setProperty("--atomix-glass-container-padding", padding), style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
@@ -1167,7 +1239,24 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
1167
1239
  }), targetGlobalMousePositionRef = useRef({
1168
1240
  x: 0,
1169
1241
  y: 0
1170
- }), lerpRafRef = useRef(null), lerpActiveRef = useRef(!1), [dynamicBorderRadius, setDynamicCornerRadius] = useState(CONSTANTS.DEFAULT_CORNER_RADIUS), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1), animationFrameIdRef = useRef(null), animationStartTimeRef = useRef(0), elapsedTimeRef = useRef(0), shaderTimeRef = useRef(0), fbmConfig = useMemo((() => {
1242
+ }), lerpRafRef = useRef(null), lerpActiveRef = useRef(!1), [dynamicBorderRadius, setDynamicCornerRadius] = useState(CONSTANTS.DEFAULT_CORNER_RADIUS), elasticTranslationRef = useRef({
1243
+ x: 0,
1244
+ y: 0
1245
+ }), elasticVelocityRef = useRef({
1246
+ x: 0,
1247
+ y: 0
1248
+ }), directionalScaleRef = useRef({
1249
+ x: 1,
1250
+ y: 1
1251
+ }), scaleVelocityRef = useRef({
1252
+ x: 0,
1253
+ y: 0
1254
+ });
1255
+ useRef(0);
1256
+ const mouseVelocityRef = useRef({
1257
+ x: 0,
1258
+ y: 0
1259
+ }), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1), animationFrameIdRef = useRef(null), animationStartTimeRef = useRef(0), elapsedTimeRef = useRef(0), shaderTimeRef = useRef(0), fbmConfig = useMemo((() => {
1171
1260
  // If quality preset is provided, use it as base
1172
1261
  const preset = (quality = distortionQuality, ATOMIX_GLASS.CONSTANTS.DISTORTION_QUALITY_PRESETS[quality]);
1173
1262
  // Override with custom values if provided
@@ -1452,57 +1541,85 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
1452
1541
  return "undefined" == typeof process || process.env, finalConfig;
1453
1542
  }
1454
1543
  return "undefined" == typeof process || process.env, baseConfig;
1455
- }), [ overLight, getEffectiveOverLight, isHovered, isActive, validateConfigValue, debugOverLight ]), transformStyle = useMemo((() => effectiveWithoutEffects || isActive && Boolean(onClick) ? "scale(0.98)" : "scale(1)"), [ effectiveWithoutEffects, isActive, onClick ]), updateRectRef = useRef(null), stopLerpLoop = useCallback((() => {
1544
+ }), [ overLight, getEffectiveOverLight, isHovered, isActive, validateConfigValue, debugOverLight ]), transformStyle = useMemo((() => effectiveWithoutEffects || isActive && Boolean(onClick) ? "scale(0.99)" : "scale(1)"), [ effectiveWithoutEffects, isActive, onClick ]), updateRectRef = useRef(null), stopLerpLoop = useCallback((() => {
1456
1545
  lerpActiveRef.current = !1, null !== lerpRafRef.current && (cancelAnimationFrame(lerpRafRef.current),
1457
1546
  lerpRafRef.current = null);
1458
1547
  }), []), startLerpLoop = useCallback((() => {
1459
1548
  if (lerpActiveRef.current) return;
1460
- lerpActiveRef.current = !0;
1461
- const LERP_T = CONSTANTS.LERP_FACTOR, tick = () => {
1549
+ lerpActiveRef.current = !0, CONSTANTS.LERP_FACTOR;
1550
+ // 0.08 lower = more viscous
1551
+ const tick = () => {
1462
1552
  if (!lerpActiveRef.current) return;
1463
1553
  if (!glassRef.current) return void (lerpActiveRef.current = !1);
1464
- const cur = internalMouseOffsetRef.current, tgt = targetMouseOffsetRef.current, dx = tgt.x - cur.x, dy = tgt.y - cur.y;
1465
- // If we're close enough, snap and park
1466
- if (Math.abs(dx) < .01 && Math.abs(dy) < .01) return internalMouseOffsetRef.current = {
1467
- ...tgt
1468
- }, internalGlobalMousePositionRef.current = {
1469
- ...targetGlobalMousePositionRef.current
1470
- },
1471
- // Final update and stop
1472
- updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
1473
- mouseOffset: internalMouseOffsetRef.current,
1474
- globalMousePosition: internalGlobalMousePositionRef.current,
1475
- glassSize: glassSize,
1476
- isHovered: isHovered,
1477
- isActive: isActive,
1478
- isOverLight: overLightConfig.isOverLight,
1479
- baseOverLightConfig: overLightConfig,
1480
- effectiveBorderRadius: effectiveBorderRadius,
1481
- effectiveWithoutEffects: effectiveWithoutEffects,
1482
- effectiveReducedMotion: effectiveReducedMotion,
1483
- elasticity: elasticity,
1484
- directionalScale: isActive && Boolean(onClick) ? "scale(0.96)" : "scale(1)",
1485
- onClick: onClick,
1486
- withLiquidBlur: withLiquidBlur,
1487
- blurAmount: blurAmount,
1488
- saturation: saturation,
1489
- padding: padding,
1490
- isFixedOrSticky: isFixedOrSticky
1491
- }), void stopLerpLoop();
1492
- // Smooth step
1493
- internalMouseOffsetRef.current = {
1494
- x: lerp$1(cur.x, tgt.x, LERP_T),
1495
- y: lerp$1(cur.y, tgt.y, LERP_T)
1554
+ const cur = internalMouseOffsetRef.current, tgt = targetMouseOffsetRef.current, springX = calculateSpring(cur.x, tgt.x, mouseVelocityRef.current.x, CONSTANTS.LERP_FACTOR, CONSTANTS.ELASTICITY_DAMPING), springY = calculateSpring(cur.y, tgt.y, mouseVelocityRef.current.y, CONSTANTS.LERP_FACTOR, CONSTANTS.ELASTICITY_DAMPING);
1555
+ internalMouseOffsetRef.current = {
1556
+ x: springX.value,
1557
+ y: springY.value
1558
+ }, mouseVelocityRef.current = {
1559
+ x: springX.velocity,
1560
+ y: springY.velocity
1496
1561
  };
1497
1562
  const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
1498
1563
  internalGlobalMousePositionRef.current = {
1499
- x: lerp$1(curG.x, tgtG.x, LERP_T),
1500
- y: lerp$1(curG.y, tgtG.y, LERP_T)
1564
+ x: lerp$1(curG.x, tgtG.x, CONSTANTS.LERP_FACTOR),
1565
+ y: lerp$1(curG.y, tgtG.y, CONSTANTS.LERP_FACTOR)
1566
+ };
1567
+ // ── Calculate Elastic Physics ─────────────────────────────────────
1568
+ let targetElasticTranslation = {
1569
+ x: 0,
1570
+ y: 0
1571
+ }, targetScale = {
1572
+ x: 1,
1573
+ y: 1
1574
+ };
1575
+ if (!effectiveWithoutEffects && glassRef.current) {
1576
+ const rect = cachedRectRef.current || glassRef.current.getBoundingClientRect(), center = calculateElementCenter(rect), globalPos = internalGlobalMousePositionRef.current;
1577
+ if (globalPos.x && globalPos.y) {
1578
+ const deltaX = globalPos.x - center.x, deltaY = globalPos.y - center.y, edgeDistanceX = Math.max(0, Math.abs(deltaX) - rect.width / 2), edgeDistanceY = Math.max(0, Math.abs(deltaY) - rect.height / 2), edgeDistance = Math.sqrt(edgeDistanceX * edgeDistanceX + edgeDistanceY * edgeDistanceY), activationZone = CONSTANTS.ACTIVATION_ZONE, rawT = edgeDistance > activationZone ? 0 : 1 - edgeDistance / activationZone, fadeInFactor = smoothstep(rawT);
1579
+ // Scale stretch logic (liquid surface tension)
1580
+ if (targetElasticTranslation = {
1581
+ x: deltaX * elasticity * CONSTANTS.ELASTICITY_TRANSLATION_FACTOR * fadeInFactor,
1582
+ y: deltaY * elasticity * CONSTANTS.ELASTICITY_TRANSLATION_FACTOR * fadeInFactor
1583
+ }, edgeDistance <= activationZone) {
1584
+ const centerDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
1585
+ if (centerDistance > 0) {
1586
+ const nx = deltaX / centerDistance, ny = deltaY / centerDistance, stretchIntensity = Math.min(centerDistance / 350, 1) * elasticity * rawT, mag = 1 + .06 * stretchIntensity;
1587
+ targetScale = {
1588
+ x: mag + Math.abs(nx) * stretchIntensity * CONSTANTS.ELASTICITY_STRETCH_RATIO,
1589
+ y: mag + Math.abs(ny) * stretchIntensity * CONSTANTS.ELASTICITY_STRETCH_RATIO
1590
+ },
1591
+ // Maintain liquid volume by compressing the perpendicular axis
1592
+ targetScale.x -= Math.abs(ny) * stretchIntensity * .15, targetScale.y -= Math.abs(nx) * stretchIntensity * .15;
1593
+ }
1594
+ }
1595
+ }
1596
+ }
1597
+ // Integrate Elastic Translation Spring
1598
+ const springTX = calculateSpring(elasticTranslationRef.current.x, targetElasticTranslation.x, elasticVelocityRef.current.x, CONSTANTS.ELASTICITY_STIFFNESS, CONSTANTS.ELASTICITY_DAMPING), springTY = calculateSpring(elasticTranslationRef.current.y, targetElasticTranslation.y, elasticVelocityRef.current.y, CONSTANTS.ELASTICITY_STIFFNESS, CONSTANTS.ELASTICITY_DAMPING);
1599
+ elasticTranslationRef.current = {
1600
+ x: springTX.value,
1601
+ y: springTY.value
1602
+ }, elasticVelocityRef.current = {
1603
+ x: springTX.velocity,
1604
+ y: springTY.velocity
1605
+ };
1606
+ // Integrate Scale Spring
1607
+ const springSX = calculateSpring(directionalScaleRef.current.x, targetScale.x, scaleVelocityRef.current.x, CONSTANTS.ELASTICITY_STIFFNESS, CONSTANTS.ELASTICITY_DAMPING), springSY = calculateSpring(directionalScaleRef.current.y, targetScale.y, scaleVelocityRef.current.y, CONSTANTS.ELASTICITY_STIFFNESS, CONSTANTS.ELASTICITY_DAMPING);
1608
+ directionalScaleRef.current = {
1609
+ x: springSX.value,
1610
+ y: springSY.value
1611
+ }, scaleVelocityRef.current = {
1612
+ x: springSX.velocity,
1613
+ y: springSY.velocity
1501
1614
  },
1502
1615
  // Imperative style update
1503
1616
  updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
1504
1617
  mouseOffset: internalMouseOffsetRef.current,
1505
1618
  globalMousePosition: internalGlobalMousePositionRef.current,
1619
+ elasticTranslation: elasticTranslationRef.current,
1620
+ elasticVelocity: elasticVelocityRef.current,
1621
+ mouseVelocity: mouseVelocityRef.current,
1622
+ directionalScale: directionalScaleRef.current,
1506
1623
  glassSize: glassSize,
1507
1624
  isHovered: isHovered,
1508
1625
  isActive: isActive,
@@ -1512,17 +1629,16 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
1512
1629
  effectiveWithoutEffects: effectiveWithoutEffects,
1513
1630
  effectiveReducedMotion: effectiveReducedMotion,
1514
1631
  elasticity: elasticity,
1515
- directionalScale: isActive && Boolean(onClick) ? "scale(0.96)" : "scale(1)",
1632
+ scaleBase: isActive && Boolean(onClick) ? .99 : 1,
1516
1633
  onClick: onClick,
1517
1634
  withLiquidBlur: withLiquidBlur,
1518
1635
  blurAmount: blurAmount,
1519
1636
  saturation: saturation,
1520
1637
  padding: padding,
1521
1638
  isFixedOrSticky: isFixedOrSticky
1522
- }), lerpRafRef.current = requestAnimationFrame(tick);
1639
+ }), Math.abs(mouseVelocityRef.current.x) < .001 && Math.abs(mouseVelocityRef.current.y) < .001 && Math.abs(elasticVelocityRef.current.x) < .001 && Math.abs(elasticVelocityRef.current.y) < .001 && Math.abs(scaleVelocityRef.current.x) < .001 && Math.abs(scaleVelocityRef.current.y) < .001 && Math.abs(internalMouseOffsetRef.current.x - targetMouseOffsetRef.current.x) < .001 && Math.abs(internalMouseOffsetRef.current.y - targetMouseOffsetRef.current.y) < .001 ? stopLerpLoop() : lerpRafRef.current = requestAnimationFrame(tick);
1523
1640
  };
1524
- // 0.08 – lower = more viscous
1525
- lerpRafRef.current = requestAnimationFrame(tick);
1641
+ lerpRafRef.current = requestAnimationFrame(tick);
1526
1642
  }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding, isFixedOrSticky, stopLerpLoop ]), handleGlobalMousePosition = useCallback((globalPos => {
1527
1643
  if (externalGlobalMousePosition && externalMouseOffset) return;
1528
1644
  if (effectiveWithoutEffects) return;
@@ -1569,6 +1685,11 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
1569
1685
  updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
1570
1686
  mouseOffset: externalMouseOffset || internalMouseOffsetRef.current,
1571
1687
  globalMousePosition: externalGlobalMousePosition || internalGlobalMousePositionRef.current,
1688
+ elasticTranslation: elasticTranslationRef.current,
1689
+ elasticVelocity: elasticVelocityRef.current,
1690
+ mouseVelocity: mouseVelocityRef.current,
1691
+ directionalScale: directionalScaleRef.current,
1692
+ scaleBase: isActive && Boolean(onClick) ? .96 : 1,
1572
1693
  glassSize: glassSize,
1573
1694
  isHovered: isHovered,
1574
1695
  isActive: isActive,
@@ -1578,7 +1699,6 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
1578
1699
  effectiveWithoutEffects: effectiveWithoutEffects,
1579
1700
  effectiveReducedMotion: effectiveReducedMotion,
1580
1701
  elasticity: elasticity,
1581
- directionalScale: isActive && Boolean(onClick) ? "scale(0.96)" : "scale(1)",
1582
1702
  onClick: onClick,
1583
1703
  withLiquidBlur: withLiquidBlur,
1584
1704
  blurAmount: blurAmount,
@@ -2846,7 +2966,7 @@ const PERFORMANCE_PRESET = {
2846
2966
  "aria-label": ariaLabel,
2847
2967
  "aria-describedby": ariaDescribedBy,
2848
2968
  "aria-disabled": !(!onClick || !effectiveWithoutEffects) || !onClick && void 0,
2849
- "aria-pressed": void 0,
2969
+ "aria-pressed": onClick ? isActive : void 0,
2850
2970
  onKeyDown: onClick ? handleKeyDown : void 0,
2851
2971
  children: [ jsx(AtomixGlassContainer, {
2852
2972
  ref: glassRef,
@@ -4451,10 +4571,10 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
4451
4571
  children: renderSlot(slots?.spinner, {
4452
4572
  className: ThemeNaming.bemClass("btn", "spinner"),
4453
4573
  size: spinnerSize,
4454
- variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
4574
+ variant: "link" === variant || "ghost" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "danger" : variant
4455
4575
  }, jsx(Spinner, {
4456
4576
  size: spinnerSize,
4457
- variant: "link" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "error" : variant
4577
+ variant: "link" === variant || "ghost" === variant || "string" == typeof variant && variant.startsWith("outline-") ? "primary" : "danger" === variant ? "danger" : variant
4458
4578
  }))
4459
4579
  }), iconElement && !loading && jsx("span", {
4460
4580
  className: ThemeNaming.bemClass("btn", "icon"),
@@ -4543,8 +4663,7 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
4543
4663
  const defaultGlassProps = {
4544
4664
  displacementScale: 20,
4545
4665
  blurAmount: 0,
4546
- saturation: 200,
4547
- elasticity: 0
4666
+ saturation: 200
4548
4667
  }, glassProps = !0 === glass ? defaultGlassProps : {
4549
4668
  ...defaultGlassProps,
4550
4669
  ...glass