@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.
Files changed (214) hide show
  1. package/README.md +19 -0
  2. package/dist/atomix.css +1300 -1418
  3. package/dist/atomix.min.css +3 -3
  4. package/dist/index.d.ts +1259 -874
  5. package/dist/index.esm.js +16256 -26366
  6. package/dist/index.esm.js.map +1 -1
  7. package/dist/index.js +15691 -22295
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.min.js +1 -1
  10. package/dist/index.min.js.map +1 -1
  11. package/dist/themes/applemix.css +15036 -0
  12. package/dist/themes/applemix.min.css +72 -0
  13. package/dist/themes/boomdevs.css +1300 -1419
  14. package/dist/themes/boomdevs.min.css +3 -3
  15. package/dist/themes/esrar.css +1301 -1419
  16. package/dist/themes/esrar.min.css +3 -3
  17. package/dist/themes/flashtrade.css +15187 -0
  18. package/dist/themes/flashtrade.min.css +86 -0
  19. package/dist/themes/mashroom.css +1299 -1417
  20. package/dist/themes/mashroom.min.css +5 -5
  21. package/dist/themes/shaj-default.css +1300 -1418
  22. package/dist/themes/shaj-default.min.css +3 -3
  23. package/package.json +6 -17
  24. package/src/components/Accordion/Accordion.stories.tsx +4 -26
  25. package/src/components/Accordion/Accordion.tsx +21 -12
  26. package/src/components/AtomixGlass/AtomixGlass.test.tsx +106 -72
  27. package/src/components/AtomixGlass/AtomixGlass.tsx +485 -1215
  28. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +399 -0
  29. package/src/components/AtomixGlass/GlassFilter.tsx +156 -0
  30. package/src/components/AtomixGlass/README.md +124 -2
  31. package/src/components/AtomixGlass/atomixGLass.old.tsx +1266 -0
  32. package/src/components/AtomixGlass/glass-utils.ts +263 -0
  33. package/src/components/AtomixGlass/shader-utils.ts +404 -236
  34. package/src/components/AtomixGlass/{AtomixGlass.stories.tsx → stories/AtomixGlass.stories.tsx} +55 -35
  35. package/src/components/AtomixGlass/stories/Examples.stories.tsx +57 -89
  36. package/src/components/AtomixGlass/stories/Modes.stories.tsx +149 -149
  37. package/src/components/AtomixGlass/stories/Playground.stories.tsx +95 -32
  38. package/src/components/AtomixGlass/stories/ShaderVariants.stories.tsx +0 -2
  39. package/src/components/AtomixGlass/stories/shared-components.tsx +9 -18
  40. package/src/components/AtomixGlass/utils.ts +3 -3
  41. package/src/components/Avatar/Avatar.tsx +3 -0
  42. package/src/components/Avatar/AvatarGroup.tsx +2 -1
  43. package/src/components/Badge/Badge.stories.tsx +74 -54
  44. package/src/components/Badge/Badge.tsx +8 -12
  45. package/src/components/Breadcrumb/Breadcrumb.tsx +23 -4
  46. package/src/components/Button/Button.tsx +3 -5
  47. package/src/components/Callout/Callout.stories.tsx +86 -35
  48. package/src/components/Callout/Callout.tsx +4 -0
  49. package/src/components/Card/Card.stories.tsx +89 -85
  50. package/src/components/Card/Card.tsx +15 -4
  51. package/src/components/Card/ElevationCard.tsx +2 -0
  52. package/src/components/Chart/AnimatedChart.tsx +179 -156
  53. package/src/components/Chart/AreaChart.tsx +123 -12
  54. package/src/components/Chart/BarChart.tsx +91 -100
  55. package/src/components/Chart/BaseChart.tsx +80 -0
  56. package/src/components/Chart/BubbleChart.tsx +114 -290
  57. package/src/components/Chart/CandlestickChart.tsx +282 -622
  58. package/src/components/Chart/Chart.stories.tsx +576 -179
  59. package/src/components/Chart/Chart.tsx +374 -75
  60. package/src/components/Chart/ChartRenderer.tsx +371 -220
  61. package/src/components/Chart/ChartToolbar.tsx +372 -61
  62. package/src/components/Chart/ChartTooltip.tsx +33 -18
  63. package/src/components/Chart/DonutChart.tsx +172 -254
  64. package/src/components/Chart/FunnelChart.tsx +169 -240
  65. package/src/components/Chart/GaugeChart.tsx +224 -392
  66. package/src/components/Chart/HeatmapChart.tsx +302 -440
  67. package/src/components/Chart/LineChart.tsx +148 -103
  68. package/src/components/Chart/MultiAxisChart.tsx +267 -395
  69. package/src/components/Chart/PieChart.tsx +114 -64
  70. package/src/components/Chart/RadarChart.tsx +202 -218
  71. package/src/components/Chart/ScatterChart.tsx +111 -97
  72. package/src/components/Chart/TreemapChart.tsx +147 -222
  73. package/src/components/Chart/WaterfallChart.tsx +253 -291
  74. package/src/components/Chart/index.ts +11 -9
  75. package/src/components/Chart/types.ts +85 -9
  76. package/src/components/Chart/utils.ts +66 -0
  77. package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +121 -11
  78. package/src/components/ColorModeToggle/ColorModeToggle.tsx +149 -45
  79. package/src/components/ColorModeToggle/index.ts +1 -1
  80. package/src/components/Countdown/Countdown.tsx +4 -0
  81. package/src/components/DataTable/DataTable.tsx +2 -1
  82. package/src/components/DatePicker/DatePicker.stories.tsx +0 -11
  83. package/src/components/DatePicker/DatePicker.tsx +3 -9
  84. package/src/components/DatePicker/types.ts +5 -0
  85. package/src/components/Dropdown/Dropdown.stories.tsx +32 -25
  86. package/src/components/Dropdown/Dropdown.tsx +26 -28
  87. package/src/components/EdgePanel/EdgePanel.stories.tsx +13 -15
  88. package/src/components/EdgePanel/EdgePanel.tsx +20 -5
  89. package/src/components/Footer/Footer.stories.tsx +187 -60
  90. package/src/components/Footer/Footer.test.tsx +134 -0
  91. package/src/components/Footer/Footer.tsx +133 -34
  92. package/src/components/Footer/FooterLink.tsx +1 -1
  93. package/src/components/Footer/FooterSection.tsx +53 -36
  94. package/src/components/Footer/FooterSocialLink.tsx +32 -29
  95. package/src/components/Footer/README.md +82 -3
  96. package/src/components/Footer/index.ts +1 -1
  97. package/src/components/Form/Checkbox.stories.tsx +13 -5
  98. package/src/components/Form/Checkbox.tsx +3 -6
  99. package/src/components/Form/Form.stories.tsx +10 -3
  100. package/src/components/Form/Form.tsx +2 -0
  101. package/src/components/Form/FormGroup.tsx +2 -1
  102. package/src/components/Form/Input.stories.tsx +12 -11
  103. package/src/components/Form/Input.tsx +97 -95
  104. package/src/components/Form/Radio.stories.tsx +22 -7
  105. package/src/components/Form/Radio.tsx +3 -6
  106. package/src/components/Form/Select.stories.tsx +21 -6
  107. package/src/components/Form/Select.tsx +3 -5
  108. package/src/components/Form/Textarea.stories.tsx +13 -11
  109. package/src/components/Form/Textarea.tsx +88 -86
  110. package/src/components/Hero/Hero.stories.tsx +2 -3
  111. package/src/components/Hero/Hero.tsx +5 -6
  112. package/src/components/Icon/Icon.tsx +12 -1
  113. package/src/components/List/List.tsx +2 -1
  114. package/src/components/List/ListGroup.tsx +2 -1
  115. package/src/components/Messages/Messages.tsx +3 -2
  116. package/src/components/Modal/Modal.stories.tsx +48 -34
  117. package/src/components/Modal/Modal.tsx +19 -23
  118. package/src/components/Navigation/Menu/MegaMenu.tsx +2 -2
  119. package/src/components/Navigation/Menu/Menu.tsx +2 -2
  120. package/src/components/Navigation/Nav/Nav.tsx +6 -1
  121. package/src/components/Navigation/Nav/NavDropdown.tsx +10 -1
  122. package/src/components/Navigation/Navbar/Navbar.tsx +4 -1
  123. package/src/components/Navigation/SideMenu/SideMenu.tsx +3 -2
  124. package/src/components/Pagination/Pagination.stories.tsx +13 -6
  125. package/src/components/Pagination/Pagination.tsx +7 -6
  126. package/src/components/PhotoViewer/PhotoViewer.tsx +2 -1
  127. package/src/components/Popover/Popover.stories.tsx +32 -24
  128. package/src/components/Popover/Popover.tsx +4 -1
  129. package/src/components/ProductReview/ProductReview.tsx +8 -2
  130. package/src/components/Progress/Progress.tsx +2 -1
  131. package/src/components/Rating/Rating.stories.tsx +11 -6
  132. package/src/components/Rating/Rating.tsx +3 -5
  133. package/src/components/River/River.tsx +5 -5
  134. package/src/components/SectionIntro/SectionIntro.tsx +8 -2
  135. package/src/components/Slider/Slider.stories.tsx +4 -4
  136. package/src/components/Slider/Slider.tsx +4 -3
  137. package/src/components/Spinner/Spinner.tsx +2 -1
  138. package/src/components/Steps/Steps.stories.tsx +5 -4
  139. package/src/components/Steps/Steps.tsx +8 -5
  140. package/src/components/Tab/Tab.stories.tsx +4 -3
  141. package/src/components/Tab/Tab.tsx +8 -6
  142. package/src/components/Testimonial/Testimonial.tsx +8 -2
  143. package/src/components/Todo/Todo.tsx +2 -1
  144. package/src/components/Toggle/Toggle.stories.tsx +5 -4
  145. package/src/components/Toggle/Toggle.tsx +8 -5
  146. package/src/components/Tooltip/Tooltip.stories.tsx +40 -30
  147. package/src/components/Tooltip/Tooltip.tsx +9 -2
  148. package/src/components/Upload/Upload.stories.tsx +252 -0
  149. package/src/components/Upload/Upload.tsx +92 -53
  150. package/src/components/VideoPlayer/VideoPlayer.tsx +3 -1
  151. package/src/components/index.ts +0 -4
  152. package/src/layouts/Grid/Grid.stories.tsx +10 -23
  153. package/src/layouts/Grid/Grid.tsx +20 -1
  154. package/src/layouts/Grid/GridCol.tsx +76 -48
  155. package/src/lib/composables/useAtomixGlass.ts +861 -44
  156. package/src/lib/composables/useBarChart.ts +13 -6
  157. package/src/lib/composables/useChart.ts +17 -13
  158. package/src/lib/composables/useChartExport.ts +19 -78
  159. package/src/lib/composables/useChartToolbar.ts +0 -1
  160. package/src/lib/composables/useEdgePanel.ts +111 -103
  161. package/src/lib/composables/useFooter.ts +3 -3
  162. package/src/lib/composables/useGlassContainer.ts +16 -7
  163. package/src/lib/composables/useLineChart.ts +8 -1
  164. package/src/lib/composables/useRiver.ts +5 -0
  165. package/src/lib/composables/useSlider.ts +62 -24
  166. package/src/lib/composables/useVideoPlayer.ts +60 -63
  167. package/src/lib/constants/components.ts +146 -32
  168. package/src/lib/types/components.ts +258 -10
  169. package/src/lib/utils/displacement-generator.ts +55 -49
  170. package/src/lib/utils/icons.ts +1 -1
  171. package/src/lib/utils/index.ts +16 -10
  172. package/src/styles/01-settings/_settings.accordion.scss +19 -19
  173. package/src/styles/01-settings/_settings.animations.scss +5 -5
  174. package/src/styles/01-settings/_settings.avatar-group.scss +1 -1
  175. package/src/styles/01-settings/_settings.avatar.scss +17 -17
  176. package/src/styles/01-settings/_settings.background.scss +1 -4
  177. package/src/styles/01-settings/_settings.badge.scss +1 -1
  178. package/src/styles/01-settings/_settings.breadcrumb.scss +1 -1
  179. package/src/styles/01-settings/_settings.card.scss +1 -1
  180. package/src/styles/01-settings/_settings.chart.scss +65 -2
  181. package/src/styles/01-settings/_settings.dropdown.scss +1 -1
  182. package/src/styles/01-settings/_settings.footer.scss +35 -42
  183. package/src/styles/01-settings/_settings.input.scss +1 -1
  184. package/src/styles/01-settings/_settings.list.scss +1 -1
  185. package/src/styles/01-settings/_settings.rating.scss +1 -1
  186. package/src/styles/01-settings/_settings.tabs.scss +1 -1
  187. package/src/styles/01-settings/_settings.upload.scss +6 -5
  188. package/src/styles/02-tools/_tools.animations.scss +4 -5
  189. package/src/styles/02-tools/_tools.background.scss +1 -13
  190. package/src/styles/02-tools/_tools.glass.scss +0 -1
  191. package/src/styles/02-tools/_tools.utility-api.scss +42 -34
  192. package/src/styles/03-generic/_generic.root.scss +1 -4
  193. package/src/styles/04-elements/_elements.body.scss +0 -1
  194. package/src/styles/06-components/_components.atomix-glass.scss +217 -39
  195. package/src/styles/06-components/_components.badge.scss +6 -8
  196. package/src/styles/06-components/_components.button.scss +8 -3
  197. package/src/styles/06-components/_components.card.scss +2 -14
  198. package/src/styles/06-components/_components.chart.scss +969 -1449
  199. package/src/styles/06-components/_components.color-mode-toggle.scss +43 -6
  200. package/src/styles/06-components/_components.dropdown.scss +19 -7
  201. package/src/styles/06-components/_components.edge-panel.scss +4 -2
  202. package/src/styles/06-components/_components.footer.scss +166 -85
  203. package/src/styles/06-components/_components.input.scss +8 -9
  204. package/src/styles/06-components/_components.list.scss +1 -0
  205. package/src/styles/06-components/_components.modal.scss +5 -3
  206. package/src/styles/06-components/_components.skeleton.scss +8 -6
  207. package/src/styles/06-components/_components.upload.scss +219 -4
  208. package/src/styles/06-components/old.chart.styles.scss +1 -30
  209. package/src/styles/99-utilities/_utilities.opacity.scss +1 -1
  210. package/src/styles/99-utilities/_utilities.scss +1 -1
  211. package/src/components/Chart/AdvancedChart.tsx +0 -624
  212. package/src/components/Chart/LineChartNew.tsx +0 -167
  213. package/src/components/Chart/RealTimeChart.tsx +0 -436
  214. 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 | false | Whether the glass is over a light background |
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
- - Consider using the `overLight` prop when placing glass over light backgrounds
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