@shohojdhara/atomix 0.4.5 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/atomix.css +33 -14
  2. package/dist/atomix.css.map +1 -1
  3. package/dist/atomix.min.css +1 -1
  4. package/dist/atomix.min.css.map +1 -1
  5. package/dist/charts.js +183 -184
  6. package/dist/charts.js.map +1 -1
  7. package/dist/core.js +183 -184
  8. package/dist/core.js.map +1 -1
  9. package/dist/forms.js +183 -184
  10. package/dist/forms.js.map +1 -1
  11. package/dist/heavy.js +183 -184
  12. package/dist/heavy.js.map +1 -1
  13. package/dist/index.d.ts +4 -31
  14. package/dist/index.esm.js +192 -283
  15. package/dist/index.esm.js.map +1 -1
  16. package/dist/index.js +194 -285
  17. package/dist/index.js.map +1 -1
  18. package/dist/index.min.js +1 -1
  19. package/dist/index.min.js.map +1 -1
  20. package/package.json +1 -1
  21. package/src/components/AtomixGlass/AtomixGlass.tsx +60 -38
  22. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +6 -35
  23. package/src/components/AtomixGlass/glass-utils.ts +27 -14
  24. package/src/components/AtomixGlass/stories/Overview.stories.tsx +19 -21
  25. package/src/components/AtomixGlass/stories/Playground.stories.tsx +1162 -515
  26. package/src/components/AtomixGlass/stories/shared-components.tsx +11 -3
  27. package/src/components/Navigation/Navbar/Navbar.tsx +13 -5
  28. package/src/lib/composables/index.ts +1 -2
  29. package/src/lib/composables/useAtomixGlass.ts +246 -222
  30. package/src/lib/composables/useAtomixGlassStyles.ts +46 -23
  31. package/src/lib/constants/components.ts +3 -1
  32. package/src/styles/06-components/_components.atomix-glass.scss +45 -20
  33. package/src/lib/composables/atomix-glass/useGlassBackgroundDetection.ts +0 -329
  34. package/src/lib/composables/atomix-glass/useGlassCornerRadius.ts +0 -82
  35. package/src/lib/composables/atomix-glass/useGlassMouseTracking.ts +0 -153
  36. package/src/lib/composables/atomix-glass/useGlassOverLight.ts +0 -198
  37. package/src/lib/composables/atomix-glass/useGlassState.ts +0 -112
  38. package/src/lib/composables/atomix-glass/useGlassTransforms.ts +0 -160
  39. package/src/lib/composables/glass-styles.ts +0 -302
  40. package/src/lib/composables/useGlassContainer.ts +0 -177
@@ -1,5 +1,5 @@
1
1
  import { ATOMIX_GLASS } from '../constants/components';
2
- import { calculateDistance, calculateElementCenter, calculateMouseInfluence, validateGlassSize, clampBlur } from '../../components/AtomixGlass/glass-utils';
2
+ import { calculateDistance, calculateElementCenter, calculateMouseInfluence, validateGlassSize, clampBlur, smoothstep, softClamp } from '../../components/AtomixGlass/glass-utils';
3
3
  import type { GlassSize, MousePosition, OverLightObjectConfig } from '../types/components';
4
4
 
