@shohojdhara/atomix 0.4.0 → 0.4.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/dist/atomix.css +0 -14
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +4 -4
- package/dist/atomix.min.css.map +1 -1
- package/dist/charts.d.ts +12 -19
- package/dist/charts.js +555 -359
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +98 -28
- package/dist/core.js +1082 -733
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +26 -21
- package/dist/forms.js +937 -350
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +14 -21
- package/dist/heavy.js +409 -256
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +518 -284
- package/dist/index.esm.js +1993 -1237
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1994 -1237
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/package.json +2 -2
- package/scripts/atomix-cli.js +43 -1
- package/scripts/cli/__tests__/utils.test.js +6 -2
- package/scripts/cli/migration-tools.js +2 -2
- package/scripts/cli/theme-bridge.js +7 -9
- package/scripts/cli/utils.js +2 -1
- package/src/components/Accordion/Accordion.stories.tsx +40 -0
- package/src/components/Accordion/Accordion.tsx +174 -56
- package/src/components/Accordion/AccordionCompound.test.tsx +70 -0
- package/src/components/AtomixGlass/AtomixGlass.tsx +82 -54
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +17 -18
- package/src/components/AtomixGlass/README.md +5 -5
- package/src/components/AtomixGlass/stories/Customization.stories.tsx +2 -2
- package/src/components/AtomixGlass/stories/Examples.stories.tsx +42 -42
- package/src/components/AtomixGlass/stories/Modes.stories.tsx +5 -5
- package/src/components/AtomixGlass/stories/Overview.stories.tsx +3 -3
- package/src/components/AtomixGlass/stories/Performance.stories.tsx +2 -2
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +45 -45
- package/src/components/AtomixGlass/stories/Shaders.stories.tsx +3 -3
- package/src/components/Badge/Badge.stories.tsx +1 -1
- package/src/components/Badge/Badge.tsx +1 -1
- package/src/components/Breadcrumb/Breadcrumb.tsx +185 -65
- package/src/components/Breadcrumb/BreadcrumbCompound.test.tsx +84 -0
- package/src/components/Breadcrumb/index.ts +2 -2
- package/src/components/Button/Button.stories.tsx +1 -1
- package/src/components/Button/README.md +2 -2
- package/src/components/Callout/Callout.stories.tsx +166 -1011
- package/src/components/Callout/Callout.test.tsx +3 -3
- package/src/components/Callout/Callout.tsx +196 -84
- package/src/components/Callout/CalloutCompound.test.tsx +72 -0
- package/src/components/Callout/README.md +2 -2
- package/src/components/Chart/Chart.stories.tsx +1 -1
- package/src/components/Chart/Chart.tsx +5 -5
- package/src/components/Chart/TreemapChart.tsx +37 -29
- package/src/components/DatePicker/readme.md +3 -3
- package/src/components/Dropdown/Dropdown.stories.tsx +1 -1
- package/src/components/Dropdown/Dropdown.tsx +133 -20
- package/src/components/Dropdown/DropdownCompound.test.tsx +64 -0
- package/src/components/EdgePanel/EdgePanel.stories.tsx +7 -7
- package/src/components/EdgePanel/EdgePanel.tsx +164 -112
- package/src/components/EdgePanel/EdgePanelCompound.test.tsx +53 -0
- package/src/components/Form/Checkbox.stories.tsx +1 -1
- package/src/components/Form/Checkbox.tsx +1 -1
- package/src/components/Form/Input.stories.tsx +1 -1
- package/src/components/Form/Input.tsx +1 -1
- package/src/components/Form/Radio.stories.tsx +1 -1
- package/src/components/Form/Radio.tsx +1 -1
- package/src/components/Form/Select.stories.tsx +24 -1
- package/src/components/Form/Select.test.tsx +99 -0
- package/src/components/Form/Select.tsx +145 -94
- package/src/components/Form/SelectOption.tsx +88 -0
- package/src/components/Form/Textarea.stories.tsx +1 -1
- package/src/components/Form/Textarea.tsx +1 -1
- package/src/components/Hero/Hero.stories.tsx +39 -2
- package/src/components/Hero/Hero.test.tsx +142 -0
- package/src/components/Hero/Hero.tsx +143 -4
- package/src/components/List/List.test.tsx +62 -0
- package/src/components/List/List.tsx +16 -5
- package/src/components/List/ListItem.tsx +20 -0
- package/src/components/Messages/Messages.stories.tsx +1 -1
- package/src/components/Messages/Messages.tsx +2 -2
- package/src/components/Modal/Modal.stories.tsx +66 -2
- package/src/components/Modal/Modal.tsx +115 -35
- package/src/components/Modal/ModalCompound.test.tsx +94 -0
- package/src/components/Navigation/Nav/Nav.stories.tsx +2 -2
- package/src/components/Navigation/Nav/Nav.tsx +1 -1
- package/src/components/Navigation/Navbar/Navbar.stories.tsx +3 -3
- package/src/components/Navigation/Navbar/Navbar.tsx +1 -1
- package/src/components/Navigation/SideMenu/SideMenu.stories.tsx +2 -2
- package/src/components/Navigation/SideMenu/SideMenu.tsx +1 -1
- package/src/components/Pagination/Pagination.stories.tsx +1 -1
- package/src/components/Pagination/Pagination.tsx +1 -1
- package/src/components/Popover/Popover.stories.tsx +1 -1
- package/src/components/Popover/Popover.tsx +1 -1
- package/src/components/Progress/Progress.tsx +1 -1
- package/src/components/Rating/Rating.stories.tsx +1 -1
- package/src/components/Rating/Rating.test.tsx +73 -0
- package/src/components/Rating/Rating.tsx +25 -37
- package/src/components/Spinner/Spinner.tsx +1 -1
- package/src/components/Steps/Steps.stories.tsx +1 -1
- package/src/components/Steps/Steps.tsx +125 -22
- package/src/components/Steps/StepsCompound.test.tsx +81 -0
- package/src/components/Tabs/Tabs.stories.tsx +1 -1
- package/src/components/Tabs/Tabs.tsx +198 -45
- package/src/components/Tabs/TabsCompound.test.tsx +64 -0
- package/src/components/Todo/Todo.tsx +0 -1
- package/src/components/Toggle/Toggle.stories.tsx +1 -1
- package/src/components/Toggle/Toggle.tsx +1 -1
- package/src/components/Tooltip/Tooltip.stories.tsx +1 -1
- package/src/components/VideoPlayer/VideoPlayer.stories.tsx +2 -2
- package/src/lib/composables/__tests__/useAtomixGlassPerf.test.tsx +88 -0
- package/src/lib/composables/__tests__/useChart.test.ts +50 -0
- package/src/lib/composables/__tests__/useChart.test.tsx +139 -0
- package/src/lib/composables/__tests__/useHeroBackgroundSlider.test.tsx +59 -0
- package/src/lib/composables/__tests__/useSliderAutoplay.test.tsx +68 -0
- package/src/lib/composables/atomix-glass/useGlassBackgroundDetection.ts +329 -0
- package/src/lib/composables/atomix-glass/useGlassCornerRadius.ts +82 -0
- package/src/lib/composables/atomix-glass/useGlassMouseTracking.ts +153 -0
- package/src/lib/composables/atomix-glass/useGlassOverLight.ts +198 -0
- package/src/lib/composables/atomix-glass/useGlassSize.ts +117 -0
- package/src/lib/composables/atomix-glass/useGlassState.ts +112 -0
- package/src/lib/composables/atomix-glass/useGlassTransforms.ts +160 -0
- package/src/lib/composables/glass-styles.ts +302 -0
- package/src/lib/composables/index.ts +0 -8
- package/src/lib/composables/useAtomixGlass.ts +331 -537
- package/src/lib/composables/useAtomixGlassStyles.ts +307 -0
- package/src/lib/composables/useBarChart.ts +1 -1
- package/src/lib/composables/useBreadcrumb.ts +6 -6
- package/src/lib/composables/useChart.ts +104 -21
- package/src/lib/composables/useHeroBackgroundSlider.ts +16 -7
- package/src/lib/composables/useSlider.ts +66 -34
- package/src/lib/theme/devtools/CLI.ts +2 -10
- package/src/lib/theme/utils/__tests__/themeUtils.test.ts +213 -0
- package/src/lib/types/components.ts +21 -23
- package/src/lib/utils/__tests__/componentUtils.test.ts +57 -2
- package/src/lib/utils/__tests__/dom.test.ts +100 -0
- package/src/lib/utils/__tests__/fontPreloader.test.ts +102 -0
- package/src/lib/utils/__tests__/themeNaming.test.ts +117 -0
- package/src/lib/utils/themeNaming.ts +1 -1
- package/src/styles/06-components/_components.accordion.scss +0 -2
- package/src/styles/06-components/_components.chart.scss +0 -1
- package/src/styles/06-components/_components.dropdown.scss +0 -1
- package/src/styles/06-components/_components.edge-panel.scss +0 -2
- package/src/styles/06-components/_components.photoviewer.scss +0 -1
- package/src/styles/06-components/_components.river.scss +0 -1
- package/src/styles/06-components/_components.slider.scss +0 -3
- package/src/styles/99-utilities/_utilities.glass-fixes.scss +0 -1
package/dist/heavy.js
CHANGED
|
@@ -236,7 +236,7 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
|
|
|
236
236
|
HIGH_CONTRAST: 200
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
|
-
}, {CONSTANTS: CONSTANTS$
|
|
239
|
+
}, {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateDistance = (pos1, pos2) => {
|
|
240
240
|
if (!pos1 || !pos2 || "number" != typeof pos1.x || "number" != typeof pos1.y || "number" != typeof pos2.x || "number" != typeof pos2.y) return 0;
|
|
241
241
|
const deltaX = pos1.x - pos2.x, deltaY = pos1.y - pos2.y;
|
|
242
242
|
return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
|
@@ -249,36 +249,36 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
|
|
|
249
249
|
}, calculateMouseInfluence = mouseOffset => {
|
|
250
250
|
if (!mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y) return 0;
|
|
251
251
|
// Bounded calculation — keeps the glass effect subtle and stable
|
|
252
|
-
const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$
|
|
252
|
+
const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$2.MOUSE_INFLUENCE_DIVISOR;
|
|
253
253
|
return Math.min(.8, influence);
|
|
254
254
|
// Tighter cap to prevent blur/filter blow-out
|
|
255
|
-
}, clampBlur = value => "number" != typeof value || isNaN(value) ? CONSTANTS$
|
|
255
|
+
}, clampBlur = value => "number" != typeof value || isNaN(value) ? CONSTANTS$2.MIN_BLUR : Math.max(CONSTANTS$2.MIN_BLUR, Math.min(50, value)), validateGlassSize = size => size && "number" == typeof size.width && "number" == typeof size.height && size.width > 0 && size.height > 0 && size.width <= CONSTANTS$2.MAX_SIZE && size.height <= CONSTANTS$2.MAX_SIZE, parseBorderRadiusValue = value => {
|
|
256
256
|
if ("number" == typeof value) return Math.max(0, value);
|
|
257
|
-
if ("string" != typeof value || !value.trim()) return CONSTANTS$
|
|
257
|
+
if ("string" != typeof value || !value.trim()) return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
|
|
258
258
|
const trimmedValue = value.trim();
|
|
259
259
|
// Handle px values
|
|
260
260
|
if (trimmedValue.endsWith("px")) {
|
|
261
261
|
const parsed = parseFloat(trimmedValue);
|
|
262
|
-
return isNaN(parsed) ? CONSTANTS$
|
|
262
|
+
return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, parsed);
|
|
263
263
|
}
|
|
264
264
|
// Handle rem values (assume 16px = 1rem)
|
|
265
265
|
if (trimmedValue.endsWith("rem")) {
|
|
266
266
|
const parsed = parseFloat(trimmedValue);
|
|
267
|
-
return isNaN(parsed) ? CONSTANTS$
|
|
267
|
+
return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
|
|
268
268
|
}
|
|
269
269
|
// Handle em values (assume 16px = 1em for simplicity)
|
|
270
270
|
if (trimmedValue.endsWith("em")) {
|
|
271
271
|
const parsed = parseFloat(trimmedValue);
|
|
272
|
-
return isNaN(parsed) ? CONSTANTS$
|
|
272
|
+
return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
|
|
273
273
|
}
|
|
274
274
|
// Handle percentage (convert to approximate px value, assuming 200px container)
|
|
275
275
|
if (trimmedValue.endsWith("%")) {
|
|
276
276
|
const parsed = parseFloat(trimmedValue);
|
|
277
|
-
return isNaN(parsed) ? CONSTANTS$
|
|
277
|
+
return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, parsed / 100 * 200);
|
|
278
278
|
}
|
|
279
279
|
// Handle unitless numbers
|
|
280
280
|
const numValue = parseFloat(trimmedValue);
|
|
281
|
-
return isNaN(numValue) ? CONSTANTS$
|
|
281
|
+
return isNaN(numValue) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, numValue);
|
|
282
282
|
}, extractBorderRadiusFromElement = element => {
|
|
283
283
|
if (!element || !element.props) return null;
|
|
284
284
|
// Check inline styles first (highest priority)
|
|
@@ -294,11 +294,11 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
|
|
|
294
294
|
// If element has children, recursively check them
|
|
295
295
|
if (element.props.children) {
|
|
296
296
|
const childRadius = extractBorderRadiusFromChildren(element.props.children);
|
|
297
|
-
if (childRadius > 0 && childRadius !== CONSTANTS$
|
|
297
|
+
if (childRadius > 0 && childRadius !== CONSTANTS$2.DEFAULT_CORNER_RADIUS) return childRadius;
|
|
298
298
|
}
|
|
299
299
|
return null;
|
|
300
300
|
}, extractBorderRadiusFromChildren = children => {
|
|
301
|
-
if (!children) return CONSTANTS$
|
|
301
|
+
if (!children) return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
|
|
302
302
|
try {
|
|
303
303
|
const childArray = React.Children.toArray(children);
|
|
304
304
|
for (let i = 0; i < childArray.length; i++) {
|
|
@@ -311,7 +311,7 @@ import { Pause, Play, SkipBack, SkipForward, SpeakerX, SpeakerHigh, Gear, Downlo
|
|
|
311
311
|
} catch (error) {
|
|
312
312
|
// Silently handle errors
|
|
313
313
|
}
|
|
314
|
-
return CONSTANTS$
|
|
314
|
+
return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
|
|
315
315
|
}, getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
|
|
316
316
|
switch (mode) {
|
|
317
317
|
case "standard":
|
|
@@ -480,10 +480,10 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
|
|
|
480
480
|
}, globalMousePosition: globalMousePosition = {
|
|
481
481
|
x: 0,
|
|
482
482
|
y: 0
|
|
483
|
-
}, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isHovered: isHovered = !1, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {},
|
|
483
|
+
}, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isHovered: isHovered = !1, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0, padding: padding = "0 0", glassSize: glassSize = {
|
|
484
484
|
width: 0,
|
|
485
485
|
height: 0
|
|
486
|
-
}, onClick: onClick, mode: mode = "standard",
|
|
486
|
+
}, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, elasticity: elasticity = 0, contentRef: contentRef}, ref) => {
|
|
487
487
|
// Generate a stable, deterministic ID for SSR compatibility
|
|
488
488
|
// Use a module-level counter that's consistent across server and client
|
|
489
489
|
const filterId = useMemo((() => "atomix-glass-filter-" + ++idCounter), []), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null);
|
|
@@ -593,7 +593,7 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
|
|
|
593
593
|
flowBlur: 1.2 * blurAmount
|
|
594
594
|
};
|
|
595
595
|
// Enhanced validation for liquid blur
|
|
596
|
-
if (!
|
|
596
|
+
if (!withLiquidBlur || !rectCache || !mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y || isNaN(mouseOffset.x) || isNaN(mouseOffset.y)) return defaultBlur;
|
|
597
597
|
try {
|
|
598
598
|
const mouseInfluence = calculateMouseInfluence(mouseOffset), maxBlur = 2 * blurAmount, baseBlur = Math.min(maxBlur, blurAmount + mouseInfluence * blurAmount * .15), edgeIntensity = .15 * mouseInfluence, edgeBlur = Math.min(maxBlur, baseBlur * (.8 + .4 * edgeIntensity)), centerIntensity = .1 * mouseInfluence, centerBlur = Math.min(maxBlur, baseBlur * (.3 + .3 * centerIntensity)), flowBlur = Math.min(maxBlur, 1.2 * baseBlur);
|
|
599
599
|
// NOTE: hover/active multipliers intentionally omitted here —
|
|
@@ -608,14 +608,14 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
|
|
|
608
608
|
return console.warn("AtomixGlassContainer: Error calculating liquid blur", error),
|
|
609
609
|
defaultBlur;
|
|
610
610
|
}
|
|
611
|
-
}), [
|
|
611
|
+
}), [ withLiquidBlur, blurAmount, mouseOffset, rectCache ]), backdropStyle = useMemo((() => {
|
|
612
612
|
try {
|
|
613
613
|
const dynamicSaturation = saturation + 20 * (liquidBlur.baseBlur || 0), validatedBaseBlur = "number" != typeof liquidBlur.baseBlur || isNaN(liquidBlur.baseBlur) ? 0 : liquidBlur.baseBlur, validatedEdgeBlur = "number" != typeof liquidBlur.edgeBlur || isNaN(liquidBlur.edgeBlur) ? 0 : liquidBlur.edgeBlur, validatedCenterBlur = "number" != typeof liquidBlur.centerBlur || isNaN(liquidBlur.centerBlur) ? 0 : liquidBlur.centerBlur, validatedFlowBlur = "number" != typeof liquidBlur.flowBlur || isNaN(liquidBlur.flowBlur) ? 0 : liquidBlur.flowBlur, area = rectCache ? rectCache.width * rectCache.height : 0;
|
|
614
614
|
// Validate blur values before using them
|
|
615
|
-
return !
|
|
615
|
+
return !withLiquidBlur || effectiveReducedMotion || effectiveWithoutEffects || area > 18e4 ? {
|
|
616
616
|
backdropFilter: `blur(${clampBlur(Math.max(validatedBaseBlur, .8 * validatedEdgeBlur, 1.1 * validatedCenterBlur, .9 * validatedFlowBlur))}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig?.contrast || 1.05}) brightness(${overLightConfig?.brightness || 1.05})`
|
|
617
617
|
} : {
|
|
618
|
-
backdropFilter: `blur(${clampBlur(.4 * validatedBaseBlur + .25 * validatedEdgeBlur + .15 * validatedCenterBlur + .2 * validatedFlowBlur)}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig?.contrast || 1
|
|
618
|
+
backdropFilter: `blur(${clampBlur(.4 * validatedBaseBlur + .25 * validatedEdgeBlur + .15 * validatedCenterBlur + .2 * validatedFlowBlur)}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig?.contrast || 1}) brightness(${overLightConfig?.brightness || 1})`
|
|
619
619
|
};
|
|
620
620
|
// Single-pass fallback: stronger radius to match perceived blur of multi-pass
|
|
621
621
|
} catch (error) {
|
|
@@ -624,7 +624,7 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
|
|
|
624
624
|
backdropFilter: `blur(${blurAmount}px) saturate(${saturation}%) contrast(1.05) brightness(1.05)`
|
|
625
625
|
};
|
|
626
626
|
}
|
|
627
|
-
}), [ liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion,
|
|
627
|
+
}), [ liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion, effectiveWithoutEffects, withLiquidBlur ]), containerVars = useMemo((() => {
|
|
628
628
|
try {
|
|
629
629
|
// Safe extraction of mouse offset values
|
|
630
630
|
const mx = mouseOffset && "number" == typeof mouseOffset.x && !isNaN(mouseOffset.x) ? mouseOffset.x : 0, my = mouseOffset && "number" == typeof mouseOffset.y && !isNaN(mouseOffset.y) ? mouseOffset.y : 0;
|
|
@@ -632,10 +632,10 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
|
|
|
632
632
|
"--atomix-glass-container-width": `${glassSize?.width}`,
|
|
633
633
|
"--atomix-glass-container-height": `${glassSize?.height}`,
|
|
634
634
|
"--atomix-glass-container-padding": padding || "0 0",
|
|
635
|
-
"--atomix-glass-container-radius": `${"number" != typeof
|
|
635
|
+
"--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px`,
|
|
636
636
|
"--atomix-glass-container-backdrop": backdropStyle?.backdropFilter || "none",
|
|
637
637
|
"--atomix-glass-container-shadow": overLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${(.4 + .002 * mx) * (overLightConfig?.shadowIntensity || 1)})`, `inset 0 -1px 0 rgba(0, 0, 0, ${(.2 + .001 * Math.abs(my)) * (overLightConfig?.shadowIntensity || 1)})`, `inset 0 0 20px rgba(0, 0, 0, ${(.08 + .001 * Math.abs(mx + my)) * (overLightConfig?.shadowIntensity || 1)})`, `0 2px 12px rgba(0, 0, 0, ${(.12 + .002 * Math.abs(my)) * (overLightConfig?.shadowIntensity || 1)})` ].join(", ") : "0 0 20px rgba(0, 0, 0, 0.15) inset, 0 4px 8px rgba(0, 0, 0, 0.08) inset",
|
|
638
|
-
"--atomix-glass-container-shadow-opacity":
|
|
638
|
+
"--atomix-glass-container-shadow-opacity": effectiveWithoutEffects ? 0 : 1,
|
|
639
639
|
// Background and shadow values use design token-aligned RGB values
|
|
640
640
|
"--atomix-glass-container-bg": overLight ? `linear-gradient(${180 + .5 * mx}deg, rgba(255, 255, 255, 0.1) 0%, transparent 20%, transparent 80%, rgba(0, 0, 0, 0.05) 100%)` : "none",
|
|
641
641
|
"--atomix-glass-container-text-shadow": overLight ? "0px 2px 12px rgba(0, 0, 0, 0)" : "0px 2px 12px rgba(0, 0, 0, 0.4)",
|
|
@@ -653,14 +653,10 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
|
|
|
653
653
|
"--atomix-glass-container-text-shadow": "none"
|
|
654
654
|
};
|
|
655
655
|
}
|
|
656
|
-
}), [ glassSize, padding,
|
|
657
|
-
el && (el.style.setProperty("transition-duration", "0s", "important"), el.style.setProperty("animation-duration", "0s", "important"),
|
|
658
|
-
el.style.setProperty("transition-delay", "0s", "important"));
|
|
659
|
-
};
|
|
656
|
+
}), [ glassSize, padding, borderRadius, backdropStyle, mouseOffset, overLight, effectiveWithoutEffects ]);
|
|
660
657
|
return jsx("div", {
|
|
661
658
|
ref: el => {
|
|
662
659
|
// Apply force no-transition
|
|
663
|
-
setForceNoTransition(el),
|
|
664
660
|
// Handle forwarded ref
|
|
665
661
|
"function" == typeof ref ? ref(el) : ref && (ref.current = el);
|
|
666
662
|
},
|
|
@@ -695,7 +691,10 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
|
|
|
695
691
|
aberrationIntensity: "number" != typeof aberrationIntensity || isNaN(aberrationIntensity) ? 0 : aberrationIntensity,
|
|
696
692
|
shaderMapUrl: shaderMapUrl
|
|
697
693
|
}), jsx("div", {
|
|
698
|
-
ref:
|
|
694
|
+
ref: el => {
|
|
695
|
+
el && (el.style.setProperty("transition-duration", "0s", "important"), el.style.setProperty("animation-duration", "0s", "important"),
|
|
696
|
+
el.style.setProperty("transition-delay", "0s", "important"));
|
|
697
|
+
},
|
|
699
698
|
className: ATOMIX_GLASS.FILTER_OVERLAY_CLASS,
|
|
700
699
|
style: {
|
|
701
700
|
filter: `url(#${filterId})`,
|
|
@@ -812,7 +811,128 @@ class {
|
|
|
812
811
|
*/ getSubscriberCount() {
|
|
813
812
|
return this.listeners.size;
|
|
814
813
|
}
|
|
815
|
-
},
|
|
814
|
+
}, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
|
|
815
|
+
if (!wrapperElement && !containerElement) return;
|
|
816
|
+
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} = params, mouseInfluence = calculateMouseInfluence(mouseOffset), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1, overLightConfig = {
|
|
817
|
+
opacity: baseOverLightConfig.opacity * hoverIntensity * activeIntensity,
|
|
818
|
+
contrast: Math.min(1.6, baseOverLightConfig.contrast + .1 * mouseInfluence),
|
|
819
|
+
brightness: Math.min(1.1, baseOverLightConfig.brightness + .05 * mouseInfluence),
|
|
820
|
+
shadowIntensity: Math.min(1.2, Math.max(.5, baseOverLightConfig.shadowIntensity + .2 * mouseInfluence)),
|
|
821
|
+
borderOpacity: Math.min(1, Math.max(.3, baseOverLightConfig.borderOpacity + .1 * mouseInfluence)),
|
|
822
|
+
saturationBoost: baseOverLightConfig.saturationBoost
|
|
823
|
+
};
|
|
824
|
+
// Calculate mouse influence
|
|
825
|
+
// Calculate elastic translation
|
|
826
|
+
let elasticTranslation = {
|
|
827
|
+
x: 0,
|
|
828
|
+
y: 0
|
|
829
|
+
};
|
|
830
|
+
if (!effectiveWithoutEffects && wrapperElement) {
|
|
831
|
+
const rect = wrapperElement.getBoundingClientRect(), center = calculateElementCenter(rect);
|
|
832
|
+
// Calculate fade in factor
|
|
833
|
+
let fadeInFactor = 0;
|
|
834
|
+
if (globalMousePosition.x && globalMousePosition.y && validateGlassSize(glassSize)) {
|
|
835
|
+
const edgeDistanceX = Math.max(0, Math.abs(globalMousePosition.x - center.x) - glassSize.width / 2), edgeDistanceY = Math.max(0, Math.abs(globalMousePosition.y - center.y) - glassSize.height / 2), edgeDistance = calculateDistance({
|
|
836
|
+
x: edgeDistanceX,
|
|
837
|
+
y: edgeDistanceY
|
|
838
|
+
}, {
|
|
839
|
+
x: 0,
|
|
840
|
+
y: 0
|
|
841
|
+
});
|
|
842
|
+
fadeInFactor = edgeDistance > ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE ? 0 : 1 - edgeDistance / ATOMIX_GLASS.CONSTANTS.ACTIVATION_ZONE;
|
|
843
|
+
}
|
|
844
|
+
elasticTranslation = {
|
|
845
|
+
x: (globalMousePosition.x - center.x) * elasticity * .1 * fadeInFactor,
|
|
846
|
+
y: (globalMousePosition.y - center.y) * elasticity * .1 * fadeInFactor
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
const transformStyle = effectiveWithoutEffects ? isActive && Boolean(onClick) ? "scale(0.98)" : "scale(1)" : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) ${isActive && Boolean(onClick) ? "scale(0.96)" : directionalScale}`;
|
|
850
|
+
// Update Wrapper Styles (glassVars)
|
|
851
|
+
if (wrapperElement) {
|
|
852
|
+
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 = {
|
|
853
|
+
hover1: {
|
|
854
|
+
x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
|
|
855
|
+
y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1
|
|
856
|
+
},
|
|
857
|
+
hover2: {
|
|
858
|
+
x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_2,
|
|
859
|
+
y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_2
|
|
860
|
+
},
|
|
861
|
+
hover3: {
|
|
862
|
+
x: GRADIENT.CENTER_POSITION + mx * GRADIENT.HOVER_POSITION.MULTIPLIER_3,
|
|
863
|
+
y: GRADIENT.CENTER_POSITION + my * GRADIENT.HOVER_POSITION.MULTIPLIER_3
|
|
864
|
+
}
|
|
865
|
+
}, basePosition = {
|
|
866
|
+
x: GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER,
|
|
867
|
+
y: GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER
|
|
868
|
+
}, opacityValues = {
|
|
869
|
+
hover1: isHovered || isActive ? .5 : 0,
|
|
870
|
+
hover2: isActive ? .5 : 0,
|
|
871
|
+
hover3: isHovered ? .4 : isActive ? .8 : 0,
|
|
872
|
+
base: isOverLight ? overLightConfig.opacity : 0,
|
|
873
|
+
over: isOverLight ? 1.1 * overLightConfig.opacity : 0
|
|
874
|
+
}, style = wrapperElement.style;
|
|
875
|
+
style.setProperty("--atomix-glass-transform", transformStyle || "none"),
|
|
876
|
+
// Gradients
|
|
877
|
+
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%)`),
|
|
878
|
+
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%)`),
|
|
879
|
+
// Hover gradients
|
|
880
|
+
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}%)`),
|
|
881
|
+
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}%)`),
|
|
882
|
+
style.setProperty("--atomix-glass-hover-3-gradient", isOverLight ? `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}%)` : `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}%)`),
|
|
883
|
+
style.setProperty("--atomix-glass-base-gradient", isOverLight ? `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%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`),
|
|
884
|
+
style.setProperty("--atomix-glass-overlay-gradient", isOverLight ? `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%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`),
|
|
885
|
+
// Opacities
|
|
886
|
+
style.setProperty("--atomix-glass-hover-1-opacity", opacityValues.hover1.toString()),
|
|
887
|
+
style.setProperty("--atomix-glass-hover-2-opacity", opacityValues.hover2.toString()),
|
|
888
|
+
style.setProperty("--atomix-glass-hover-3-opacity", opacityValues.hover3.toString()),
|
|
889
|
+
style.setProperty("--atomix-glass-base-opacity", opacityValues.base.toString()),
|
|
890
|
+
style.setProperty("--atomix-glass-overlay-opacity", opacityValues.over.toString()),
|
|
891
|
+
style.setProperty("--atomix-glass-overlay-highlight-opacity", (opacityValues.over * ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER).toString()),
|
|
892
|
+
// Other
|
|
893
|
+
style.setProperty("--atomix-glass-blend-mode", isOverLight ? "multiply" : "overlay"),
|
|
894
|
+
style.setProperty("--atomix-glass-radius", `${effectiveBorderRadius}px`);
|
|
895
|
+
}
|
|
896
|
+
// Update Container Styles (containerVars)
|
|
897
|
+
if (containerElement) {
|
|
898
|
+
const mx = mouseOffset.x, my = mouseOffset.y, EDGE_BLUR_MULTIPLIER = 1.25, CENTER_BLUR_MULTIPLIER = 1.1, FLOW_BLUR_MULTIPLIER = 1.2, MOUSE_INFLUENCE_BLUR_FACTOR = .15, EDGE_INTENSITY_MOUSE_FACTOR = .15, CENTER_INTENSITY_MOUSE_FACTOR = .1, MAX_BLUR_RELATIVE = 2, rect = containerElement.getBoundingClientRect();
|
|
899
|
+
let liquidBlur = {
|
|
900
|
+
baseBlur: blurAmount,
|
|
901
|
+
edgeBlur: blurAmount * EDGE_BLUR_MULTIPLIER,
|
|
902
|
+
centerBlur: blurAmount * CENTER_BLUR_MULTIPLIER,
|
|
903
|
+
flowBlur: blurAmount * FLOW_BLUR_MULTIPLIER
|
|
904
|
+
};
|
|
905
|
+
if (withLiquidBlur && rect) {
|
|
906
|
+
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);
|
|
907
|
+
liquidBlur = {
|
|
908
|
+
baseBlur: clampBlur(baseBlur),
|
|
909
|
+
edgeBlur: clampBlur(edgeBlur),
|
|
910
|
+
centerBlur: clampBlur(centerBlur),
|
|
911
|
+
flowBlur: clampBlur(flowBlur)
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
// Backdrop filter
|
|
915
|
+
let backdropFilterString = `blur(${blurAmount}px) saturate(${saturation}%) contrast(1.05) brightness(1.05)`;
|
|
916
|
+
const dynamicSaturation = saturation + 20 * (liquidBlur.baseBlur || 0), area = rect ? rect.width * rect.height : 0;
|
|
917
|
+
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})`;
|
|
918
|
+
// Container variables
|
|
919
|
+
const style = containerElement.style;
|
|
920
|
+
style.setProperty("--atomix-glass-container-width", `${glassSize.width}`), style.setProperty("--atomix-glass-container-height", `${glassSize.height}`),
|
|
921
|
+
style.setProperty("--atomix-glass-container-padding", padding), style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
|
|
922
|
+
style.setProperty("--atomix-glass-container-backdrop", backdropFilterString),
|
|
923
|
+
// Shadows
|
|
924
|
+
style.setProperty("--atomix-glass-container-shadow", isOverLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${(.4 + .002 * mx) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 -1px 0 rgba(0, 0, 0, ${(.2 + .001 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 0 20px rgba(0, 0, 0, ${(.08 + .001 * Math.abs(mx + my)) * (overLightConfig.shadowIntensity || 1)})`, `0 2px 12px rgba(0, 0, 0, ${(.12 + .002 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})` ].join(", ") : "0 0 20px rgba(0, 0, 0, 0.15) inset, 0 4px 8px rgba(0, 0, 0, 0.08) inset"),
|
|
925
|
+
style.setProperty("--atomix-glass-container-shadow-opacity", effectiveWithoutEffects ? "0" : "1"),
|
|
926
|
+
style.setProperty("--atomix-glass-container-bg", isOverLight ? `linear-gradient(${180 + .5 * mx}deg, rgba(255, 255, 255, 0.1) 0%, transparent 20%, transparent 80%, rgba(0, 0, 0, 0.05) 100%)` : "none"),
|
|
927
|
+
style.setProperty("--atomix-glass-container-text-shadow", isOverLight ? "0px 2px 12px rgba(0, 0, 0, 0)" : "0px 2px 12px rgba(0, 0, 0, 0.4)"),
|
|
928
|
+
style.setProperty("--atomix-glass-container-box-shadow", isOverLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)");
|
|
929
|
+
}
|
|
930
|
+
}, {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* Updates the styles of the AtomixGlass wrapper and container elements imperatively
|
|
934
|
+
* to avoid React re-renders on mouse movement.
|
|
935
|
+
*/ const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new WeakMap, setCachedBackgroundDetection = (parentElement, overLightConfig, result, threshold) => {
|
|
816
936
|
parentElement && backgroundDetectionCache.set(parentElement, {
|
|
817
937
|
result: result,
|
|
818
938
|
timestamp: Date.now(),
|
|
@@ -825,18 +945,74 @@ class {
|
|
|
825
945
|
* Composable hook for AtomixGlass component logic
|
|
826
946
|
* Manages all state, calculations, and event handlers
|
|
827
947
|
*/
|
|
828
|
-
function useAtomixGlass({glassRef: glassRef, contentRef: contentRef,
|
|
948
|
+
function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef: wrapperRef, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, elasticity: elasticity = .05, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, debugPerformance: debugPerformance = !1, children: children, blurAmount: blurAmount, saturation: saturation, padding: padding, withLiquidBlur: withLiquidBlur}) {
|
|
829
949
|
// State
|
|
830
|
-
const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1),
|
|
831
|
-
width: 270,
|
|
832
|
-
height: 69
|
|
833
|
-
}), [internalGlobalMousePosition, setInternalGlobalMousePosition] = useState({
|
|
950
|
+
const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1), cachedRectRef = useRef(null), internalGlobalMousePositionRef = useRef({
|
|
834
951
|
x: 0,
|
|
835
952
|
y: 0
|
|
836
|
-
}),
|
|
953
|
+
}), internalMouseOffsetRef = useRef({
|
|
837
954
|
x: 0,
|
|
838
955
|
y: 0
|
|
839
|
-
}), [
|
|
956
|
+
}), [dynamicBorderRadius, setDynamicCornerRadius] = useState(CONSTANTS.DEFAULT_CORNER_RADIUS), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1), effectiveBorderRadius = useMemo((() => void 0 !== borderRadius ? Math.max(0, borderRadius) : Math.max(0, dynamicBorderRadius)), [ borderRadius, dynamicBorderRadius ]), {glassSize: glassSize} = function({glassRef: glassRef, effectiveBorderRadius: effectiveBorderRadius, cachedRectRef: cachedRectRef}) {
|
|
957
|
+
const [glassSize, setGlassSize] = useState({
|
|
958
|
+
width: 270,
|
|
959
|
+
height: 69
|
|
960
|
+
});
|
|
961
|
+
return useEffect((() => {
|
|
962
|
+
const isValidElement = element => null !== element && element instanceof HTMLElement && element.isConnected;
|
|
963
|
+
let rafId = null, lastSize = {
|
|
964
|
+
width: 0,
|
|
965
|
+
height: 0
|
|
966
|
+
}, lastCornerRadius = effectiveBorderRadius;
|
|
967
|
+
const updateGlassSize = (forceUpdate = !1) => {
|
|
968
|
+
null !== rafId && cancelAnimationFrame(rafId), rafId = requestAnimationFrame((() => {
|
|
969
|
+
if (!isValidElement(glassRef.current)) return void (rafId = null);
|
|
970
|
+
const rect = glassRef.current.getBoundingClientRect();
|
|
971
|
+
if (rect.width <= 0 || rect.height <= 0) return void (rafId = null);
|
|
972
|
+
// Measure actual rendered size without artificial offsets to avoid feedback loops
|
|
973
|
+
const newSize = {
|
|
974
|
+
width: Math.round(rect.width),
|
|
975
|
+
height: Math.round(rect.height)
|
|
976
|
+
}, cornerRadiusChanged = lastCornerRadius !== effectiveBorderRadius, dimensionsChanged = Math.abs(newSize.width - lastSize.width) > 1 || Math.abs(newSize.height - lastSize.height) > 1;
|
|
977
|
+
var size;
|
|
978
|
+
(forceUpdate || cornerRadiusChanged || dimensionsChanged) && validateGlassSize(size = newSize) && size.width <= CONSTANTS$1.MAX_SIZE && size.height <= CONSTANTS$1.MAX_SIZE && (lastSize = newSize,
|
|
979
|
+
lastCornerRadius = effectiveBorderRadius, setGlassSize(newSize)), rafId = null;
|
|
980
|
+
}));
|
|
981
|
+
};
|
|
982
|
+
let resizeTimeoutId = null;
|
|
983
|
+
const debouncedResizeHandler = () => {
|
|
984
|
+
resizeTimeoutId && clearTimeout(resizeTimeoutId), resizeTimeoutId = setTimeout((() => updateGlassSize(!1)), 16);
|
|
985
|
+
}, initialTimeoutId = setTimeout((() => updateGlassSize(!0)), 0);
|
|
986
|
+
let resizeObserver = null, resizeDebounceTimeout = null;
|
|
987
|
+
// ResizeObserver has 98%+ browser support, no need for fallback
|
|
988
|
+
if ("undefined" != typeof ResizeObserver && isValidElement(glassRef.current)) try {
|
|
989
|
+
resizeObserver = new ResizeObserver((entries => {
|
|
990
|
+
for (const entry of entries) if (entry.target === glassRef.current) {
|
|
991
|
+
// Update cached rect when size changes
|
|
992
|
+
glassRef.current && cachedRectRef && (cachedRectRef.current = glassRef.current.getBoundingClientRect()),
|
|
993
|
+
// Debounce resize updates to match RAF timing (16ms)
|
|
994
|
+
resizeDebounceTimeout && clearTimeout(resizeDebounceTimeout), resizeDebounceTimeout = setTimeout((() => updateGlassSize(!1)), 16);
|
|
995
|
+
break;
|
|
996
|
+
}
|
|
997
|
+
})), resizeObserver.observe(glassRef.current);
|
|
998
|
+
} catch (error) {
|
|
999
|
+
console.warn("AtomixGlass: ResizeObserver not available, using window resize only", error);
|
|
1000
|
+
}
|
|
1001
|
+
return window.addEventListener("resize", debouncedResizeHandler, {
|
|
1002
|
+
passive: !0
|
|
1003
|
+
}), () => {
|
|
1004
|
+
clearTimeout(initialTimeoutId), null !== rafId && cancelAnimationFrame(rafId), resizeTimeoutId && clearTimeout(resizeTimeoutId),
|
|
1005
|
+
resizeDebounceTimeout && clearTimeout(resizeDebounceTimeout), window.removeEventListener("resize", debouncedResizeHandler),
|
|
1006
|
+
resizeObserver?.disconnect();
|
|
1007
|
+
};
|
|
1008
|
+
}), [ effectiveBorderRadius, glassRef, cachedRectRef ]), {
|
|
1009
|
+
glassSize: glassSize
|
|
1010
|
+
};
|
|
1011
|
+
}({
|
|
1012
|
+
glassRef: glassRef,
|
|
1013
|
+
effectiveBorderRadius: effectiveBorderRadius,
|
|
1014
|
+
cachedRectRef: cachedRectRef
|
|
1015
|
+
}), effectiveReducedMotion = useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveHighContrast = useMemo((() => highContrast || userPrefersHighContrast), [ highContrast, userPrefersHighContrast ]), effectiveWithoutEffects = useMemo((() => withoutEffects || effectiveReducedMotion), [ withoutEffects, effectiveReducedMotion ]), globalMousePosition = externalGlobalMousePosition || internalGlobalMousePositionRef.current, mouseOffset = externalMouseOffset || internalMouseOffsetRef.current;
|
|
840
1016
|
// Extract border-radius from children
|
|
841
1017
|
useEffect((() => {
|
|
842
1018
|
const extractRadius = () => {
|
|
@@ -867,13 +1043,13 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
867
1043
|
}
|
|
868
1044
|
null !== extractedRadius && extractedRadius > 0 && setDynamicCornerRadius(extractedRadius);
|
|
869
1045
|
} catch (error) {
|
|
870
|
-
"undefined" != typeof process && "production" === process.env?.NODE_ENV || !
|
|
1046
|
+
"undefined" != typeof process && "production" === process.env?.NODE_ENV || !debugBorderRadius || console.error("[AtomixGlass] Error extracting corner radius:", error);
|
|
871
1047
|
}
|
|
872
1048
|
};
|
|
873
1049
|
extractRadius();
|
|
874
1050
|
const timeoutId = setTimeout(extractRadius, 100);
|
|
875
1051
|
return () => clearTimeout(timeoutId);
|
|
876
|
-
}), [ children,
|
|
1052
|
+
}), [ children, debugBorderRadius, contentRef ]),
|
|
877
1053
|
// Media query handlers and background detection
|
|
878
1054
|
useEffect((() => {
|
|
879
1055
|
if (("auto" === overLight || "object" == typeof overLight && null !== overLight) && glassRef.current) {
|
|
@@ -929,72 +1105,52 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
929
1105
|
const rgb = bgColor.match(/\d+/g);
|
|
930
1106
|
if (rgb && rgb.length >= 3) {
|
|
931
1107
|
const r = Number(rgb[0]), g = Number(rgb[1]), b = Number(rgb[2]);
|
|
932
|
-
|
|
933
|
-
if (!isNaN(r) && !isNaN(g) && !isNaN(b) && isFinite(r) && isFinite(g) && isFinite(b) && r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255 && (r > 10 || g > 10 || b > 10)) {
|
|
1108
|
+
if (!isNaN(r) && !isNaN(g) && !isNaN(b) && (r > 10 || g > 10 || b > 10)) {
|
|
934
1109
|
const luminance = (.299 * r + .587 * g + .114 * b) / 255;
|
|
935
1110
|
!isNaN(luminance) && isFinite(luminance) && (totalLuminance += luminance, validSamples++,
|
|
936
1111
|
hasValidBackground = !0);
|
|
937
1112
|
}
|
|
938
1113
|
}
|
|
939
1114
|
}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
// For image backgrounds, assume medium luminance
|
|
943
|
-
totalLuminance += .5, validSamples++, hasValidBackground = !0);
|
|
1115
|
+
bgImage && "none" !== bgImage && "initial" !== bgImage && (totalLuminance += .5,
|
|
1116
|
+
validSamples++, hasValidBackground = !0);
|
|
944
1117
|
} catch (styleError) {
|
|
945
|
-
|
|
1118
|
+
// Silently continue
|
|
946
1119
|
}
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
// Exit loop if currentElement becomes null
|
|
950
|
-
currentElement = currentElement.parentElement, depth++;
|
|
1120
|
+
if (!currentElement) break;
|
|
1121
|
+
currentElement = currentElement.parentElement, depth++;
|
|
951
1122
|
}
|
|
952
|
-
|
|
953
|
-
if (hasValidBackground && validSamples > 0) {
|
|
1123
|
+
if (hasValidBackground && validSamples > 0) {
|
|
954
1124
|
const avgLuminance = totalLuminance / validSamples;
|
|
955
1125
|
if (!isNaN(avgLuminance) && isFinite(avgLuminance)) {
|
|
956
1126
|
let threshold = .7;
|
|
957
|
-
|
|
958
|
-
// If overLight is an object, use its threshold property with validation
|
|
959
|
-
if ("object" == typeof overLight && null !== overLight) {
|
|
1127
|
+
if ("object" == typeof overLight && null !== overLight) {
|
|
960
1128
|
const objConfig = overLight;
|
|
961
1129
|
if (void 0 !== objConfig.threshold) {
|
|
962
|
-
const configThreshold = "number"
|
|
1130
|
+
const configThreshold = "number" != typeof objConfig.threshold || isNaN(objConfig.threshold) ? .7 : objConfig.threshold;
|
|
963
1131
|
threshold = Math.min(.9, Math.max(.1, configThreshold));
|
|
964
1132
|
}
|
|
965
1133
|
}
|
|
966
1134
|
const isOverLightDetected = avgLuminance > threshold;
|
|
967
|
-
|
|
968
|
-
setCachedBackgroundDetection(element.parentElement, overLight, isOverLightDetected, threshold),
|
|
1135
|
+
setCachedBackgroundDetection(element.parentElement, overLight, isOverLightDetected, threshold),
|
|
969
1136
|
setDetectedOverLight(isOverLightDetected);
|
|
970
1137
|
} else {
|
|
971
|
-
// Invalid luminance calculation, default to false
|
|
972
1138
|
const result = !1, threshold = "object" == typeof overLight && null !== overLight && overLight.threshold || .7;
|
|
973
1139
|
setCachedBackgroundDetection(element.parentElement, overLight, result, threshold),
|
|
974
1140
|
setDetectedOverLight(result);
|
|
975
1141
|
}
|
|
976
1142
|
} else {
|
|
977
|
-
// Default to false if no valid background found
|
|
978
1143
|
const result = !1, threshold = "object" == typeof overLight && null !== overLight && overLight.threshold || .7;
|
|
979
1144
|
setCachedBackgroundDetection(element.parentElement, overLight, result, threshold),
|
|
980
1145
|
setDetectedOverLight(result);
|
|
981
1146
|
}
|
|
982
1147
|
} catch (error) {
|
|
983
|
-
|
|
984
|
-
"undefined" != typeof process && "development" !== process.env?.NODE_ENV || console.warn("AtomixGlass: Error detecting background brightness:", error);
|
|
985
|
-
const result = !1;
|
|
986
|
-
if (element && element.parentElement) {
|
|
987
|
-
const threshold = "object" == typeof overLight && null !== overLight && overLight.threshold || .7;
|
|
988
|
-
setCachedBackgroundDetection(element.parentElement, overLight, result, threshold);
|
|
989
|
-
}
|
|
990
|
-
setDetectedOverLight(result);
|
|
1148
|
+
setDetectedOverLight(!1);
|
|
991
1149
|
}
|
|
992
1150
|
}), 150);
|
|
993
1151
|
return () => clearTimeout(timeoutId);
|
|
994
1152
|
}
|
|
995
|
-
if ("boolean" == typeof overLight &&
|
|
996
|
-
// For boolean values, disable auto-detection
|
|
997
|
-
setDetectedOverLight(!1), "function" == typeof window.matchMedia) try {
|
|
1153
|
+
if ("boolean" == typeof overLight && setDetectedOverLight(!1), "function" == typeof window.matchMedia) try {
|
|
998
1154
|
const mediaQueryReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)"), mediaQueryHighContrast = window.matchMedia("(prefers-contrast: high)");
|
|
999
1155
|
setUserPrefersReducedMotion(mediaQueryReducedMotion.matches), setUserPrefersHighContrast(mediaQueryHighContrast.matches);
|
|
1000
1156
|
const handleReducedMotionChange = e => {
|
|
@@ -1005,65 +1161,54 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
1005
1161
|
return mediaQueryReducedMotion.addEventListener ? (mediaQueryReducedMotion.addEventListener("change", handleReducedMotionChange),
|
|
1006
1162
|
mediaQueryHighContrast.addEventListener("change", handleHighContrastChange)) : mediaQueryReducedMotion.addListener && (mediaQueryReducedMotion.addListener(handleReducedMotionChange),
|
|
1007
1163
|
mediaQueryHighContrast.addListener(handleHighContrastChange)), () => {
|
|
1008
|
-
|
|
1009
|
-
mediaQueryReducedMotion.removeEventListener ? (mediaQueryReducedMotion.removeEventListener("change", handleReducedMotionChange),
|
|
1010
|
-
mediaQueryHighContrast.removeEventListener("change", handleHighContrastChange)) : mediaQueryReducedMotion.removeListener && (mediaQueryReducedMotion.removeListener(handleReducedMotionChange),
|
|
1011
|
-
mediaQueryHighContrast.removeListener(handleHighContrastChange));
|
|
1012
|
-
} catch (cleanupError) {
|
|
1013
|
-
console.error("AtomixGlass: Error cleaning up media query listeners:", cleanupError);
|
|
1014
|
-
}
|
|
1164
|
+
// ignore
|
|
1015
1165
|
};
|
|
1016
1166
|
} catch (error) {
|
|
1017
|
-
return
|
|
1167
|
+
return;
|
|
1018
1168
|
}
|
|
1019
1169
|
}), [ overLight, glassRef, debugOverLight ]);
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
x: (globalPos.x - center.x) / rect.width * 100,
|
|
1036
|
-
y: (globalPos.y - center.y) / rect.height * 100
|
|
1170
|
+
/**
|
|
1171
|
+
* Get effective overLight value based on configuration
|
|
1172
|
+
*/
|
|
1173
|
+
const getEffectiveOverLight = useCallback((() => "boolean" == typeof overLight ? overLight : ("auto" === overLight || "object" == typeof overLight && null !== overLight) && detectedOverLight), [ overLight, detectedOverLight ]), validateConfigValue = useCallback(((value, min, max, defaultValue) => "number" != typeof value || isNaN(value) || !isFinite(value) ? defaultValue : Math.min(max, Math.max(min, value))), []), baseOverLightConfig = useMemo((() => {
|
|
1174
|
+
const isOverLight = getEffectiveOverLight(), baseConfig = {
|
|
1175
|
+
isOverLight: isOverLight,
|
|
1176
|
+
threshold: .7,
|
|
1177
|
+
opacity: isOverLight ? Math.min(.6, Math.max(.2, .5)) : 0,
|
|
1178
|
+
contrast: 1,
|
|
1179
|
+
// Base contrast
|
|
1180
|
+
brightness: 1,
|
|
1181
|
+
// Base brightness
|
|
1182
|
+
saturationBoost: 1.3,
|
|
1183
|
+
shadowIntensity: .9,
|
|
1184
|
+
borderOpacity: .7
|
|
1037
1185
|
};
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
return;
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
updateRectRef.current = null), resizeObserver && resizeObserver.disconnect();
|
|
1186
|
+
if ("object" == typeof overLight && null !== overLight) {
|
|
1187
|
+
const objConfig = overLight, validatedThreshold = validateConfigValue(objConfig.threshold, .1, 1, baseConfig.threshold), validatedOpacity = validateConfigValue(objConfig.opacity, .1, 1, baseConfig.opacity), validatedContrast = validateConfigValue(objConfig.contrast, .5, 2.5, baseConfig.contrast), validatedBrightness = validateConfigValue(objConfig.brightness, .5, 2, baseConfig.brightness), validatedSaturationBoost = validateConfigValue(objConfig.saturationBoost, .5, 3, baseConfig.saturationBoost);
|
|
1188
|
+
return {
|
|
1189
|
+
...baseConfig,
|
|
1190
|
+
threshold: validatedThreshold,
|
|
1191
|
+
opacity: validatedOpacity,
|
|
1192
|
+
contrast: validatedContrast,
|
|
1193
|
+
brightness: validatedBrightness,
|
|
1194
|
+
saturationBoost: validatedSaturationBoost
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1197
|
+
return baseConfig;
|
|
1198
|
+
}), [ overLight, getEffectiveOverLight, validateConfigValue ]), overLightConfig = useMemo((() => {
|
|
1199
|
+
const mouseInfluence = calculateMouseInfluence(mouseOffset), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1;
|
|
1200
|
+
return {
|
|
1201
|
+
isOverLight: baseOverLightConfig.isOverLight,
|
|
1202
|
+
threshold: baseOverLightConfig.threshold,
|
|
1203
|
+
opacity: baseOverLightConfig.opacity * hoverIntensity * activeIntensity,
|
|
1204
|
+
contrast: Math.min(1.6, baseOverLightConfig.contrast + .1 * mouseInfluence),
|
|
1205
|
+
brightness: Math.min(1.1, baseOverLightConfig.brightness + .05 * mouseInfluence),
|
|
1206
|
+
saturationBoost: baseOverLightConfig.saturationBoost,
|
|
1207
|
+
shadowIntensity: Math.min(1.2, Math.max(.5, baseOverLightConfig.shadowIntensity + .2 * mouseInfluence)),
|
|
1208
|
+
borderOpacity: Math.min(1, Math.max(.3, baseOverLightConfig.borderOpacity + .1 * mouseInfluence))
|
|
1062
1209
|
};
|
|
1063
|
-
}), [
|
|
1064
|
-
|
|
1065
|
-
const calculateDirectionalScale = useCallback((() => {
|
|
1066
|
-
if (!0 === overLight || "auto" === overLight && detectedOverLight || "object" == typeof overLight && null !== overLight && detectedOverLight) return "scale(1)";
|
|
1210
|
+
}), [ baseOverLightConfig, mouseOffset, isHovered, isActive ]), updateRectRef = useRef(null), calculateDirectionalScale = useCallback((() => {
|
|
1211
|
+
if (baseOverLightConfig.isOverLight) return "scale(1)";
|
|
1067
1212
|
if (!(globalMousePosition.x && globalMousePosition.y && glassRef.current && validateGlassSize(glassSize))) return "scale(1)";
|
|
1068
1213
|
const rect = glassRef.current.getBoundingClientRect(), center = calculateElementCenter(rect), 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({
|
|
1069
1214
|
x: edgeDistanceX,
|
|
@@ -1077,7 +1222,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
1077
1222
|
if (0 === centerDistance) return "scale(1)";
|
|
1078
1223
|
const normalizedX = deltaX / centerDistance, normalizedY = deltaY / centerDistance, stretchIntensity = Math.min(centerDistance / 300, 1) * elasticity * fadeInFactor, scaleX = 1 + Math.abs(normalizedX) * stretchIntensity * .3 - Math.abs(normalizedY) * stretchIntensity * .15, scaleY = 1 + Math.abs(normalizedY) * stretchIntensity * .3 - Math.abs(normalizedX) * stretchIntensity * .15;
|
|
1079
1224
|
return `scaleX(${Math.max(.8, scaleX)}) scaleY(${Math.max(.8, scaleY)})`;
|
|
1080
|
-
}), [ globalMousePosition, elasticity, glassSize, glassRef,
|
|
1225
|
+
}), [ globalMousePosition, elasticity, glassSize, glassRef, baseOverLightConfig ]), calculateFadeInFactor = useCallback((() => {
|
|
1081
1226
|
if (!(globalMousePosition.x && globalMousePosition.y && glassRef.current && validateGlassSize(glassSize))) return 0;
|
|
1082
1227
|
const rect = glassRef.current.getBoundingClientRect(), center = calculateElementCenter(rect), edgeDistanceX = Math.max(0, Math.abs(globalMousePosition.x - center.x) - glassSize.width / 2), edgeDistanceY = Math.max(0, Math.abs(globalMousePosition.y - center.y) - glassSize.height / 2), edgeDistance = calculateDistance({
|
|
1083
1228
|
x: edgeDistanceX,
|
|
@@ -1097,122 +1242,110 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
1097
1242
|
x: (globalMousePosition.x - center.x) * elasticity * .1 * fadeInFactor,
|
|
1098
1243
|
y: (globalMousePosition.y - center.y) * elasticity * .1 * fadeInFactor
|
|
1099
1244
|
};
|
|
1100
|
-
}), [ globalMousePosition, elasticity, calculateFadeInFactor, glassRef ]), elasticTranslation = useMemo((() =>
|
|
1245
|
+
}), [ globalMousePosition, elasticity, calculateFadeInFactor, glassRef ]), elasticTranslation = useMemo((() => effectiveWithoutEffects ? {
|
|
1101
1246
|
x: 0,
|
|
1102
1247
|
y: 0
|
|
1103
|
-
} : calculateElasticTranslation()), [ calculateElasticTranslation,
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
const
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
if (rect.width <= 0 || rect.height <= 0) return void (rafId = null);
|
|
1116
|
-
// Measure actual rendered size without artificial offsets to avoid feedback loops
|
|
1117
|
-
const newSize = {
|
|
1118
|
-
width: Math.round(rect.width),
|
|
1119
|
-
height: Math.round(rect.height)
|
|
1120
|
-
}, cornerRadiusChanged = lastCornerRadius !== effectiveCornerRadius, dimensionsChanged = Math.abs(newSize.width - lastSize.width) > 1 || Math.abs(newSize.height - lastSize.height) > 1;
|
|
1121
|
-
var size;
|
|
1122
|
-
(forceUpdate || cornerRadiusChanged || dimensionsChanged) && validateGlassSize(size = newSize) && size.width <= CONSTANTS.MAX_SIZE && size.height <= CONSTANTS.MAX_SIZE && (lastSize = newSize,
|
|
1123
|
-
lastCornerRadius = effectiveCornerRadius, setGlassSize(newSize)), rafId = null;
|
|
1124
|
-
}));
|
|
1125
|
-
};
|
|
1126
|
-
let resizeTimeoutId = null;
|
|
1127
|
-
const debouncedResizeHandler = () => {
|
|
1128
|
-
resizeTimeoutId && clearTimeout(resizeTimeoutId), resizeTimeoutId = setTimeout((() => updateGlassSize(!1)), 16);
|
|
1129
|
-
}, initialTimeoutId = setTimeout((() => updateGlassSize(!0)), 0);
|
|
1130
|
-
let resizeObserver = null, resizeDebounceTimeout = null;
|
|
1131
|
-
// ResizeObserver has 98%+ browser support, no need for fallback
|
|
1132
|
-
if ("undefined" != typeof ResizeObserver && isValidElement(glassRef.current)) try {
|
|
1133
|
-
resizeObserver = new ResizeObserver((entries => {
|
|
1134
|
-
for (const entry of entries) if (entry.target === glassRef.current) {
|
|
1135
|
-
// Update cached rect when size changes
|
|
1136
|
-
glassRef.current && (cachedRectRef.current = glassRef.current.getBoundingClientRect()),
|
|
1137
|
-
// Debounce resize updates to match RAF timing (16ms)
|
|
1138
|
-
resizeDebounceTimeout && clearTimeout(resizeDebounceTimeout), resizeDebounceTimeout = setTimeout((() => updateGlassSize(!1)), 16);
|
|
1139
|
-
break;
|
|
1140
|
-
}
|
|
1141
|
-
})), resizeObserver.observe(glassRef.current);
|
|
1142
|
-
} catch (error) {
|
|
1143
|
-
console.warn("AtomixGlass: ResizeObserver not available, using window resize only", error);
|
|
1144
|
-
}
|
|
1145
|
-
return window.addEventListener("resize", debouncedResizeHandler, {
|
|
1146
|
-
passive: !0
|
|
1147
|
-
}), () => {
|
|
1148
|
-
clearTimeout(initialTimeoutId), null !== rafId && cancelAnimationFrame(rafId), resizeTimeoutId && clearTimeout(resizeTimeoutId),
|
|
1149
|
-
resizeDebounceTimeout && clearTimeout(resizeDebounceTimeout), window.removeEventListener("resize", debouncedResizeHandler),
|
|
1150
|
-
resizeObserver?.disconnect();
|
|
1248
|
+
} : calculateElasticTranslation()), [ calculateElasticTranslation, effectiveWithoutEffects ]), directionalScale = useMemo((() => effectiveWithoutEffects ? "scale(1)" : calculateDirectionalScale()), [ calculateDirectionalScale, effectiveWithoutEffects ]), transformStyle = useMemo((() => effectiveWithoutEffects ? isActive && Boolean(onClick) ? "scale(0.98)" : "scale(1)" : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) ${isActive && Boolean(onClick) ? "scale(0.96)" : directionalScale}`), [ elasticTranslation, isActive, onClick, directionalScale, effectiveWithoutEffects ]), handleGlobalMousePosition = useCallback((globalPos => {
|
|
1249
|
+
if (externalGlobalMousePosition && externalMouseOffset) return;
|
|
1250
|
+
if (effectiveWithoutEffects) return;
|
|
1251
|
+
const container = mouseContainer?.current || glassRef.current;
|
|
1252
|
+
if (!container) return;
|
|
1253
|
+
// Use cached rect if available, otherwise get new one
|
|
1254
|
+
let rect = cachedRectRef.current;
|
|
1255
|
+
if (rect && 0 !== rect.width && 0 !== rect.height || (rect = container.getBoundingClientRect(),
|
|
1256
|
+
cachedRectRef.current = rect), 0 === rect.width || 0 === rect.height) return;
|
|
1257
|
+
const center = calculateElementCenter(rect), newOffset = {
|
|
1258
|
+
x: (globalPos.x - center.x) / rect.width * 100,
|
|
1259
|
+
y: (globalPos.y - center.y) / rect.height * 100
|
|
1151
1260
|
};
|
|
1152
|
-
|
|
1153
|
-
|
|
1261
|
+
// Calculate offset relative to this container
|
|
1262
|
+
// Store in refs instead of state
|
|
1263
|
+
internalMouseOffsetRef.current = newOffset, internalGlobalMousePositionRef.current = globalPos,
|
|
1264
|
+
// Imperative style update
|
|
1265
|
+
updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
|
|
1266
|
+
mouseOffset: newOffset,
|
|
1267
|
+
globalMousePosition: globalPos,
|
|
1268
|
+
glassSize: glassSize,
|
|
1269
|
+
isHovered: isHovered,
|
|
1270
|
+
isActive: isActive,
|
|
1271
|
+
isOverLight: baseOverLightConfig.isOverLight,
|
|
1272
|
+
baseOverLightConfig: baseOverLightConfig,
|
|
1273
|
+
effectiveBorderRadius: effectiveBorderRadius,
|
|
1274
|
+
effectiveWithoutEffects: effectiveWithoutEffects,
|
|
1275
|
+
effectiveReducedMotion: effectiveReducedMotion,
|
|
1276
|
+
elasticity: elasticity,
|
|
1277
|
+
directionalScale: isActive && Boolean(onClick) ? "scale(0.96)" : "scale(1)",
|
|
1278
|
+
// Simplified directional scale for fast path
|
|
1279
|
+
onClick: onClick,
|
|
1280
|
+
withLiquidBlur: withLiquidBlur,
|
|
1281
|
+
blurAmount: blurAmount,
|
|
1282
|
+
saturation: saturation,
|
|
1283
|
+
padding: padding
|
|
1284
|
+
});
|
|
1285
|
+
}), [ mouseContainer, glassRef, wrapperRef, externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects, glassSize, isHovered, isActive, baseOverLightConfig, effectiveBorderRadius, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding ]);
|
|
1154
1286
|
/**
|
|
1155
|
-
*
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
const
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1287
|
+
* Validate and clamp a numeric config value
|
|
1288
|
+
*/
|
|
1289
|
+
// Subscribe to shared mouse tracker
|
|
1290
|
+
useEffect((() => {
|
|
1291
|
+
if (externalGlobalMousePosition && externalMouseOffset) return;
|
|
1292
|
+
if (effectiveWithoutEffects) return;
|
|
1293
|
+
const unsubscribe = globalMouseTracker.subscribe(handleGlobalMousePosition), container = mouseContainer?.current || glassRef.current;
|
|
1294
|
+
let resizeObserver = null;
|
|
1295
|
+
return container && "undefined" != typeof ResizeObserver && (resizeObserver = new ResizeObserver((() => {
|
|
1296
|
+
null !== updateRectRef.current && cancelAnimationFrame(updateRectRef.current), updateRectRef.current = requestAnimationFrame((() => {
|
|
1297
|
+
const container = mouseContainer?.current || glassRef.current;
|
|
1298
|
+
container && (cachedRectRef.current = container.getBoundingClientRect()), updateRectRef.current = null;
|
|
1299
|
+
}));
|
|
1300
|
+
})), resizeObserver.observe(container)), () => {
|
|
1301
|
+
unsubscribe(), null !== updateRectRef.current && (cancelAnimationFrame(updateRectRef.current),
|
|
1302
|
+
updateRectRef.current = null), resizeObserver && resizeObserver.disconnect();
|
|
1171
1303
|
};
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1304
|
+
}), [ handleGlobalMousePosition, mouseContainer, glassRef, externalGlobalMousePosition, externalMouseOffset, effectiveWithoutEffects ]),
|
|
1305
|
+
// Also call updateStyles on other state changes (hover, active, etc)
|
|
1306
|
+
useEffect((() => {
|
|
1307
|
+
updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
|
|
1308
|
+
mouseOffset: externalMouseOffset || internalMouseOffsetRef.current,
|
|
1309
|
+
globalMousePosition: externalGlobalMousePosition || internalGlobalMousePositionRef.current,
|
|
1310
|
+
glassSize: glassSize,
|
|
1311
|
+
isHovered: isHovered,
|
|
1312
|
+
isActive: isActive,
|
|
1313
|
+
isOverLight: baseOverLightConfig.isOverLight,
|
|
1314
|
+
baseOverLightConfig: baseOverLightConfig,
|
|
1315
|
+
effectiveBorderRadius: effectiveBorderRadius,
|
|
1316
|
+
effectiveWithoutEffects: effectiveWithoutEffects,
|
|
1317
|
+
effectiveReducedMotion: effectiveReducedMotion,
|
|
1318
|
+
elasticity: elasticity,
|
|
1319
|
+
directionalScale: directionalScale,
|
|
1320
|
+
onClick: onClick,
|
|
1321
|
+
withLiquidBlur: withLiquidBlur,
|
|
1322
|
+
blurAmount: blurAmount,
|
|
1323
|
+
saturation: saturation,
|
|
1324
|
+
padding: padding
|
|
1325
|
+
});
|
|
1326
|
+
}), [ isHovered, isActive, glassSize, baseOverLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, directionalScale, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation, padding, onClick ]);
|
|
1327
|
+
// Event handlers
|
|
1328
|
+
const handleMouseEnter = useCallback((() => setIsHovered(!0)), []), handleMouseLeave = useCallback((() => setIsHovered(!1)), []), handleMouseDown = useCallback((() => setIsActive(!0)), []), handleMouseUp = useCallback((() => setIsActive(!1)), []), handleMouseMove = useCallback((_e => {}), []), handleKeyDown = useCallback((e => {
|
|
1187
1329
|
!onClick || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), onClick());
|
|
1188
|
-
}), [ onClick ])
|
|
1189
|
-
|
|
1190
|
-
* Validate and clamp a numeric config value
|
|
1191
|
-
* @param value - The value to validate
|
|
1192
|
-
* @param min - Minimum allowed value
|
|
1193
|
-
* @param max - Maximum allowed value
|
|
1194
|
-
* @param defaultValue - Default value if validation fails
|
|
1195
|
-
* @returns Validated and clamped value
|
|
1196
|
-
*/ return {
|
|
1197
|
-
// State
|
|
1330
|
+
}), [ onClick ]);
|
|
1331
|
+
return {
|
|
1198
1332
|
isHovered: isHovered,
|
|
1199
1333
|
isActive: isActive,
|
|
1200
1334
|
glassSize: glassSize,
|
|
1201
|
-
|
|
1202
|
-
|
|
1335
|
+
dynamicBorderRadius: dynamicBorderRadius,
|
|
1336
|
+
effectiveBorderRadius: effectiveBorderRadius,
|
|
1203
1337
|
effectiveReducedMotion: effectiveReducedMotion,
|
|
1204
1338
|
effectiveHighContrast: effectiveHighContrast,
|
|
1205
|
-
|
|
1339
|
+
effectiveWithoutEffects: effectiveWithoutEffects,
|
|
1206
1340
|
detectedOverLight: detectedOverLight,
|
|
1207
1341
|
globalMousePosition: globalMousePosition,
|
|
1342
|
+
// This is now static (refs or props) unless prop changes
|
|
1208
1343
|
mouseOffset: mouseOffset,
|
|
1209
|
-
//
|
|
1344
|
+
// This is now static (refs or props) unless prop changes
|
|
1210
1345
|
overLightConfig: overLightConfig,
|
|
1211
|
-
// Transform calculations
|
|
1212
1346
|
elasticTranslation: elasticTranslation,
|
|
1213
1347
|
directionalScale: directionalScale,
|
|
1214
1348
|
transformStyle: transformStyle,
|
|
1215
|
-
// Event handlers
|
|
1216
1349
|
handleMouseEnter: handleMouseEnter,
|
|
1217
1350
|
handleMouseLeave: handleMouseLeave,
|
|
1218
1351
|
handleMouseDown: handleMouseDown,
|
|
@@ -1251,7 +1384,7 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
1251
1384
|
*
|
|
1252
1385
|
* @example
|
|
1253
1386
|
* // Manual border-radius override
|
|
1254
|
-
* <AtomixGlass
|
|
1387
|
+
* <AtomixGlass borderRadius={20}>
|
|
1255
1388
|
* <div>Content with 20px glass radius</div>
|
|
1256
1389
|
* </AtomixGlass>
|
|
1257
1390
|
*
|
|
@@ -1292,37 +1425,48 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
1292
1425
|
* <AtomixGlass overLight="auto" debugOverLight={true}>
|
|
1293
1426
|
* <div>Content with debug logging enabled</div>
|
|
1294
1427
|
* </AtomixGlass>
|
|
1295
|
-
*/ function AtomixGlass({children: children, displacementScale: displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, aberrationIntensity: aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY,
|
|
1296
|
-
const glassRef = useRef(null), contentRef = useRef(null), {isHovered: isHovered, isActive: isActive, glassSize: glassSize,
|
|
1428
|
+
*/ function AtomixGlass({children: children, displacementScale: displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, aberrationIntensity: aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer = null, className: className = "", padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, style: style = {}, mode: mode = ATOMIX_GLASS.DEFAULTS.MODE, onClick: onClick, shaderVariant: shaderVariant = "liquidGlass", "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, role: role, tabIndex: tabIndex, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, withLiquidBlur: withLiquidBlur = !1, withBorder: withBorder = !0, withOverLightLayers: withOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS, debugPerformance: debugPerformance = !1, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, height: height, width: width, ...rest}) {
|
|
1429
|
+
const glassRef = useRef(null), contentRef = useRef(null), {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveBorderRadius: effectiveBorderRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveWithoutEffects: effectiveWithoutEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
|
|
1297
1430
|
glassRef: glassRef,
|
|
1298
1431
|
contentRef: contentRef,
|
|
1299
|
-
|
|
1432
|
+
borderRadius: borderRadius,
|
|
1300
1433
|
globalMousePosition: externalGlobalMousePosition,
|
|
1301
1434
|
mouseOffset: externalMouseOffset,
|
|
1302
1435
|
mouseContainer: mouseContainer,
|
|
1303
1436
|
overLight: overLight,
|
|
1304
1437
|
reducedMotion: reducedMotion,
|
|
1305
1438
|
highContrast: highContrast,
|
|
1306
|
-
|
|
1439
|
+
withoutEffects: withoutEffects,
|
|
1307
1440
|
elasticity: elasticity,
|
|
1308
1441
|
onClick: onClick,
|
|
1309
|
-
|
|
1442
|
+
debugBorderRadius: debugBorderRadius,
|
|
1310
1443
|
debugOverLight: debugOverLight,
|
|
1311
|
-
|
|
1312
|
-
children: children
|
|
1313
|
-
|
|
1444
|
+
debugPerformance: debugPerformance,
|
|
1445
|
+
children: children,
|
|
1446
|
+
blurAmount: blurAmount,
|
|
1447
|
+
saturation: saturation,
|
|
1448
|
+
withLiquidBlur: withLiquidBlur,
|
|
1449
|
+
padding: padding,
|
|
1450
|
+
style: style
|
|
1451
|
+
}), isOverLight = useMemo((() => overLightConfig?.isOverLight), [ overLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, baseStyle = {
|
|
1314
1452
|
...style,
|
|
1315
|
-
...!
|
|
1453
|
+
...!effectiveWithoutEffects && {
|
|
1316
1454
|
transform: transformStyle
|
|
1317
1455
|
}
|
|
1318
|
-
}, componentClassName = [ ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`,
|
|
1456
|
+
}, componentClassName = [ ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`, effectiveWithoutEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`, className ].filter(Boolean).join(" "), positionStyles = useMemo((() => ({
|
|
1319
1457
|
position: style.position || "absolute",
|
|
1320
1458
|
top: style.top || 0,
|
|
1321
1459
|
left: style.left || 0
|
|
1322
|
-
})), [ style.position, style.top, style.left ]), adjustedSize = useMemo((() =>
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1460
|
+
})), [ style.position, style.top, style.left ]), adjustedSize = useMemo((() => {
|
|
1461
|
+
const resolveSize = (propValue, styleValue, measuredSize) => {
|
|
1462
|
+
const explicitSize = propValue ?? styleValue;
|
|
1463
|
+
return void 0 !== explicitSize ? "number" == typeof explicitSize ? `${explicitSize}px` : explicitSize : "fixed" === positionStyles.position ? `${Math.max(measuredSize, 0)}px` : "100%";
|
|
1464
|
+
};
|
|
1465
|
+
return {
|
|
1466
|
+
width: resolveSize(width, style.width, glassSize.width),
|
|
1467
|
+
height: resolveSize(height, style.height, glassSize.height)
|
|
1468
|
+
};
|
|
1469
|
+
}), [ width, height, style.width, style.height, positionStyles.position, glassSize.width, glassSize.height ]), gradientValues = useMemo((() => {
|
|
1326
1470
|
const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT;
|
|
1327
1471
|
return {
|
|
1328
1472
|
borderGradientAngle: GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER,
|
|
@@ -1364,13 +1508,13 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
1364
1508
|
}), [ isHovered, isActive, isOverLight, overLightConfig.opacity ]), glassVars = useMemo((() => {
|
|
1365
1509
|
const whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, {borderGradientAngle: borderGradientAngle, borderStop1: borderStop1, borderStop2: borderStop2, borderOpacities: borderOpacities, hoverPositions: hoverPositions, basePosition: basePosition, mx: mx, my: my, absMx: absMx, absMy: absMy} = gradientValues, configBorderOpacity = overLightConfig?.borderOpacity ?? 1;
|
|
1366
1510
|
return {
|
|
1367
|
-
"--atomix-glass-radius": `${
|
|
1511
|
+
"--atomix-glass-radius": `${effectiveBorderRadius}px`,
|
|
1368
1512
|
"--atomix-glass-transform": transformStyle || "none",
|
|
1369
1513
|
"--atomix-glass-position": positionStyles.position,
|
|
1370
1514
|
"--atomix-glass-top": "fixed" !== positionStyles.top ? `${positionStyles.top}px` : "0",
|
|
1371
1515
|
"--atomix-glass-left": "fixed" !== positionStyles.left ? `${positionStyles.left}px` : "0",
|
|
1372
|
-
"--atomix-glass-width":
|
|
1373
|
-
"--atomix-glass-height":
|
|
1516
|
+
"--atomix-glass-width": adjustedSize.width,
|
|
1517
|
+
"--atomix-glass-height": adjustedSize.height,
|
|
1374
1518
|
"--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
|
|
1375
1519
|
"--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay",
|
|
1376
1520
|
"--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%)`,
|
|
@@ -1386,24 +1530,25 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
1386
1530
|
"--atomix-glass-overlay-opacity": opacityValues.over,
|
|
1387
1531
|
"--atomix-glass-overlay-gradient": isOverLight ? `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%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`
|
|
1388
1532
|
};
|
|
1389
|
-
}), [ gradientValues, opacityValues,
|
|
1533
|
+
}), [ gradientValues, opacityValues, effectiveBorderRadius, transformStyle, positionStyles, adjustedSize, isOverLight, overLightConfig.borderOpacity ]), renderBackgroundLayer = layerType => jsx("div", {
|
|
1390
1534
|
className: [ ATOMIX_GLASS.BACKGROUND_LAYER_CLASS, "dark" === layerType ? ATOMIX_GLASS.BACKGROUND_LAYER_DARK_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_BLACK_CLASS, isOverLight ? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS ].filter(Boolean).join(" "),
|
|
1391
1535
|
style: {
|
|
1392
1536
|
...positionStyles,
|
|
1393
1537
|
height: adjustedSize.height,
|
|
1394
1538
|
width: adjustedSize.width,
|
|
1395
|
-
borderRadius: `${
|
|
1539
|
+
borderRadius: `${effectiveBorderRadius}px`,
|
|
1396
1540
|
transform: baseStyle.transform
|
|
1397
1541
|
}
|
|
1398
1542
|
});
|
|
1399
1543
|
return jsxs("div", {
|
|
1544
|
+
...rest,
|
|
1400
1545
|
className: componentClassName,
|
|
1401
1546
|
style: glassVars,
|
|
1402
1547
|
role: role || (onClick ? "button" : void 0),
|
|
1403
1548
|
tabIndex: onClick ? tabIndex ?? 0 : tabIndex,
|
|
1404
1549
|
"aria-label": ariaLabel,
|
|
1405
1550
|
"aria-describedby": ariaDescribedBy,
|
|
1406
|
-
"aria-disabled": !(!onClick || !
|
|
1551
|
+
"aria-disabled": !(!onClick || !effectiveWithoutEffects) || !onClick && void 0,
|
|
1407
1552
|
"aria-pressed": !(!onClick || !isActive) || !onClick && void 0,
|
|
1408
1553
|
onKeyDown: onClick ? handleKeyDown : void 0,
|
|
1409
1554
|
children: [ jsx(AtomixGlassContainer, {
|
|
@@ -1411,18 +1556,18 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
1411
1556
|
contentRef: contentRef,
|
|
1412
1557
|
className: className,
|
|
1413
1558
|
style: baseStyle,
|
|
1414
|
-
|
|
1415
|
-
displacementScale:
|
|
1416
|
-
blurAmount:
|
|
1559
|
+
borderRadius: effectiveBorderRadius,
|
|
1560
|
+
displacementScale: effectiveWithoutEffects ? 0 : "shader" === mode ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_DISPLACEMENT : isOverLight ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.OVER_LIGHT_DISPLACEMENT : displacementScale,
|
|
1561
|
+
blurAmount: effectiveWithoutEffects ? 0 : blurAmount,
|
|
1417
1562
|
saturation: effectiveHighContrast ? ATOMIX_GLASS.CONSTANTS.SATURATION.HIGH_CONTRAST : isOverLight ? saturation * overLightConfig.saturationBoost : saturation,
|
|
1418
|
-
aberrationIntensity:
|
|
1563
|
+
aberrationIntensity: effectiveWithoutEffects ? 0 : "shader" === mode ? aberrationIntensity * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_ABERRATION : aberrationIntensity,
|
|
1419
1564
|
glassSize: glassSize,
|
|
1420
1565
|
padding: padding,
|
|
1421
|
-
mouseOffset:
|
|
1566
|
+
mouseOffset: effectiveWithoutEffects ? {
|
|
1422
1567
|
x: 0,
|
|
1423
1568
|
y: 0
|
|
1424
1569
|
} : mouseOffset,
|
|
1425
|
-
globalMousePosition:
|
|
1570
|
+
globalMousePosition: effectiveWithoutEffects ? {
|
|
1426
1571
|
x: 0,
|
|
1427
1572
|
y: 0
|
|
1428
1573
|
} : globalMousePosition,
|
|
@@ -1442,11 +1587,11 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
1442
1587
|
onClick: onClick,
|
|
1443
1588
|
mode: mode,
|
|
1444
1589
|
transform: baseStyle.transform,
|
|
1445
|
-
|
|
1590
|
+
effectiveWithoutEffects: effectiveWithoutEffects,
|
|
1446
1591
|
effectiveReducedMotion: effectiveReducedMotion,
|
|
1447
1592
|
shaderVariant: shaderVariant,
|
|
1448
1593
|
elasticity: elasticity,
|
|
1449
|
-
|
|
1594
|
+
withLiquidBlur: withLiquidBlur,
|
|
1450
1595
|
children: children
|
|
1451
1596
|
}), Boolean(onClick) && jsxs(Fragment, {
|
|
1452
1597
|
children: [ jsx("div", {
|
|
@@ -1468,11 +1613,19 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, cornerRadiu
|
|
|
1468
1613
|
background: `radial-gradient(circle at ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_X}% ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_Y}%, rgba(255, 255, 255, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.WHITE_OPACITY}) 0%, transparent ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.STOP}%)`
|
|
1469
1614
|
}
|
|
1470
1615
|
}) ]
|
|
1471
|
-
}),
|
|
1616
|
+
}), withBorder && jsxs(Fragment, {
|
|
1472
1617
|
children: [ jsx("span", {
|
|
1473
|
-
className: ATOMIX_GLASS.BORDER_1_CLASS
|
|
1618
|
+
className: ATOMIX_GLASS.BORDER_1_CLASS,
|
|
1619
|
+
style: {
|
|
1620
|
+
width: glassSize.width,
|
|
1621
|
+
height: glassSize.height
|
|
1622
|
+
}
|
|
1474
1623
|
}), jsx("span", {
|
|
1475
|
-
className: ATOMIX_GLASS.BORDER_2_CLASS
|
|
1624
|
+
className: ATOMIX_GLASS.BORDER_2_CLASS,
|
|
1625
|
+
style: {
|
|
1626
|
+
width: glassSize.width,
|
|
1627
|
+
height: glassSize.height
|
|
1628
|
+
}
|
|
1476
1629
|
}) ]
|
|
1477
1630
|
}) ]
|
|
1478
1631
|
});
|
|
@@ -3088,7 +3241,7 @@ const Badge = memo((({label: label, variant: variant = "primary", size: size =
|
|
|
3088
3241
|
// Default glass settings for badges
|
|
3089
3242
|
const defaultGlassProps = {
|
|
3090
3243
|
displacementScale: 20,
|
|
3091
|
-
|
|
3244
|
+
borderRadius: ref.current?.getBoundingClientRect().width ? ref.current?.getBoundingClientRect().width / 2 : 16,
|
|
3092
3245
|
className: "c-badge--glass",
|
|
3093
3246
|
elasticity: 0
|
|
3094
3247
|
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
@@ -3154,7 +3307,7 @@ const Spinner = memo((({size: size = "md", variant: variant = "primary", fullsc
|
|
|
3154
3307
|
const defaultGlassProps = {
|
|
3155
3308
|
displacementScale: 20,
|
|
3156
3309
|
blurAmount: 1,
|
|
3157
|
-
|
|
3310
|
+
borderRadius: 999,
|
|
3158
3311
|
mode: "shader"
|
|
3159
3312
|
}, glassProps = !0 === glass ? defaultGlassProps : {
|
|
3160
3313
|
...defaultGlassProps,
|
|
@@ -3222,7 +3375,7 @@ class ThemeNaming {
|
|
|
3222
3375
|
* Convert camelCase to kebab-case for CSS variables
|
|
3223
3376
|
* @param str - String to convert
|
|
3224
3377
|
*/ static camelToKebab(str) {
|
|
3225
|
-
return str.replace(/([a-z0-9]
|
|
3378
|
+
return str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
3226
3379
|
}
|
|
3227
3380
|
/**
|
|
3228
3381
|
* Convert kebab-case to camelCase for JavaScript properties
|