@shohojdhara/atomix 0.2.4 → 0.2.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.
- package/README.md +19 -0
- package/dist/atomix.css +1300 -1418
- package/dist/atomix.min.css +3 -3
- package/dist/index.d.ts +1259 -874
- package/dist/index.esm.js +16256 -26366
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +15691 -22295
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/themes/applemix.css +15036 -0
- package/dist/themes/applemix.min.css +72 -0
- package/dist/themes/boomdevs.css +1300 -1419
- package/dist/themes/boomdevs.min.css +3 -3
- package/dist/themes/esrar.css +1301 -1419
- package/dist/themes/esrar.min.css +3 -3
- package/dist/themes/flashtrade.css +15187 -0
- package/dist/themes/flashtrade.min.css +86 -0
- package/dist/themes/mashroom.css +1299 -1417
- package/dist/themes/mashroom.min.css +5 -5
- package/dist/themes/shaj-default.css +1300 -1418
- package/dist/themes/shaj-default.min.css +3 -3
- package/package.json +6 -17
- package/src/components/Accordion/Accordion.stories.tsx +4 -26
- package/src/components/Accordion/Accordion.tsx +21 -12
- package/src/components/AtomixGlass/AtomixGlass.test.tsx +106 -72
- package/src/components/AtomixGlass/AtomixGlass.tsx +485 -1215
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +399 -0
- package/src/components/AtomixGlass/GlassFilter.tsx +156 -0
- package/src/components/AtomixGlass/README.md +124 -2
- package/src/components/AtomixGlass/atomixGLass.old.tsx +1266 -0
- package/src/components/AtomixGlass/glass-utils.ts +263 -0
- package/src/components/AtomixGlass/shader-utils.ts +404 -236
- package/src/components/AtomixGlass/{AtomixGlass.stories.tsx → stories/AtomixGlass.stories.tsx} +55 -35
- package/src/components/AtomixGlass/stories/Examples.stories.tsx +57 -89
- package/src/components/AtomixGlass/stories/Modes.stories.tsx +149 -149
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +95 -32
- package/src/components/AtomixGlass/stories/ShaderVariants.stories.tsx +0 -2
- package/src/components/AtomixGlass/stories/shared-components.tsx +9 -18
- package/src/components/AtomixGlass/utils.ts +3 -3
- package/src/components/Avatar/Avatar.tsx +3 -0
- package/src/components/Avatar/AvatarGroup.tsx +2 -1
- package/src/components/Badge/Badge.stories.tsx +74 -54
- package/src/components/Badge/Badge.tsx +8 -12
- package/src/components/Breadcrumb/Breadcrumb.tsx +23 -4
- package/src/components/Button/Button.tsx +3 -5
- package/src/components/Callout/Callout.stories.tsx +86 -35
- package/src/components/Callout/Callout.tsx +4 -0
- package/src/components/Card/Card.stories.tsx +89 -85
- package/src/components/Card/Card.tsx +15 -4
- package/src/components/Card/ElevationCard.tsx +2 -0
- package/src/components/Chart/AnimatedChart.tsx +179 -156
- package/src/components/Chart/AreaChart.tsx +123 -12
- package/src/components/Chart/BarChart.tsx +91 -100
- package/src/components/Chart/BaseChart.tsx +80 -0
- package/src/components/Chart/BubbleChart.tsx +114 -290
- package/src/components/Chart/CandlestickChart.tsx +282 -622
- package/src/components/Chart/Chart.stories.tsx +576 -179
- package/src/components/Chart/Chart.tsx +374 -75
- package/src/components/Chart/ChartRenderer.tsx +371 -220
- package/src/components/Chart/ChartToolbar.tsx +372 -61
- package/src/components/Chart/ChartTooltip.tsx +33 -18
- package/src/components/Chart/DonutChart.tsx +172 -254
- package/src/components/Chart/FunnelChart.tsx +169 -240
- package/src/components/Chart/GaugeChart.tsx +224 -392
- package/src/components/Chart/HeatmapChart.tsx +302 -440
- package/src/components/Chart/LineChart.tsx +148 -103
- package/src/components/Chart/MultiAxisChart.tsx +267 -395
- package/src/components/Chart/PieChart.tsx +114 -64
- package/src/components/Chart/RadarChart.tsx +202 -218
- package/src/components/Chart/ScatterChart.tsx +111 -97
- package/src/components/Chart/TreemapChart.tsx +147 -222
- package/src/components/Chart/WaterfallChart.tsx +253 -291
- package/src/components/Chart/index.ts +11 -9
- package/src/components/Chart/types.ts +85 -9
- package/src/components/Chart/utils.ts +66 -0
- package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +121 -11
- package/src/components/ColorModeToggle/ColorModeToggle.tsx +149 -45
- package/src/components/ColorModeToggle/index.ts +1 -1
- package/src/components/Countdown/Countdown.tsx +4 -0
- package/src/components/DataTable/DataTable.tsx +2 -1
- package/src/components/DatePicker/DatePicker.stories.tsx +0 -11
- package/src/components/DatePicker/DatePicker.tsx +3 -9
- package/src/components/DatePicker/types.ts +5 -0
- package/src/components/Dropdown/Dropdown.stories.tsx +32 -25
- package/src/components/Dropdown/Dropdown.tsx +26 -28
- package/src/components/EdgePanel/EdgePanel.stories.tsx +13 -15
- package/src/components/EdgePanel/EdgePanel.tsx +20 -5
- package/src/components/Footer/Footer.stories.tsx +187 -60
- package/src/components/Footer/Footer.test.tsx +134 -0
- package/src/components/Footer/Footer.tsx +133 -34
- package/src/components/Footer/FooterLink.tsx +1 -1
- package/src/components/Footer/FooterSection.tsx +53 -36
- package/src/components/Footer/FooterSocialLink.tsx +32 -29
- package/src/components/Footer/README.md +82 -3
- package/src/components/Footer/index.ts +1 -1
- package/src/components/Form/Checkbox.stories.tsx +13 -5
- package/src/components/Form/Checkbox.tsx +3 -6
- package/src/components/Form/Form.stories.tsx +10 -3
- package/src/components/Form/Form.tsx +2 -0
- package/src/components/Form/FormGroup.tsx +2 -1
- package/src/components/Form/Input.stories.tsx +12 -11
- package/src/components/Form/Input.tsx +97 -95
- package/src/components/Form/Radio.stories.tsx +22 -7
- package/src/components/Form/Radio.tsx +3 -6
- package/src/components/Form/Select.stories.tsx +21 -6
- package/src/components/Form/Select.tsx +3 -5
- package/src/components/Form/Textarea.stories.tsx +13 -11
- package/src/components/Form/Textarea.tsx +88 -86
- package/src/components/Hero/Hero.stories.tsx +2 -3
- package/src/components/Hero/Hero.tsx +5 -6
- package/src/components/Icon/Icon.tsx +12 -1
- package/src/components/List/List.tsx +2 -1
- package/src/components/List/ListGroup.tsx +2 -1
- package/src/components/Messages/Messages.tsx +3 -2
- package/src/components/Modal/Modal.stories.tsx +48 -34
- package/src/components/Modal/Modal.tsx +19 -23
- package/src/components/Navigation/Menu/MegaMenu.tsx +2 -2
- package/src/components/Navigation/Menu/Menu.tsx +2 -2
- package/src/components/Navigation/Nav/Nav.tsx +6 -1
- package/src/components/Navigation/Nav/NavDropdown.tsx +10 -1
- package/src/components/Navigation/Navbar/Navbar.tsx +4 -1
- package/src/components/Navigation/SideMenu/SideMenu.tsx +3 -2
- package/src/components/Pagination/Pagination.stories.tsx +13 -6
- package/src/components/Pagination/Pagination.tsx +7 -6
- package/src/components/PhotoViewer/PhotoViewer.tsx +2 -1
- package/src/components/Popover/Popover.stories.tsx +32 -24
- package/src/components/Popover/Popover.tsx +4 -1
- package/src/components/ProductReview/ProductReview.tsx +8 -2
- package/src/components/Progress/Progress.tsx +2 -1
- package/src/components/Rating/Rating.stories.tsx +11 -6
- package/src/components/Rating/Rating.tsx +3 -5
- package/src/components/River/River.tsx +5 -5
- package/src/components/SectionIntro/SectionIntro.tsx +8 -2
- package/src/components/Slider/Slider.stories.tsx +4 -4
- package/src/components/Slider/Slider.tsx +4 -3
- package/src/components/Spinner/Spinner.tsx +2 -1
- package/src/components/Steps/Steps.stories.tsx +5 -4
- package/src/components/Steps/Steps.tsx +8 -5
- package/src/components/Tab/Tab.stories.tsx +4 -3
- package/src/components/Tab/Tab.tsx +8 -6
- package/src/components/Testimonial/Testimonial.tsx +8 -2
- package/src/components/Todo/Todo.tsx +2 -1
- package/src/components/Toggle/Toggle.stories.tsx +5 -4
- package/src/components/Toggle/Toggle.tsx +8 -5
- package/src/components/Tooltip/Tooltip.stories.tsx +40 -30
- package/src/components/Tooltip/Tooltip.tsx +9 -2
- package/src/components/Upload/Upload.stories.tsx +252 -0
- package/src/components/Upload/Upload.tsx +92 -53
- package/src/components/VideoPlayer/VideoPlayer.tsx +3 -1
- package/src/components/index.ts +0 -4
- package/src/layouts/Grid/Grid.stories.tsx +10 -23
- package/src/layouts/Grid/Grid.tsx +20 -1
- package/src/layouts/Grid/GridCol.tsx +76 -48
- package/src/lib/composables/useAtomixGlass.ts +861 -44
- package/src/lib/composables/useBarChart.ts +13 -6
- package/src/lib/composables/useChart.ts +17 -13
- package/src/lib/composables/useChartExport.ts +19 -78
- package/src/lib/composables/useChartToolbar.ts +0 -1
- package/src/lib/composables/useEdgePanel.ts +111 -103
- package/src/lib/composables/useFooter.ts +3 -3
- package/src/lib/composables/useGlassContainer.ts +16 -7
- package/src/lib/composables/useLineChart.ts +8 -1
- package/src/lib/composables/useRiver.ts +5 -0
- package/src/lib/composables/useSlider.ts +62 -24
- package/src/lib/composables/useVideoPlayer.ts +60 -63
- package/src/lib/constants/components.ts +146 -32
- package/src/lib/types/components.ts +258 -10
- package/src/lib/utils/displacement-generator.ts +55 -49
- package/src/lib/utils/icons.ts +1 -1
- package/src/lib/utils/index.ts +16 -10
- package/src/styles/01-settings/_settings.accordion.scss +19 -19
- package/src/styles/01-settings/_settings.animations.scss +5 -5
- package/src/styles/01-settings/_settings.avatar-group.scss +1 -1
- package/src/styles/01-settings/_settings.avatar.scss +17 -17
- package/src/styles/01-settings/_settings.background.scss +1 -4
- package/src/styles/01-settings/_settings.badge.scss +1 -1
- package/src/styles/01-settings/_settings.breadcrumb.scss +1 -1
- package/src/styles/01-settings/_settings.card.scss +1 -1
- package/src/styles/01-settings/_settings.chart.scss +65 -2
- package/src/styles/01-settings/_settings.dropdown.scss +1 -1
- package/src/styles/01-settings/_settings.footer.scss +35 -42
- package/src/styles/01-settings/_settings.input.scss +1 -1
- package/src/styles/01-settings/_settings.list.scss +1 -1
- package/src/styles/01-settings/_settings.rating.scss +1 -1
- package/src/styles/01-settings/_settings.tabs.scss +1 -1
- package/src/styles/01-settings/_settings.upload.scss +6 -5
- package/src/styles/02-tools/_tools.animations.scss +4 -5
- package/src/styles/02-tools/_tools.background.scss +1 -13
- package/src/styles/02-tools/_tools.glass.scss +0 -1
- package/src/styles/02-tools/_tools.utility-api.scss +42 -34
- package/src/styles/03-generic/_generic.root.scss +1 -4
- package/src/styles/04-elements/_elements.body.scss +0 -1
- package/src/styles/06-components/_components.atomix-glass.scss +217 -39
- package/src/styles/06-components/_components.badge.scss +6 -8
- package/src/styles/06-components/_components.button.scss +8 -3
- package/src/styles/06-components/_components.card.scss +2 -14
- package/src/styles/06-components/_components.chart.scss +969 -1449
- package/src/styles/06-components/_components.color-mode-toggle.scss +43 -6
- package/src/styles/06-components/_components.dropdown.scss +19 -7
- package/src/styles/06-components/_components.edge-panel.scss +4 -2
- package/src/styles/06-components/_components.footer.scss +166 -85
- package/src/styles/06-components/_components.input.scss +8 -9
- package/src/styles/06-components/_components.list.scss +1 -0
- package/src/styles/06-components/_components.modal.scss +5 -3
- package/src/styles/06-components/_components.skeleton.scss +8 -6
- package/src/styles/06-components/_components.upload.scss +219 -4
- package/src/styles/06-components/old.chart.styles.scss +1 -30
- package/src/styles/99-utilities/_utilities.opacity.scss +1 -1
- package/src/styles/99-utilities/_utilities.scss +1 -1
- package/src/components/Chart/AdvancedChart.tsx +0 -624
- package/src/components/Chart/LineChartNew.tsx +0 -167
- package/src/components/Chart/RealTimeChart.tsx +0 -436
- package/src/components/DatePicker/DatePicker copy.tsx +0 -551
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import React, { forwardRef, useId, useRef, useState, useEffect, useMemo } from 'react';
|
|
2
|
+
import type { CSSProperties } from 'react';
|
|
3
|
+
import type { DisplacementMode, MousePosition, GlassSize } from '../../lib/types/components';
|
|
4
|
+
import type { FragmentShaderType } from './shader-utils';
|
|
5
|
+
import { ShaderDisplacementGenerator, fragmentShaders } from './shader-utils';
|
|
6
|
+
import { GlassFilter } from './GlassFilter';
|
|
7
|
+
import {
|
|
8
|
+
calculateElementCenter,
|
|
9
|
+
calculateDistance,
|
|
10
|
+
calculateMouseInfluence,
|
|
11
|
+
clampBlur,
|
|
12
|
+
validateGlassSize,
|
|
13
|
+
} from './glass-utils';
|
|
14
|
+
import { ATOMIX_GLASS } from '../../lib/constants/components';
|
|
15
|
+
|
|
16
|
+
const { CONSTANTS } = ATOMIX_GLASS;
|
|
17
|
+
|
|
18
|
+
interface AtomixGlassContainerProps {
|
|
19
|
+
className?: string;
|
|
20
|
+
style?: React.CSSProperties;
|
|
21
|
+
displacementScale?: number;
|
|
22
|
+
blurAmount?: number;
|
|
23
|
+
saturation?: number;
|
|
24
|
+
aberrationIntensity?: number;
|
|
25
|
+
mouseOffset?: MousePosition;
|
|
26
|
+
globalMousePosition?: MousePosition;
|
|
27
|
+
onMouseLeave?: () => void;
|
|
28
|
+
onMouseEnter?: () => void;
|
|
29
|
+
onMouseDown?: () => void;
|
|
30
|
+
onMouseUp?: () => void;
|
|
31
|
+
active?: boolean;
|
|
32
|
+
isHovered?: boolean;
|
|
33
|
+
isActive?: boolean;
|
|
34
|
+
overLight?: boolean;
|
|
35
|
+
cornerRadius?: number;
|
|
36
|
+
padding?: string;
|
|
37
|
+
glassSize?: GlassSize;
|
|
38
|
+
onClick?: () => void;
|
|
39
|
+
mode?: DisplacementMode;
|
|
40
|
+
transform?: string;
|
|
41
|
+
effectiveDisableEffects?: boolean;
|
|
42
|
+
effectiveReducedMotion?: boolean;
|
|
43
|
+
shaderVariant?: FragmentShaderType;
|
|
44
|
+
enableLiquidBlur?: boolean;
|
|
45
|
+
elasticity?: number;
|
|
46
|
+
contentRef?: React.RefObject<HTMLDivElement>;
|
|
47
|
+
children?: React.ReactNode;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* AtomixGlassContainer - Internal container component for glass effects
|
|
52
|
+
* Handles the visual glass morphism layer with filters and backdrop effects
|
|
53
|
+
*/
|
|
54
|
+
export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContainerProps>(
|
|
55
|
+
(
|
|
56
|
+
{
|
|
57
|
+
children,
|
|
58
|
+
className = '',
|
|
59
|
+
style,
|
|
60
|
+
displacementScale = 25,
|
|
61
|
+
blurAmount = 0.0625,
|
|
62
|
+
saturation = 180,
|
|
63
|
+
aberrationIntensity = 2,
|
|
64
|
+
mouseOffset = { x: 0, y: 0 },
|
|
65
|
+
globalMousePosition = { x: 0, y: 0 },
|
|
66
|
+
onMouseEnter,
|
|
67
|
+
onMouseLeave,
|
|
68
|
+
onMouseDown,
|
|
69
|
+
onMouseUp,
|
|
70
|
+
active = false,
|
|
71
|
+
isHovered = false,
|
|
72
|
+
isActive = false,
|
|
73
|
+
overLight = false,
|
|
74
|
+
cornerRadius = 0,
|
|
75
|
+
padding = '0 0',
|
|
76
|
+
glassSize = { width: 0, height: 0 },
|
|
77
|
+
onClick,
|
|
78
|
+
mode = 'standard',
|
|
79
|
+
effectiveDisableEffects = false,
|
|
80
|
+
effectiveReducedMotion = false,
|
|
81
|
+
shaderVariant = 'liquidGlass',
|
|
82
|
+
enableLiquidBlur = false,
|
|
83
|
+
elasticity = 0,
|
|
84
|
+
contentRef,
|
|
85
|
+
},
|
|
86
|
+
ref
|
|
87
|
+
) => {
|
|
88
|
+
const filterId = useId();
|
|
89
|
+
const [shaderMapUrl, setShaderMapUrl] = useState<string>('');
|
|
90
|
+
const shaderGeneratorRef = useRef<ShaderDisplacementGenerator | null>(null);
|
|
91
|
+
|
|
92
|
+
// Generate initial shader map when mode/size/variant changes
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
// Enhanced validation for shader mode
|
|
95
|
+
if (mode === 'shader' && glassSize && validateGlassSize(glassSize)) {
|
|
96
|
+
try {
|
|
97
|
+
shaderGeneratorRef.current?.destroy();
|
|
98
|
+
const selectedShader = fragmentShaders[shaderVariant] || fragmentShaders.liquidGlass;
|
|
99
|
+
shaderGeneratorRef.current = new ShaderDisplacementGenerator({
|
|
100
|
+
width: glassSize.width,
|
|
101
|
+
height: glassSize.height,
|
|
102
|
+
fragment: selectedShader,
|
|
103
|
+
});
|
|
104
|
+
const url = shaderGeneratorRef.current.updateShader();
|
|
105
|
+
setShaderMapUrl(url);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.warn('AtomixGlassContainer: Error generating shader map', error);
|
|
108
|
+
setShaderMapUrl(''); // Fallback to empty string
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Cleanup function with error handling
|
|
113
|
+
return () => {
|
|
114
|
+
try {
|
|
115
|
+
shaderGeneratorRef.current?.destroy();
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.warn('AtomixGlassContainer: Error during shader cleanup', error);
|
|
118
|
+
} finally {
|
|
119
|
+
shaderGeneratorRef.current = null;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}, [mode, glassSize, shaderVariant]);
|
|
123
|
+
|
|
124
|
+
useEffect(() => {
|
|
125
|
+
if (!ref || typeof ref === 'function') return undefined;
|
|
126
|
+
|
|
127
|
+
const element = (ref as React.RefObject<HTMLDivElement>).current;
|
|
128
|
+
if (!element) return undefined;
|
|
129
|
+
|
|
130
|
+
const timeoutId = setTimeout(() => {
|
|
131
|
+
try {
|
|
132
|
+
// Force reflow to ensure proper sizing
|
|
133
|
+
element.offsetHeight;
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.warn('AtomixGlassContainer: Error during reflow', error);
|
|
136
|
+
}
|
|
137
|
+
}, 0);
|
|
138
|
+
|
|
139
|
+
return () => clearTimeout(timeoutId);
|
|
140
|
+
}, [cornerRadius, glassSize?.width, glassSize?.height, ref]);
|
|
141
|
+
|
|
142
|
+
const [rectCache, setRectCache] = useState<DOMRect | null>(null);
|
|
143
|
+
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
if (!ref || typeof ref === 'function') return undefined;
|
|
146
|
+
const element = (ref as React.RefObject<HTMLDivElement>).current;
|
|
147
|
+
if (!element) return undefined;
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
setRectCache(element.getBoundingClientRect());
|
|
151
|
+
} catch (error) {
|
|
152
|
+
console.warn('AtomixGlassContainer: Error getting element bounds', error);
|
|
153
|
+
setRectCache(null);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return undefined;
|
|
157
|
+
}, [ref, glassSize]);
|
|
158
|
+
|
|
159
|
+
const liquidBlur = useMemo(() => {
|
|
160
|
+
const defaultBlur = {
|
|
161
|
+
baseBlur: blurAmount,
|
|
162
|
+
edgeBlur: blurAmount * 1.25,
|
|
163
|
+
centerBlur: blurAmount * 1.1,
|
|
164
|
+
flowBlur: blurAmount * 1.2,
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// Enhanced validation for liquid blur
|
|
168
|
+
if (
|
|
169
|
+
!enableLiquidBlur ||
|
|
170
|
+
!rectCache ||
|
|
171
|
+
!globalMousePosition ||
|
|
172
|
+
typeof globalMousePosition.x !== 'number' ||
|
|
173
|
+
typeof globalMousePosition.y !== 'number' ||
|
|
174
|
+
isNaN(globalMousePosition.x) ||
|
|
175
|
+
isNaN(globalMousePosition.y)
|
|
176
|
+
) {
|
|
177
|
+
return defaultBlur;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
const center = calculateElementCenter(rectCache);
|
|
182
|
+
const distance = calculateDistance(globalMousePosition, center);
|
|
183
|
+
const maxDistance =
|
|
184
|
+
Math.sqrt(rectCache.width * rectCache.width + rectCache.height * rectCache.height) / 2;
|
|
185
|
+
const normalizedDistance = Math.min(distance / maxDistance, 1);
|
|
186
|
+
const mouseInfluence = calculateMouseInfluence(mouseOffset);
|
|
187
|
+
|
|
188
|
+
const baseBlur = blurAmount + mouseInfluence * blurAmount * 0.4;
|
|
189
|
+
const edgeIntensity = normalizedDistance * 1.5 + mouseInfluence * 0.3;
|
|
190
|
+
const edgeBlur = baseBlur * (0.8 + edgeIntensity * 0.6);
|
|
191
|
+
const centerIntensity = (1 - normalizedDistance) * 0.3 + mouseInfluence * 0.2;
|
|
192
|
+
const centerBlur = baseBlur * (0.3 + centerIntensity * 0.4);
|
|
193
|
+
const deltaX = globalMousePosition.x - center.x;
|
|
194
|
+
const deltaY = globalMousePosition.y - center.y;
|
|
195
|
+
const flowDirection = Math.atan2(deltaY, deltaX);
|
|
196
|
+
const flowIntensity = Math.sin(flowDirection + mouseInfluence * Math.PI) * 0.5 + 0.5;
|
|
197
|
+
const flowBlur = baseBlur * (0.4 + flowIntensity * 0.6);
|
|
198
|
+
|
|
199
|
+
const hoverMultiplier = isHovered ? 1.2 : 1;
|
|
200
|
+
const activeMultiplier = isActive ? 1.4 : 1;
|
|
201
|
+
const stateMultiplier = hoverMultiplier * activeMultiplier;
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
baseBlur: clampBlur(baseBlur * stateMultiplier),
|
|
205
|
+
edgeBlur: clampBlur(edgeBlur * stateMultiplier),
|
|
206
|
+
centerBlur: clampBlur(centerBlur * stateMultiplier),
|
|
207
|
+
flowBlur: clampBlur(flowBlur * stateMultiplier),
|
|
208
|
+
};
|
|
209
|
+
} catch (error) {
|
|
210
|
+
console.warn('AtomixGlassContainer: Error calculating liquid blur', error);
|
|
211
|
+
return defaultBlur;
|
|
212
|
+
}
|
|
213
|
+
}, [
|
|
214
|
+
enableLiquidBlur,
|
|
215
|
+
blurAmount,
|
|
216
|
+
globalMousePosition,
|
|
217
|
+
mouseOffset,
|
|
218
|
+
isHovered,
|
|
219
|
+
isActive,
|
|
220
|
+
rectCache,
|
|
221
|
+
style,
|
|
222
|
+
glassSize,
|
|
223
|
+
]);
|
|
224
|
+
|
|
225
|
+
const backdropStyle = useMemo(() => {
|
|
226
|
+
try {
|
|
227
|
+
const dynamicSaturation = saturation + (liquidBlur.baseBlur || 0) * 20;
|
|
228
|
+
|
|
229
|
+
// Validate blur values before using them
|
|
230
|
+
const validatedBaseBlur =
|
|
231
|
+
typeof liquidBlur.baseBlur === 'number' && !isNaN(liquidBlur.baseBlur)
|
|
232
|
+
? liquidBlur.baseBlur
|
|
233
|
+
: 0;
|
|
234
|
+
const validatedEdgeBlur =
|
|
235
|
+
typeof liquidBlur.edgeBlur === 'number' && !isNaN(liquidBlur.edgeBlur)
|
|
236
|
+
? liquidBlur.edgeBlur
|
|
237
|
+
: 0;
|
|
238
|
+
const validatedCenterBlur =
|
|
239
|
+
typeof liquidBlur.centerBlur === 'number' && !isNaN(liquidBlur.centerBlur)
|
|
240
|
+
? liquidBlur.centerBlur
|
|
241
|
+
: 0;
|
|
242
|
+
const validatedFlowBlur =
|
|
243
|
+
typeof liquidBlur.flowBlur === 'number' && !isNaN(liquidBlur.flowBlur)
|
|
244
|
+
? liquidBlur.flowBlur
|
|
245
|
+
: 0;
|
|
246
|
+
|
|
247
|
+
const blurLayers = [
|
|
248
|
+
`blur(${validatedBaseBlur}px)`,
|
|
249
|
+
`blur(${validatedEdgeBlur}px)`,
|
|
250
|
+
`blur(${validatedCenterBlur}px)`,
|
|
251
|
+
`blur(${validatedFlowBlur}px)`,
|
|
252
|
+
];
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
backdropFilter: `${blurLayers.join(' ')} saturate(${Math.min(dynamicSaturation, 200)}%) `,
|
|
256
|
+
};
|
|
257
|
+
} catch (error) {
|
|
258
|
+
console.warn('AtomixGlassContainer: Error calculating backdrop style', error);
|
|
259
|
+
return {
|
|
260
|
+
backdropFilter: `blur(${blurAmount}px) saturate(${saturation}%)`,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
}, [filterId, liquidBlur, saturation, blurAmount]);
|
|
264
|
+
|
|
265
|
+
const containerVars = useMemo(() => {
|
|
266
|
+
try {
|
|
267
|
+
// Safe extraction of mouse offset values
|
|
268
|
+
const mx =
|
|
269
|
+
mouseOffset && typeof mouseOffset.x === 'number' && !isNaN(mouseOffset.x)
|
|
270
|
+
? mouseOffset.x
|
|
271
|
+
: 0;
|
|
272
|
+
const my =
|
|
273
|
+
mouseOffset && typeof mouseOffset.y === 'number' && !isNaN(mouseOffset.y)
|
|
274
|
+
? mouseOffset.y
|
|
275
|
+
: 0;
|
|
276
|
+
return {
|
|
277
|
+
'--atomix-glass-container-width': `${glassSize?.width}`,
|
|
278
|
+
'--atomix-glass-container-height': `${glassSize?.height}`,
|
|
279
|
+
'--atomix-glass-container-padding': padding || '0 0',
|
|
280
|
+
'--atomix-glass-container-radius': `${typeof cornerRadius === 'number' && !isNaN(cornerRadius) ? cornerRadius : 0}px`,
|
|
281
|
+
'--atomix-glass-container-backdrop': backdropStyle?.backdropFilter || 'none',
|
|
282
|
+
'--atomix-glass-container-shadow': overLight
|
|
283
|
+
? [
|
|
284
|
+
`inset 0 1px 0 rgba(255, 255, 255, ${0.4 + mx * 0.002})`,
|
|
285
|
+
`inset 0 -1px 0 rgba(0, 0, 0, ${0.2 + Math.abs(my) * 0.001})`,
|
|
286
|
+
`inset 0 0 20px rgba(0, 0, 0, ${0.08 + Math.abs(mx + my) * 0.001})`,
|
|
287
|
+
`0 2px 12px rgba(0, 0, 0, ${0.12 + Math.abs(my) * 0.002})`,
|
|
288
|
+
].join(', ')
|
|
289
|
+
: '0 0 20px rgba(0, 0, 0, 0.15) inset, 0 4px 8px rgba(0, 0, 0, 0.08) inset',
|
|
290
|
+
'--atomix-glass-container-shadow-opacity': effectiveDisableEffects ? 0 : 1,
|
|
291
|
+
// Background and shadow values use design token-aligned RGB values
|
|
292
|
+
'--atomix-glass-container-bg': overLight
|
|
293
|
+
? `linear-gradient(${180 + mx * 0.5}deg, rgba(255, 255, 255, 0.1) 0%, transparent 20%, transparent 80%, rgba(0, 0, 0, 0.05) 100%)`
|
|
294
|
+
: 'none',
|
|
295
|
+
'--atomix-glass-container-text-shadow': overLight
|
|
296
|
+
? '0px 2px 12px rgba(0, 0, 0, 0)'
|
|
297
|
+
: '0px 2px 12px rgba(0, 0, 0, 0.4)',
|
|
298
|
+
'--atomix-glass-container-box-shadow': overLight
|
|
299
|
+
? '0px 16px 70px rgba(0, 0, 0, 0.75)'
|
|
300
|
+
: '0px 12px 40px rgba(0, 0, 0, 0.25)',
|
|
301
|
+
} as React.CSSProperties;
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.warn('AtomixGlassContainer: Error generating container variables', error);
|
|
304
|
+
return {
|
|
305
|
+
'--atomix-glass-container-padding': '0 0',
|
|
306
|
+
'--atomix-glass-container-radius': '0px',
|
|
307
|
+
'--atomix-glass-container-backdrop': 'none',
|
|
308
|
+
'--atomix-glass-container-shadow': 'none',
|
|
309
|
+
'--atomix-glass-container-shadow-opacity': 1,
|
|
310
|
+
'--atomix-glass-container-bg': 'none',
|
|
311
|
+
'--atomix-glass-container-text-shadow': 'none',
|
|
312
|
+
} as React.CSSProperties;
|
|
313
|
+
}
|
|
314
|
+
}, [
|
|
315
|
+
glassSize,
|
|
316
|
+
padding,
|
|
317
|
+
cornerRadius,
|
|
318
|
+
backdropStyle,
|
|
319
|
+
mouseOffset,
|
|
320
|
+
overLight,
|
|
321
|
+
effectiveDisableEffects,
|
|
322
|
+
]);
|
|
323
|
+
|
|
324
|
+
return (
|
|
325
|
+
<div
|
|
326
|
+
ref={ref}
|
|
327
|
+
className={`${ATOMIX_GLASS.CONTAINER_CLASS} ${className} ${active ? ATOMIX_GLASS.CLASSES.ACTIVE : ''} ${overLight ? ATOMIX_GLASS.CLASSES.OVER_LIGHT : ''}`}
|
|
328
|
+
style={{ ...style, ...containerVars }}
|
|
329
|
+
onClick={onClick}
|
|
330
|
+
>
|
|
331
|
+
<div
|
|
332
|
+
className={ATOMIX_GLASS.INNER_CLASS}
|
|
333
|
+
style={{
|
|
334
|
+
padding: `var(--atomix-glass-container-padding)`,
|
|
335
|
+
borderRadius: `var(--atomix-glass-container-radius)`,
|
|
336
|
+
boxShadow: `var(--atomix-glass-container-box-shadow)`,
|
|
337
|
+
}}
|
|
338
|
+
onMouseEnter={onMouseEnter}
|
|
339
|
+
onMouseLeave={onMouseLeave}
|
|
340
|
+
onMouseDown={onMouseDown}
|
|
341
|
+
onMouseUp={onMouseUp}
|
|
342
|
+
>
|
|
343
|
+
<div className={ATOMIX_GLASS.FILTER_CLASS}>
|
|
344
|
+
<GlassFilter
|
|
345
|
+
mode={mode}
|
|
346
|
+
id={filterId}
|
|
347
|
+
displacementScale={
|
|
348
|
+
typeof displacementScale === 'number' && !isNaN(displacementScale)
|
|
349
|
+
? displacementScale
|
|
350
|
+
: 0
|
|
351
|
+
}
|
|
352
|
+
aberrationIntensity={
|
|
353
|
+
typeof aberrationIntensity === 'number' && !isNaN(aberrationIntensity)
|
|
354
|
+
? aberrationIntensity
|
|
355
|
+
: 0
|
|
356
|
+
}
|
|
357
|
+
shaderMapUrl={shaderMapUrl}
|
|
358
|
+
/>
|
|
359
|
+
{/* Enhanced Apple Liquid Glass Inner Shadow Layer */}
|
|
360
|
+
|
|
361
|
+
<span
|
|
362
|
+
className={ATOMIX_GLASS.FILTER_OVERLAY_CLASS}
|
|
363
|
+
style={{
|
|
364
|
+
filter: `url(#${filterId})`,
|
|
365
|
+
backdropFilter: `var(--atomix-glass-container-backdrop)`,
|
|
366
|
+
borderRadius: `var(--atomix-glass-container-radius)`,
|
|
367
|
+
}}
|
|
368
|
+
/>
|
|
369
|
+
|
|
370
|
+
<div
|
|
371
|
+
className={ATOMIX_GLASS.FILTER_SHADOW_CLASS}
|
|
372
|
+
style={{
|
|
373
|
+
boxShadow: `var(--atomix-glass-container-shadow)`,
|
|
374
|
+
opacity: `var(--atomix-glass-container-shadow-opacity)`,
|
|
375
|
+
background: `var(--atomix-glass-container-bg)`,
|
|
376
|
+
borderRadius: `var(--atomix-glass-container-radius)`,
|
|
377
|
+
}}
|
|
378
|
+
/>
|
|
379
|
+
</div>
|
|
380
|
+
|
|
381
|
+
<div
|
|
382
|
+
ref={contentRef}
|
|
383
|
+
className={ATOMIX_GLASS.CONTENT_CLASS}
|
|
384
|
+
style={{
|
|
385
|
+
position: 'relative',
|
|
386
|
+
|
|
387
|
+
textShadow: `var(--atomix-glass-container-text-shadow)`,
|
|
388
|
+
...(elasticity > 0 ? { zIndex: 100 } : {}),
|
|
389
|
+
}}
|
|
390
|
+
>
|
|
391
|
+
{children}
|
|
392
|
+
</div>
|
|
393
|
+
</div>
|
|
394
|
+
</div>
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
AtomixGlassContainer.displayName = 'AtomixGlassContainer';
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { DisplacementMode } from '../../lib/types/components';
|
|
3
|
+
import type { FragmentShaderType } from './shader-utils';
|
|
4
|
+
import { getDisplacementMap } from './glass-utils';
|
|
5
|
+
import { displacementMap, polarDisplacementMap, prominentDisplacementMap } from './utils';
|
|
6
|
+
|
|
7
|
+
interface GlassFilterProps {
|
|
8
|
+
id: string;
|
|
9
|
+
displacementScale: number;
|
|
10
|
+
aberrationIntensity: number;
|
|
11
|
+
mode: DisplacementMode;
|
|
12
|
+
shaderMapUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* GlassFilter - SVG filter component for glass morphism effects
|
|
17
|
+
* Creates chromatic aberration and edge distortion effects using SVG filters
|
|
18
|
+
*/
|
|
19
|
+
export const GlassFilter: React.FC<GlassFilterProps> = ({
|
|
20
|
+
id,
|
|
21
|
+
displacementScale,
|
|
22
|
+
aberrationIntensity,
|
|
23
|
+
mode,
|
|
24
|
+
shaderMapUrl,
|
|
25
|
+
}) => (
|
|
26
|
+
<svg
|
|
27
|
+
style={{
|
|
28
|
+
position: 'absolute',
|
|
29
|
+
width: '100%',
|
|
30
|
+
height: '100%',
|
|
31
|
+
inset: 0,
|
|
32
|
+
visibility: 'hidden',
|
|
33
|
+
opacity: 0,
|
|
34
|
+
}}
|
|
35
|
+
aria-hidden="true"
|
|
36
|
+
>
|
|
37
|
+
<defs>
|
|
38
|
+
<radialGradient id={`${id}-edge-mask`} cx="50%" cy="50%" r="50%">
|
|
39
|
+
<stop offset="0%" stopColor="black" stopOpacity="0" />
|
|
40
|
+
<stop
|
|
41
|
+
offset={`${Math.max(30, 80 - aberrationIntensity * 2)}%`}
|
|
42
|
+
stopColor="black"
|
|
43
|
+
stopOpacity="0"
|
|
44
|
+
/>
|
|
45
|
+
<stop offset="100%" stopColor="white" stopOpacity="1" />
|
|
46
|
+
</radialGradient>
|
|
47
|
+
<filter id={id} x="-35%" y="-35%" width="170%" height="170%" colorInterpolationFilters="sRGB">
|
|
48
|
+
<feImage
|
|
49
|
+
id="feimage"
|
|
50
|
+
x="0"
|
|
51
|
+
y="0"
|
|
52
|
+
width="100%"
|
|
53
|
+
height="100%"
|
|
54
|
+
result="DISPLACEMENT_MAP"
|
|
55
|
+
href={getDisplacementMap(mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl)}
|
|
56
|
+
preserveAspectRatio="xMidYMid slice"
|
|
57
|
+
/>
|
|
58
|
+
|
|
59
|
+
<feColorMatrix
|
|
60
|
+
in="DISPLACEMENT_MAP"
|
|
61
|
+
type="matrix"
|
|
62
|
+
values="0.3 0.3 0.3 0 0
|
|
63
|
+
0.3 0.3 0.3 0 0
|
|
64
|
+
0.3 0.3 0.3 0 0
|
|
65
|
+
0 0 0 1 0"
|
|
66
|
+
result="EDGE_INTENSITY"
|
|
67
|
+
/>
|
|
68
|
+
<feComponentTransfer in="EDGE_INTENSITY" result="EDGE_MASK">
|
|
69
|
+
<feFuncA type="discrete" tableValues={`0 ${aberrationIntensity * 0.05} 1`} />
|
|
70
|
+
</feComponentTransfer>
|
|
71
|
+
|
|
72
|
+
<feOffset in="SourceGraphic" dx="0" dy="0" result="CENTER_ORIGINAL" />
|
|
73
|
+
|
|
74
|
+
<feDisplacementMap
|
|
75
|
+
in="SourceGraphic"
|
|
76
|
+
in2="DISPLACEMENT_MAP"
|
|
77
|
+
scale={displacementScale * (mode === 'shader' ? 1 : -1)}
|
|
78
|
+
xChannelSelector="R"
|
|
79
|
+
yChannelSelector="B"
|
|
80
|
+
result="RED_DISPLACED"
|
|
81
|
+
/>
|
|
82
|
+
<feColorMatrix
|
|
83
|
+
in="RED_DISPLACED"
|
|
84
|
+
type="matrix"
|
|
85
|
+
values="1 0 0 0 0
|
|
86
|
+
0 0 0 0 0
|
|
87
|
+
0 0 0 0 0
|
|
88
|
+
0 0 0 1 0"
|
|
89
|
+
result="RED_CHANNEL"
|
|
90
|
+
/>
|
|
91
|
+
|
|
92
|
+
<feDisplacementMap
|
|
93
|
+
in="SourceGraphic"
|
|
94
|
+
in2="DISPLACEMENT_MAP"
|
|
95
|
+
scale={displacementScale * ((mode === 'shader' ? 1 : -1) - aberrationIntensity * 0.02)}
|
|
96
|
+
xChannelSelector="R"
|
|
97
|
+
yChannelSelector="B"
|
|
98
|
+
result="GREEN_DISPLACED"
|
|
99
|
+
/>
|
|
100
|
+
<feColorMatrix
|
|
101
|
+
in="GREEN_DISPLACED"
|
|
102
|
+
type="matrix"
|
|
103
|
+
values="0 0 0 0 0
|
|
104
|
+
0 1 0 0 0
|
|
105
|
+
0 0 0 0 0
|
|
106
|
+
0 0 0 1 0"
|
|
107
|
+
result="GREEN_CHANNEL"
|
|
108
|
+
/>
|
|
109
|
+
|
|
110
|
+
<feDisplacementMap
|
|
111
|
+
in="SourceGraphic"
|
|
112
|
+
in2="DISPLACEMENT_MAP"
|
|
113
|
+
scale={displacementScale * ((mode === 'shader' ? 1 : -1) - aberrationIntensity * 0.03)}
|
|
114
|
+
xChannelSelector="R"
|
|
115
|
+
yChannelSelector="B"
|
|
116
|
+
result="BLUE_DISPLACED"
|
|
117
|
+
/>
|
|
118
|
+
<feColorMatrix
|
|
119
|
+
in="BLUE_DISPLACED"
|
|
120
|
+
type="matrix"
|
|
121
|
+
values="0 0 0 0 0
|
|
122
|
+
0 0 0 0 0
|
|
123
|
+
0 0 1 0 0
|
|
124
|
+
0 0 0 1 0"
|
|
125
|
+
result="BLUE_CHANNEL"
|
|
126
|
+
/>
|
|
127
|
+
|
|
128
|
+
<feBlend in="GREEN_CHANNEL" in2="BLUE_CHANNEL" mode="screen" result="GB_COMBINED" />
|
|
129
|
+
<feBlend in="RED_CHANNEL" in2="GB_COMBINED" mode="screen" result="RGB_COMBINED" />
|
|
130
|
+
|
|
131
|
+
{/* <feGaussianBlur
|
|
132
|
+
in="RGB_COMBINED"
|
|
133
|
+
stdDeviation='0'
|
|
134
|
+
result="ABERRATED_BLURRED"
|
|
135
|
+
/> */}
|
|
136
|
+
|
|
137
|
+
<feComposite
|
|
138
|
+
in="ABERRATED_BLURRED"
|
|
139
|
+
in2="EDGE_MASK"
|
|
140
|
+
operator="in"
|
|
141
|
+
result="EDGE_ABERRATION"
|
|
142
|
+
/>
|
|
143
|
+
|
|
144
|
+
<feComponentTransfer in="EDGE_MASK" result="INVERTED_MASK">
|
|
145
|
+
<feFuncA type="table" tableValues="1 0" />
|
|
146
|
+
</feComponentTransfer>
|
|
147
|
+
<feComposite in="CENTER_ORIGINAL" in2="INVERTED_MASK" operator="in" result="CENTER_CLEAN" />
|
|
148
|
+
|
|
149
|
+
<feComposite in="EDGE_ABERRATION" in2="CENTER_CLEAN" operator="over" />
|
|
150
|
+
</filter>
|
|
151
|
+
</defs>
|
|
152
|
+
</svg>
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
GlassFilter.displayName = 'GlassFilter';
|
|
156
|
+
|
|
@@ -51,7 +51,9 @@ function MyComponent() {
|
|
|
51
51
|
| `mouseContainer` | RefObject<HTMLElement> | null | Container to use for mouse position calculation |
|
|
52
52
|
| `padding` | number | 0 | Additional padding around the content |
|
|
53
53
|
| `style` | CSSProperties | {} | Additional CSS styles |
|
|
54
|
-
| `overLight` | boolean |
|
|
54
|
+
| `overLight` | boolean \| 'auto' \| OverLightObjectConfig | 'auto' | OverLight configuration. See [OverLight Configuration](#overlight-configuration) section for details |
|
|
55
|
+
| `enableOverLightLayers` | boolean | true | Whether to render additional overlay layers for overLight mode |
|
|
56
|
+
| `debugOverLight` | boolean | false | Enable debug logging for overLight detection and configuration |
|
|
55
57
|
| `mode` | 'standard' \| 'polar' \| 'prominent' \| 'shader' | 'standard' | The glass effect mode |
|
|
56
58
|
| `onClick` | function | undefined | Click handler |
|
|
57
59
|
| `showBorderEffects` | boolean | true | Whether to show border effects |
|
|
@@ -90,14 +92,134 @@ AtomixGlass is designed with accessibility in mind:
|
|
|
90
92
|
- Works with screen readers
|
|
91
93
|
- Includes reduced motion options for users with vestibular disorders
|
|
92
94
|
|
|
95
|
+
## OverLight Configuration
|
|
96
|
+
|
|
97
|
+
The `overLight` prop supports three configuration modes for handling glass effects on light backgrounds:
|
|
98
|
+
|
|
99
|
+
### Boolean Mode (Explicit Control)
|
|
100
|
+
|
|
101
|
+
Use `true` or `false` for direct control when you know the background state:
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
// Light background
|
|
105
|
+
<AtomixGlass overLight={true}>
|
|
106
|
+
<div>Content on light background</div>
|
|
107
|
+
</AtomixGlass>
|
|
108
|
+
|
|
109
|
+
// Dark background
|
|
110
|
+
<AtomixGlass overLight={false}>
|
|
111
|
+
<div>Content on dark background</div>
|
|
112
|
+
</AtomixGlass>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Use Cases:**
|
|
116
|
+
- When you know the background is light/dark
|
|
117
|
+
- When you want explicit control
|
|
118
|
+
- Performance-critical scenarios (avoids detection overhead)
|
|
119
|
+
|
|
120
|
+
### Auto-Detection Mode
|
|
121
|
+
|
|
122
|
+
Use `"auto"` to automatically detect background brightness:
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
<AtomixGlass overLight="auto">
|
|
126
|
+
<div>Content with auto-detected background</div>
|
|
127
|
+
</AtomixGlass>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**How it works:**
|
|
131
|
+
- Traverses parent elements (up to 20 levels deep)
|
|
132
|
+
- Samples up to 10 background elements
|
|
133
|
+
- Calculates average luminance using: `(0.299 * r + 0.587 * g + 0.114 * b) / 255`
|
|
134
|
+
- Compares against threshold (default: 0.7)
|
|
135
|
+
- Automatically enables overLight mode for light backgrounds
|
|
136
|
+
|
|
137
|
+
**Limitations:**
|
|
138
|
+
- 150ms delay for detection
|
|
139
|
+
- May not detect complex gradients accurately
|
|
140
|
+
- Image backgrounds assume medium luminance (0.5)
|
|
141
|
+
|
|
142
|
+
### Object Configuration Mode
|
|
143
|
+
|
|
144
|
+
Use an object to customize auto-detection with specific settings:
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
<AtomixGlass
|
|
148
|
+
overLight={{
|
|
149
|
+
threshold: 0.8, // Detection threshold (0.1 - 1.0)
|
|
150
|
+
opacity: 0.6, // Base opacity (0.1 - 1.0)
|
|
151
|
+
contrast: 1.8, // Contrast enhancement (0.5 - 2.5)
|
|
152
|
+
brightness: 1.0, // Brightness adjustment (0.5 - 2.0)
|
|
153
|
+
saturationBoost: 1.5 // Saturation multiplier (0.5 - 3.0)
|
|
154
|
+
}}
|
|
155
|
+
>
|
|
156
|
+
<div>Content with custom overLight config</div>
|
|
157
|
+
</AtomixGlass>
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Available Properties:**
|
|
161
|
+
|
|
162
|
+
| Property | Type | Range | Default | Description |
|
|
163
|
+
|----------|------|-------|---------|-------------|
|
|
164
|
+
| `threshold` | number | 0.1 - 1.0 | 0.7 | Luminance threshold for auto-detection |
|
|
165
|
+
| `opacity` | number | 0.1 - 1.0 | 0.5* | Base opacity (multiplied by hover/active intensity) |
|
|
166
|
+
| `contrast` | number | 0.5 - 2.5 | 1.4* | Contrast enhancement multiplier |
|
|
167
|
+
| `brightness` | number | 0.5 - 2.0 | 0.85* | Brightness adjustment multiplier |
|
|
168
|
+
| `saturationBoost` | number | 0.5 - 3.0 | 1.3* | Saturation multiplier |
|
|
169
|
+
|
|
170
|
+
\* Defaults are dynamic and depend on mouse influence, hover, and active states
|
|
171
|
+
|
|
172
|
+
**Example - Minimal Config:**
|
|
173
|
+
```tsx
|
|
174
|
+
// Only customize threshold
|
|
175
|
+
<AtomixGlass overLight={{ threshold: 0.8 }}>
|
|
176
|
+
<div>Content</div>
|
|
177
|
+
</AtomixGlass>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Example - Full Config:**
|
|
181
|
+
```tsx
|
|
182
|
+
// Customize all properties
|
|
183
|
+
<AtomixGlass
|
|
184
|
+
overLight={{
|
|
185
|
+
threshold: 0.75,
|
|
186
|
+
opacity: 0.6,
|
|
187
|
+
contrast: 1.8,
|
|
188
|
+
brightness: 1.1,
|
|
189
|
+
saturationBoost: 1.5
|
|
190
|
+
}}
|
|
191
|
+
>
|
|
192
|
+
<div>Content</div>
|
|
193
|
+
</AtomixGlass>
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Debug Mode
|
|
197
|
+
|
|
198
|
+
Enable `debugOverLight` to log detailed information about detection and configuration:
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
<AtomixGlass overLight="auto" debugOverLight={true}>
|
|
202
|
+
<div>Content with debug logging</div>
|
|
203
|
+
</AtomixGlass>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
This logs to console:
|
|
207
|
+
- Auto-detection results (luminance values, threshold comparison)
|
|
208
|
+
- Final overLight configuration values
|
|
209
|
+
- Detection timing and performance
|
|
210
|
+
|
|
93
211
|
## Best Practices
|
|
94
212
|
|
|
95
213
|
- Use AtomixGlass for important UI elements that need to stand out
|
|
96
214
|
- Avoid overusing glass effects which can create visual noise
|
|
97
215
|
- Ensure text on glass backgrounds has sufficient contrast
|
|
98
|
-
-
|
|
216
|
+
- Use `overLight="auto"` for dynamic backgrounds or when unsure
|
|
217
|
+
- Use `overLight={true}` or `overLight={false}` for known backgrounds (better performance)
|
|
218
|
+
- Use object config to fine-tune detection sensitivity and visual effects
|
|
219
|
+
- Enable `debugOverLight` when troubleshooting auto-detection issues
|
|
99
220
|
- Test glass effects across different devices and screen sizes
|
|
100
221
|
- Use appropriate `cornerRadius` values to match your design language
|
|
222
|
+
- Consider disabling `enableOverLightLayers` for performance optimization
|
|
101
223
|
|
|
102
224
|
## Customization
|
|
103
225
|
|