5
5
  /**
@@ -73,30 +73,53 @@ export const updateAtomixGlassStyles = (
73
73
  saturationBoost: baseOverLightConfig.saturationBoost
74
74
  };
75
75
 
76
- // Calculate elastic translation
77
- let elasticTranslation = { x: 0, y: 0 };
78
- if (!effectiveWithoutEffects && wrapperElement) {
79
- const rect = wrapperElement.getBoundingClientRect();
80
- const center = calculateElementCenter(rect);
81
-
82
- // Calculate fade in factor
83
- let fadeInFactor = 0;
84
- if (globalMousePosition.x && globalMousePosition.y && validateGlassSize(glassSize)) {
85
- const edgeDistanceX = Math.max(0, Math.abs(globalMousePosition.x - center.x) - glassSize.width / 2);
86
- const edgeDistanceY = Math.max(0, Math.abs(globalMousePosition.y - center.y) - glassSize.height / 2);
87
- const edgeDistance = calculateDistance({ x: edgeDistanceX, y: edgeDistanceY }, { x: 0, y: 0 });
88
- fadeInFactor = edgeDistance > ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE ? 0 : 1 - edgeDistance / ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE;
89
- }
76
+ let computedDirectionalScale = directionalScale;
77
+
78
+ // Calculate elastic translation and directional scale
79
+ let elasticTranslation = { x: 0, y: 0 };
80
+ if (!effectiveWithoutEffects && wrapperElement) {
81
+ const rect = wrapperElement.getBoundingClientRect();
82
+ const center = calculateElementCenter(rect);
83
+
84
+ // Mouse presence and edge distance logic
85
+ if (globalMousePosition.x && globalMousePosition.y && validateGlassSize(glassSize)) {
86
+ const deltaX = globalMousePosition.x - center.x;
87
+ const deltaY = globalMousePosition.y - center.y;
88
+ const edgeDistanceX = Math.max(0, Math.abs(deltaX) - glassSize.width / 2);
89
+ const edgeDistanceY = Math.max(0, Math.abs(deltaY) - glassSize.height / 2);
90
+ const edgeDistance = calculateDistance({ x: edgeDistanceX, y: edgeDistanceY }, { x: 0, y: 0 });
91
+
92
+ // Elastic translation
93
+ const rawT = edgeDistance > ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE ? 0 : 1 - edgeDistance / ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE;
94
+ const fadeInFactor = smoothstep(rawT);
95
+ elasticTranslation = {
96
+ x: deltaX * elasticity * 0.1 * fadeInFactor,
97
+ y: deltaY * elasticity * 0.1 * fadeInFactor,
98
+ };
90
99
 
91
- elasticTranslation = {
92
- x: (globalMousePosition.x - center.x) * elasticity * 0.1 * fadeInFactor,
93
- y: (globalMousePosition.y - center.y) * elasticity * 0.1 * fadeInFactor,
94
- };
95
- }
100
+ // Directional scale
101
+ if (!isOverLight && edgeDistance <= ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE) {
102
+ const centerDistance = calculateDistance(globalMousePosition, center);
103
+ if (centerDistance > 0) {
104
+ const normalizedX = deltaX / centerDistance;
105
+ const normalizedY = deltaY / centerDistance;
106
+ const stretchIntensity = Math.min(centerDistance / 300, 1) * elasticity * rawT;
107
+
108
+ const scaleX = 1 + Math.abs(normalizedX) * stretchIntensity * 0.3 - Math.abs(normalizedY) * stretchIntensity * 0.15;
109
+ const scaleY = 1 + Math.abs(normalizedY) * stretchIntensity * 0.3 - Math.abs(normalizedX) * stretchIntensity * 0.15;
110
+
111
+ const softScaleX = 1 - softClamp(Math.max(0, 1 - scaleX), 0.2);
112
+ const softScaleY = 1 - softClamp(Math.max(0, 1 - scaleY), 0.2);
113
+
114
+ computedDirectionalScale = `scaleX(${Math.max(0.85, softScaleX)}) scaleY(${Math.max(0.85, softScaleY)})`;
115
+ }
116
+ }
117
+ }
118
+ }
96
119
 
97
- const transformStyle = effectiveWithoutEffects
98
- ? isActive && Boolean(onClick) ? 'scale(0.98)' : 'scale(1)'
99
- : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) ${isActive && Boolean(onClick) ? 'scale(0.96)' : directionalScale}`;
120
+ const transformStyle = effectiveWithoutEffects
121
+ ? isActive && Boolean(onClick) ? 'scale(0.98)' : 'scale(1)'
122
+ : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) ${isActive && Boolean(onClick) ? 'scale(0.96)' : computedDirectionalScale}`;
100
123
 
101
124
  // Update Wrapper Styles (glassVars)
102
125
  if (wrapperElement) {
@@ -1663,7 +1663,9 @@ export const ATOMIX_GLASS = {
1663
1663
  ENABLE_OVER_LIGHT_LAYERS: true,
1664
1664
  },
1665
1665
  CONSTANTS: {
1666
- ACTIVATION_ZONE: 200,
1666
+ ACTIVATION_ZONE: 350,
1667
+ LERP_FACTOR: 0.08,
1668
+ SMOOTHSTEP_POWER: 2.5,
1667
1669
  MIN_BLUR: 0.1,
1668
1670
  MOUSE_INFLUENCE_DIVISOR: 100,
1669
1671
  EDGE_FADE_PIXELS: 2,
@@ -9,7 +9,8 @@
9
9
  // CSS custom property defaults
10
10
  --atomix-glass-radius: var(--atomix-radius-md, 16px);
11
11
  --atomix-glass-transform: none;
12
- --atomix-glass-transition: transform var(--atomix-transition-duration, 0.15s) ease-out;
12
+ --atomix-glass-transition: transform var(--atomix-transition-duration, 0.45s)
13
+ cubic-bezier(0.22, 1, 0.36, 1);
13
14
  --atomix-glass-position: absolute;
14
15
  --atomix-glass-container-width: 100%;
15
16
  --atomix-glass-container-height: 100%;
@@ -19,22 +20,28 @@
19
20
  // Z-INDEX STACKING ORDER (local scale, scoped to this component)
20
21
  // =========================================================================
21
22
  // 0: background layers
22
- // 1: filter (SVG filter + backdrop)
23
+ // 1: container (wraps filter + content)
23
24
  // 2: base / overlay effect layers
24
25
  // 3: hover effect layers
25
- // 4: content (user-facing children)
26
+ // 4: overlay-highlight
26
27
  // 5: border-1
27
28
  // 6: border-2
28
- // 7: overlay-highlight
29
29
  // =========================================================================
30
- --_glass-z-background: 0;
31
- --_glass-z-filter: 1;
32
- --_glass-z-effect: 2;
33
- --_glass-z-hover: 3;
34
- --_glass-z-overlay-highlight: 4;
35
- --_glass-z-border-1: 5;
36
- --_glass-z-border-2: 6;
37
- --_glass-z-content: 7;
30
+ // Internal layers within the container:
31
+ // filter = base + 1
32
+ // content = base + 7
33
+ // =========================================================================
34
+ --atomix-glass-base-z-index: 0;
35
+
36
+ --_glass-z-background: calc(var(--atomix-glass-base-z-index) + 0);
37
+ --_glass-z-container: calc(var(--atomix-glass-base-z-index) + 1);
38
+ --_glass-z-filter: calc(var(--atomix-glass-base-z-index) + 1);
39
+ --_glass-z-effect: calc(var(--atomix-glass-base-z-index) + 2);
40
+ --_glass-z-hover: calc(var(--atomix-glass-base-z-index) + 3);
41
+ --_glass-z-overlay-highlight: calc(var(--atomix-glass-base-z-index) + 4);
42
+ --_glass-z-border-1: calc(var(--atomix-glass-base-z-index) + 5);
43
+ --_glass-z-border-2: calc(var(--atomix-glass-base-z-index) + 6);
44
+ --_glass-z-content: calc(var(--atomix-glass-base-z-index) + 7);
38
45
 
39
46
  // Base layer styles for all effect layers (hover, border, overlay)
40
47
  &__hover-1,
@@ -71,19 +78,25 @@
71
78
  }
72
79
 
73
80
  &__hover-1 {
74
- transition: opacity var(--atomix-transition-duration-fast, 0.15s) ease-out;
81
+ transition:
82
+ opacity 0.2s cubic-bezier(0.22, 1, 0.36, 1),
83
+ background 0.35s cubic-bezier(0.22, 1, 0.36, 1);
75
84
  opacity: var(--atomix-glass-hover-1-opacity, 0);
76
85
  background: var(--atomix-glass-hover-1-gradient, none);
77
86
  }
78
87
 
79
88
  &__hover-2 {
80
- transition: opacity var(--atomix-transition-duration-base, 0.3s) ease-out;
89
+ transition:
90
+ opacity 0.35s cubic-bezier(0.22, 1, 0.36, 1),
91
+ background 0.45s cubic-bezier(0.22, 1, 0.36, 1);
81
92
  opacity: var(--atomix-glass-hover-2-opacity, 0);
82
93
  background: var(--atomix-glass-hover-2-gradient, none);
83
94
  }
84
95
 
85
96
  &__hover-3 {
86
- transition: opacity var(--atomix-transition-duration-slow, 0.5s) ease-out;
97
+ transition:
98
+ opacity 0.55s cubic-bezier(0.22, 1, 0.36, 1),
99
+ background 0.6s cubic-bezier(0.22, 1, 0.36, 1);
87
100
  opacity: var(--atomix-glass-hover-3-opacity, 0);
88
101
  background: var(--atomix-glass-hover-3-gradient, none);
89
102
  }
@@ -112,9 +125,8 @@
112
125
  transition: var(--atomix-glass-transition);
113
126
  mix-blend-mode: screen;
114
127
  z-index: var(--_glass-z-overlay-highlight);
115
- // Dynamic opacity and background are set via inline styles
116
- // Opacity is calculated: opacityValues.over * OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER
117
- // Background gradient uses constants for positioning
128
+ opacity: var(--atomix-glass-overlay-highlight-opacity, 0);
129
+ background: var(--atomix-glass-overlay-highlight-bg, none);
118
130
  }
119
131
 
120
132
  // Border effect layers - matching old version exactly
@@ -180,6 +192,7 @@
180
192
  position: relative;
181
193
  border-radius: var(--atomix-glass-radius);
182
194
  transition: var(--atomix-glass-transition);
195
+ z-index: var(--_glass-z-container);
183
196
  }
184
197
 
185
198
  &__inner {
@@ -187,6 +200,8 @@
187
200
  height: var(--atomix-glass-container-height);
188
201
  position: relative;
189
202
  border-radius: var(--atomix-glass-radius);
203
+ padding: var(--atomix-glass-container-padding);
204
+ box-shadow: var(--atomix-glass-container-box-shadow);
190
205
  }
191
206
 
192
207
  &__filter {
@@ -207,13 +222,18 @@
207
222
  position: absolute;
208
223
  inset: 0;
209
224
  pointer-events: none;
210
- border-radius: var(--atomix-glass-radius);
225
+ border-radius: var(--atomix-glass-container-radius);
226
+ backdrop-filter: var(--atomix-glass-container-backdrop);
211
227
  }
212
228
 
213
229
  &__filter-shadow {
214
230
  position: absolute;
215
231
  inset: var(--atomix-glass-border-width);
216
232
  pointer-events: none;
233
+ border-radius: var(--atomix-glass-container-radius);
234
+ box-shadow: var(--atomix-glass-container-shadow);
235
+ opacity: var(--atomix-glass-container-shadow-opacity);
236
+ background: var(--atomix-glass-container-bg);
217
237
  }
218
238
 
219
239
  &__content {
@@ -222,11 +242,16 @@
222
242
  height: var(--atomix-glass-container-height);
223
243
  border-radius: var(--atomix-glass-radius);
224
244
  z-index: var(--_glass-z-content);
245
+ text-shadow: var(--atomix-glass-container-text-shadow);
225
246
  }
226
247
 
227
248
  // Background layers for over-light mode
228
249
  &__background-layer {
229
- position: absolute;
250
+ position: var(--atomix-glass-position);
251
+ top: var(--atomix-glass-top);
252
+ left: var(--atomix-glass-left);
253
+ width: var(--atomix-glass-width);
254
+ height: var(--atomix-glass-height);
230
255
  pointer-events: none;
231
256
  border-radius: var(--atomix-glass-radius);
232
257
  transform: var(--atomix-glass-transform);
@@ -1,329 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
- import type { OverLightConfig, OverLightObjectConfig } from '../../types/components';
3
-
4
- // Module-level shared background detection cache using WeakMap
5
- // Automatically cleaned up when elements are removed from DOM
6
- interface BackgroundDetectionCacheEntry {
7
- result: boolean;
8
- timestamp: number;
9
- config: OverLightConfig;
10
- threshold: number;
11
- }
12
-
13
- const backgroundDetectionCache = new WeakMap<HTMLElement, BackgroundDetectionCacheEntry>();
14
-
15
- /**
16
- * Compare two OverLightConfig values for equality
17
- * Handles primitives (boolean, 'auto') and objects with deep comparison
18
- */
19
- export const compareOverLightConfig = (
20
- config1: OverLightConfig,
21
- config2: OverLightConfig
22
- ): boolean => {
23
- // Primitive comparison for boolean and 'auto'
24
- if (typeof config1 !== 'object' || config1 === null) {
25
- return config1 === config2;
26
- }
27
-
28
- // Both must be objects at this point
29
- if (typeof config2 !== 'object' || config2 === null) {
30
- return false;
31
- }
32
-
33
- const obj1 = config1 as OverLightObjectConfig;
34
- const obj2 = config2 as OverLightObjectConfig;
35
-
36
- // Deep comparison of object properties
37
- // Compare all defined properties (threshold, opacity, contrast, brightness, saturationBoost)
38
- const props: (keyof OverLightObjectConfig)[] = [
39
- 'threshold',
40
- 'opacity',
41
- 'contrast',
42
- 'brightness',
43
- 'saturationBoost',
44
- ];
45
-
46
- for (const prop of props) {
47
- const val1 = obj1[prop];
48
- const val2 = obj2[prop];
49
-
50
- // If both are undefined, they're equal for this property
51
- if (val1 === undefined && val2 === undefined) {
52
- continue;
53
- }
54
-
55
- // If one is undefined and the other isn't, they're different
56
- if (val1 === undefined || val2 === undefined) {
57
- return false;
58
- }
59
-
60
- // Compare numeric values (handle NaN and floating point precision)
61
- if (typeof val1 === 'number' && typeof val2 === 'number') {
62
- // Use Number.isNaN for proper NaN comparison
63
- if (Number.isNaN(val1) && Number.isNaN(val2)) {
64
- continue;
65
- }
66
- if (Number.isNaN(val1) || Number.isNaN(val2)) {
67
- return false;
68
- }
69
- // Compare with small epsilon for floating point numbers
70
- if (Math.abs(val1 - val2) > Number.EPSILON) {
71
- return false;
72
- }
73
- } else if (val1 !== val2) {
74
- return false;
75
- }
76
- }
77
-
78
- return true;
79
- };
80
-
81
- /**
82
- * Get cached background detection result
83
- */
84
- const getCachedBackgroundDetection = (
85
- parentElement: HTMLElement | null,
86
- overLightConfig: OverLightConfig
87
- ): boolean | null => {
88
- if (!parentElement) {
89
- return null;
90
- }
91
-
92
- const cached = backgroundDetectionCache.get(parentElement);
93
- if (cached && compareOverLightConfig(cached.config, overLightConfig)) {
94
- // Update timestamp for LRU-like behavior (though WeakMap doesn't support LRU)
95
- cached.timestamp = Date.now();
96
- return cached.result;
97
- }
98
-
99
- return null;
100
- };
101
-
102
- /**
103
- * Set cached background detection result
104
- */
105
- const setCachedBackgroundDetection = (
106
- parentElement: HTMLElement | null,
107
- overLightConfig: OverLightConfig,
108
- result: boolean,
109
- threshold: number
110
- ): void => {
111
- if (!parentElement) {
112
- return;
113
- }
114
-
115
- backgroundDetectionCache.set(parentElement, {
116
- result,
117
- timestamp: Date.now(),
118
- config: overLightConfig,
119
- threshold,
120
- });
121
- };
122
-
123
- interface UseGlassBackgroundDetectionProps {
124
- glassRef: React.RefObject<HTMLDivElement>;
125
- overLight: OverLightConfig;
126
- debugOverLight?: boolean;
127
- }
128
-
129
- export function useGlassBackgroundDetection({
130
- glassRef,
131
- overLight,
132
- debugOverLight = false,
133
- }: UseGlassBackgroundDetectionProps) {
134
- const [detectedOverLight, setDetectedOverLight] = useState(false);
135
-
136
- useEffect(() => {
137
- // Only run auto-detection for 'auto' mode or object config (which uses auto-detection)
138
- const shouldDetect =
139
- overLight === 'auto' || (typeof overLight === 'object' && overLight !== null);
140
-
141
- if (shouldDetect && glassRef.current) {
142
- const element = glassRef.current;
143
- const parentElement = element.parentElement;
144
-
145
- // Check shared cache: skip detection if parent unchanged and config unchanged
146
- const cachedResult = getCachedBackgroundDetection(parentElement, overLight);
147
- if (cachedResult !== null) {
148
- setDetectedOverLight(cachedResult);
149
- return;
150
- }
151
-
152
- const timeoutId = setTimeout(() => {
153
- try {
154
- if (!element) {
155
- setDetectedOverLight(false);
156
- return;
157
- }
158
-
159
- // Validate window context
160
- if (typeof window === 'undefined' || typeof window.getComputedStyle !== 'function') {
161
- setDetectedOverLight(false);
162
- return;
163
- }
164
-
165
- let totalLuminance = 0;
166
- let validSamples = 0;
167
- let hasValidBackground = false;
168
-
169
- let currentElement = element.parentElement;
170
- let depth = 0;
171
- const maxDepth = 20;
172
- const maxSamples = 10;
173
-
174
- // Limit traversal depth to prevent infinite loops and performance issues
175
- while (currentElement && validSamples < maxSamples && depth < maxDepth) {
176
- try {
177
- const computedStyle = window.getComputedStyle(currentElement);
178
- if (!computedStyle) {
179
- currentElement = currentElement.parentElement;
180
- depth++;
181
- continue;
182
- }
183
-
184
- const bgColor = computedStyle.backgroundColor;
185
- const bgImage = computedStyle.backgroundImage;
186
-
187
- // Check for solid color backgrounds
188
- if (
189
- bgColor &&
190
- bgColor !== 'rgba(0, 0, 0, 0)' &&
191
- bgColor !== 'transparent' &&
192
- bgColor !== 'initial' &&
193
- bgColor !== 'none'
194
- ) {
195
- const rgb = bgColor.match(/\d+/g);
196
- if (rgb && rgb.length >= 3) {
197
- const r = Number(rgb[0]);
198
- const g = Number(rgb[1]);
199
- const b = Number(rgb[2]);
200
-
201
- // Validate RGB values are valid numbers
202
- if (
203
- !isNaN(r) &&
204
- !isNaN(g) &&
205
- !isNaN(b) &&
206
- isFinite(r) &&
207
- isFinite(g) &&
208
- isFinite(b) &&
209
- r >= 0 &&
210
- r <= 255 &&
211
- g >= 0 &&
212
- g <= 255 &&
213
- b >= 0 &&
214
- b <= 255
215
- ) {
216
- // Only consider if it's not pure black or very dark
217
- if (r > 10 || g > 10 || b > 10) {
218
- const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
219
- if (!isNaN(luminance) && isFinite(luminance)) {
220
- totalLuminance += luminance;
221
- validSamples++;
222
- hasValidBackground = true;
223
- }
224
- }
225
- }
226
- }
227
- }
228
-
229
- // Check for image backgrounds
230
- if (bgImage && bgImage !== 'none' && bgImage !== 'initial') {
231
- // For image backgrounds, assume medium luminance
232
- totalLuminance += 0.5;
233
- validSamples++;
234
- hasValidBackground = true;
235
- }
236
- } catch (styleError) {
237
- // Silently continue if getting computed style fails for this element
238
- if (typeof process === 'undefined' || process.env?.NODE_ENV === 'development') {
239
- console.debug('AtomixGlass: Error getting computed style for element:', styleError);
240
- }
241
- }
242
-
243
- // Move to parent element for next iteration
244
- if (currentElement) {
245
- currentElement = currentElement.parentElement;
246
- depth++;
247
- } else {
248
- break; // Exit loop if currentElement becomes null
249
- }
250
- }
251
-
252
- // More conservative detection with better error handling
253
- if (hasValidBackground && validSamples > 0) {
254
- const avgLuminance = totalLuminance / validSamples;
255
- if (!isNaN(avgLuminance) && isFinite(avgLuminance)) {
256
- let threshold = 0.7; // Conservative threshold for overlight
257
-
258
- // If overLight is an object, use its threshold property with validation
259
- if (typeof overLight === 'object' && overLight !== null) {
260
- const objConfig = overLight as OverLightObjectConfig;
261
- if (objConfig.threshold !== undefined) {
262
- const configThreshold =
263
- typeof objConfig.threshold === 'number' &&
264
- !isNaN(objConfig.threshold) &&
265
- isFinite(objConfig.threshold)
266
- ? objConfig.threshold
267
- : 0.7;
268
- threshold = Math.min(0.9, Math.max(0.1, configThreshold));
269
- }
270
- }
271
-
272
- const isOverLightDetected = avgLuminance > threshold;
273
-
274
- // Cache the result in shared cache
275
- setCachedBackgroundDetection(
276
- element.parentElement,
277
- overLight,
278
- isOverLightDetected,
279
- threshold
280
- );
281
-
282
- setDetectedOverLight(isOverLightDetected);
283
- } else {
284
- // Invalid luminance calculation, default to false
285
- const result = false;
286
- const threshold =
287
- typeof overLight === 'object' && overLight !== null
288
- ? (overLight as OverLightObjectConfig).threshold || 0.7
289
- : 0.7;
290
- setCachedBackgroundDetection(element.parentElement, overLight, result, threshold);
291
- setDetectedOverLight(result);
292
- }
293
- } else {
294
- // Default to false if no valid background found
295
- const result = false;
296
- const threshold =
297
- typeof overLight === 'object' && overLight !== null
298
- ? (overLight as OverLightObjectConfig).threshold || 0.7
299
- : 0.7;
300
- setCachedBackgroundDetection(element.parentElement, overLight, result, threshold);
301
- setDetectedOverLight(result);
302
- }
303
- } catch (error) {
304
- // Enhanced error logging with context
305
- if (typeof process === 'undefined' || process.env?.NODE_ENV === 'development') {
306
- console.warn('AtomixGlass: Error detecting background brightness:', error);
307
- }
308
- const result = false;
309
- if (element && element.parentElement) {
310
- const threshold =
311
- typeof overLight === 'object' && overLight !== null
312
- ? (overLight as OverLightObjectConfig).threshold || 0.7
313
- : 0.7;
314
- setCachedBackgroundDetection(element.parentElement, overLight, result, threshold);
315
- }
316
- setDetectedOverLight(result);
317
- }
318
- }, 150);
319
-
320
- return () => clearTimeout(timeoutId);
321
- } else if (typeof overLight === 'boolean') {
322
- // For boolean values, disable auto-detection
323
- setDetectedOverLight(false);
324
- }
325
- return undefined;
326
- }, [overLight, glassRef, debugOverLight]);
327
-
328
- return { detectedOverLight };
329
- }
@@ -1,82 +0,0 @@
1
- import React, { useEffect, useMemo, useState } from 'react';
2
- import { ATOMIX_GLASS } from '../../constants/components';
3
- import {
4
- extractBorderRadiusFromChildren,
5
- extractBorderRadiusFromDOMElement,
6
- } from '../../../components/AtomixGlass/glass-utils';
7
-
8
- const { CONSTANTS } = ATOMIX_GLASS;
9
-
10
- interface UseGlassCornerRadiusProps {
11
- contentRef: React.RefObject<HTMLDivElement>;
12
- borderRadius?: number;
13
- children?: React.ReactNode;
14
- debugBorderRadius?: boolean;
15
- }
16
-
17
- export function useGlassCornerRadius({
18
- contentRef,
19
- borderRadius,
20
- children,
21
- debugBorderRadius = false,
22
- }: UseGlassCornerRadiusProps) {
23
- const [dynamicBorderRadius, setDynamicCornerRadius] = useState<number>(
24
- CONSTANTS.DEFAULT_CORNER_RADIUS
25
- );
26
-
27
- const effectiveBorderRadius = useMemo(() => {
28
- if (borderRadius !== undefined) {
29
- const result = Math.max(0, borderRadius);
30
- return result;
31
- }
32
-
33
- const result = Math.max(0, dynamicBorderRadius);
34
- return result;
35
- }, [borderRadius, dynamicBorderRadius]);
36
-
37
- // Extract border-radius from children
38
- useEffect(() => {
39
- const extractRadius = () => {
40
- try {
41
- let extractedRadius: number | null = null;
42
-
43
- if (contentRef.current) {
44
- const firstChild = contentRef.current.firstElementChild as HTMLElement;
45
- if (firstChild) {
46
- const domRadius = extractBorderRadiusFromDOMElement(firstChild);
47
- if (domRadius !== null && domRadius > 0) {
48
- extractedRadius = domRadius;
49
- }
50
- }
51
- }
52
-
53
- if (extractedRadius === null) {
54
- const childRadius = extractBorderRadiusFromChildren(children);
55
- if (childRadius > 0 && childRadius !== CONSTANTS.DEFAULT_CORNER_RADIUS) {
56
- extractedRadius = childRadius;
57
- }
58
- }
59
-
60
- if (extractedRadius !== null && extractedRadius > 0) {
61
- setDynamicCornerRadius(extractedRadius);
62
- }
63
- } catch (error) {
64
- if (
65
- (typeof process === 'undefined' || process.env?.NODE_ENV !== 'production') &&
66
- debugBorderRadius
67
- ) {
68
- console.error('[AtomixGlass] Error extracting corner radius:', error);
69
- }
70
- }
71
- };
72
-
73
- extractRadius();
74
- const timeoutId = setTimeout(extractRadius, 100);
75
- return () => clearTimeout(timeoutId);
76
- }, [children, debugBorderRadius, contentRef]);
77
-
78
- return {
79
- dynamicBorderRadius,
80
- effectiveBorderRadius,
81
- };
82
- }