@shohojdhara/atomix 0.6.1 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +510 -106
  2. package/dist/atomix.css +30 -24
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +6 -6
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/atomix.umd.js +1 -1
  7. package/dist/atomix.umd.js.map +1 -1
  8. package/dist/atomix.umd.min.js +1 -1
  9. package/dist/charts.d.ts +11 -2
  10. package/dist/charts.js +294 -139
  11. package/dist/charts.js.map +1 -1
  12. package/dist/core.d.ts +14 -39
  13. package/dist/core.js +297 -145
  14. package/dist/core.js.map +1 -1
  15. package/dist/forms.d.ts +11 -1
  16. package/dist/forms.js +385 -185
  17. package/dist/forms.js.map +1 -1
  18. package/dist/heavy.d.ts +9 -0
  19. package/dist/heavy.js +297 -143
  20. package/dist/heavy.js.map +1 -1
  21. package/dist/index.d.ts +156 -164
  22. package/dist/index.esm.js +391 -203
  23. package/dist/index.esm.js.map +1 -1
  24. package/dist/index.js +391 -203
  25. package/dist/index.js.map +1 -1
  26. package/dist/index.min.js +1 -1
  27. package/dist/index.min.js.map +1 -1
  28. package/dist/theme.d.ts +14 -6
  29. package/dist/theme.js +2 -9
  30. package/dist/theme.js.map +1 -1
  31. package/package.json +26 -26
  32. package/src/components/AtomixGlass/AtomixGlass.tsx +1 -1
  33. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +8 -1
  34. package/src/components/AtomixGlass/deprecated/AtomixGlass.deprecated.tsx +390 -0
  35. package/src/components/AtomixGlass/glass-utils.ts +29 -0
  36. package/src/components/AtomixGlass/stories/Playground.stories.tsx +32 -1
  37. package/src/components/Button/Button.stories.tsx +1 -1
  38. package/src/components/Button/Button.tsx +6 -5
  39. package/src/components/Card/Card.tsx +2 -2
  40. package/src/components/Dropdown/Dropdown.tsx +1 -0
  41. package/src/components/EdgePanel/EdgePanel.tsx +1 -3
  42. package/src/components/Form/Select.test.tsx +75 -0
  43. package/src/components/Form/Select.tsx +348 -252
  44. package/src/components/Form/SelectOption.tsx +16 -10
  45. package/src/components/index.ts +1 -1
  46. package/src/layouts/CssGrid/index.ts +1 -0
  47. package/src/lib/composables/shared-mouse-tracker.ts +62 -6
  48. package/src/lib/composables/useAtomixGlass.ts +241 -139
  49. package/src/lib/composables/useAtomixGlassStyles.ts +201 -149
  50. package/src/lib/constants/components.ts +54 -35
  51. package/src/lib/theme/config/configLoader.ts +1 -1
  52. package/src/lib/theme/test/testTheme.ts +2 -2
  53. package/src/lib/theme/utils/themeUtils.ts +98 -110
  54. package/src/lib/types/components.ts +29 -65
  55. package/src/styles/01-settings/_settings.spacing.scss +6 -1
  56. package/src/styles/03-generic/_generic.reset.scss +1 -1
  57. package/src/styles/06-components/_components.atomix-glass.scss +20 -29
  58. package/src/styles/06-components/_components.data-table.scss +5 -4
  59. package/src/styles/06-components/_components.dynamic-background.scss +9 -8
  60. package/src/styles/06-components/_components.footer.scss +8 -7
  61. package/src/styles/06-components/_components.hero.scss +2 -2
  62. package/src/styles/06-components/_components.messages.scss +16 -16
  63. package/src/styles/06-components/_components.navbar.scss +2 -0
  64. package/src/styles/06-components/_components.select.scss +15 -2
  65. package/src/styles/06-components/_components.upload.scss +3 -3
  66. package/CHANGELOG.md +0 -165
  67. package/src/lib/theme/devtools/DesignTokensCustomizer.stories.tsx +0 -215
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shohojdhara/atomix",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "description": "Atomix Design System - A modern component library for web applications",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -162,24 +162,24 @@
162
162
  "@rollup/plugin-node-resolve": "^15.0.0",
163
163
  "@rollup/plugin-terser": "^0.4.0",
164
164
  "@rollup/plugin-typescript": "^11.0.0",
165
- "@storybook/addon-a11y": "^8.6.14",
166
- "@storybook/addon-essentials": "^8.6.14",
167
- "@storybook/addon-interactions": "^8.6.14",
168
- "@storybook/addon-links": "^8.6.14",
169
- "@storybook/addon-measure": "^8.6.14",
170
- "@storybook/addon-outline": "^8.6.14",
171
- "@storybook/addon-viewport": "^8.6.14",
172
- "@storybook/blocks": "^8.6.14",
173
- "@storybook/cli": "^8.6.14",
174
- "@storybook/components": "^8.6.14",
175
- "@storybook/core-events": "^8.6.14",
176
- "@storybook/manager-api": "^8.6.14",
177
- "@storybook/preview-api": "^8.6.14",
178
- "@storybook/react": "^8.6.14",
179
- "@storybook/react-vite": "^8.6.14",
180
- "@storybook/test": "^8.6.14",
181
- "@storybook/theming": "^8.6.14",
182
- "@storybook/types": "^8.6.14",
165
+ "@storybook/addon-a11y": "8.6.15",
166
+ "@storybook/addon-essentials": "8.6.15",
167
+ "@storybook/addon-interactions": "8.6.15",
168
+ "@storybook/addon-links": "8.6.15",
169
+ "@storybook/addon-measure": "8.6.15",
170
+ "@storybook/addon-outline": "8.6.15",
171
+ "@storybook/addon-viewport": "8.6.15",
172
+ "@storybook/blocks": "8.6.15",
173
+ "@storybook/cli": "8.6.15",
174
+ "@storybook/components": "8.6.15",
175
+ "@storybook/core-events": "8.6.15",
176
+ "@storybook/manager-api": "8.6.15",
177
+ "@storybook/preview-api": "8.6.15",
178
+ "@storybook/react": "8.6.15",
179
+ "@storybook/react-vite": "8.6.15",
180
+ "@storybook/test": "8.6.15",
181
+ "@storybook/theming": "8.6.15",
182
+ "@storybook/types": "8.6.15",
183
183
  "@testing-library/dom": "^8.0.0",
184
184
  "@testing-library/jest-dom": "^5.16.0",
185
185
  "@testing-library/react": "^14.0.0",
@@ -216,7 +216,7 @@
216
216
  "rollup-plugin-postcss": "^4.0.0",
217
217
  "rollup-plugin-preserve-shebangs": "^0.2.0",
218
218
  "rollup-plugin-visualizer": "^5.12.0",
219
- "storybook": "^8.6.14",
219
+ "storybook": "8.6.15",
220
220
  "storybook-theme-switch-addon": "^1.0.2",
221
221
  "ts-node": "^10.9.0",
222
222
  "tslib": "^2.6.0",
@@ -229,14 +229,14 @@
229
229
  "dev": "storybook dev -p 6006",
230
230
  "build": "npm run prebuild && npm run build:parallel && npm run postbuild",
231
231
  "build:sequential": "rollup -c",
232
- "build:js": "rollup -c rollup.config.build.js",
233
- "build:types": "rollup -c rollup.config.types.js",
234
- "build:styles": "rollup -c rollup.config.styles.js",
232
+ "build:js": "rollup -c rollup/entries/build.js",
233
+ "build:types": "rollup -c rollup/entries/types.js",
234
+ "build:styles": "rollup -c rollup/entries/styles.js",
235
235
  "build:themes": "rollup -c rollup/config/themes.js",
236
236
  "build:parallel": "concurrently \"npm:build:js\" \"npm:build:types\" \"npm:build:styles\" \"npm:build:umd\"",
237
- "build:umd": "rollup -c rollup.config.umd.js",
238
- "build:cli": "rollup -c rollup.config.cli.js",
239
- "build:cli:dev": "rollup -c rollup.config.cli.js --environment NODE_ENV:development",
237
+ "build:umd": "rollup -c rollup/entries/umd.js",
238
+ "build:cli": "rollup -c rollup/entries/cli.js",
239
+ "build:cli:dev": "rollup -c rollup/entries/cli.js --environment NODE_ENV:development",
240
240
  "build:analyze": "ANALYZE=true rollup -c",
241
241
  "build:storybook": "storybook build",
242
242
  "test": "vitest",
@@ -576,7 +576,7 @@ const AtomixGlassInner = forwardRef<HTMLDivElement, AtomixGlassProps>(function A
576
576
  aria-label={ariaLabel}
577
577
  aria-describedby={ariaDescribedBy}
578
578
  aria-disabled={onClick && effectiveWithoutEffects ? true : onClick ? false : undefined}
579
- aria-pressed={undefined}
579
+ aria-pressed={onClick ? isActive : undefined}
580
580
  onKeyDown={onClick ? handleKeyDown : undefined}
581
581
  >
582
582
  <AtomixGlassContainer
@@ -89,6 +89,7 @@ interface AtomixGlassContainerProps
89
89
  shaderVariant?: FragmentShaderType;
90
90
  withLiquidBlur?: boolean;
91
91
  isFixedOrSticky?: boolean;
92
+ elasticity?: number;
92
93
 
93
94
  // Phase 1: Animation System props
94
95
  shaderTime?: number;
@@ -592,7 +593,13 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
592
593
  <div className={ATOMIX_GLASS.FILTER_SHADOW_CLASS} />
593
594
  </div>
594
595
 
595
- <div ref={contentRef} className={ATOMIX_GLASS.CONTENT_CLASS}>
596
+ <div
597
+ ref={contentRef}
598
+ className={ATOMIX_GLASS.CONTENT_CLASS}
599
+ style={{
600
+ transform: 'var(--atomix-glass-child-parallax, none)',
601
+ }}
602
+ >
596
603
  {children}
597
604
  </div>
598
605
  </div>
@@ -0,0 +1,390 @@
1
+ import React, { useId, useMemo, useRef } from 'react';
2
+ import type { AtomixGlassProps } from '../../../lib/types/components';
3
+ import { ATOMIX_GLASS } from '../../../lib/constants/components';
4
+ import { AtomixGlassContainer } from '../AtomixGlassContainer';
5
+ import { useAtomixGlass } from '../../../lib/composables/useAtomixGlass';
6
+
7
+ /**
8
+ * AtomixGlass - A high-performance glass morphism component with liquid distortion effects
9
+ *
10
+ * Features:
11
+ * - Hardware-accelerated glass effects with SVG filters
12
+ * - Mouse-responsive liquid distortion
13
+ * - Dynamic border-radius extraction from children CSS properties
14
+ * - Automatic light/dark theme detection
15
+ * - Accessibility and performance optimizations
16
+ * - Multiple displacement modes (standard, polar, prominent, shader)
17
+ *
18
+ * @example
19
+ * // Dynamic border-radius extraction
20
+ * <AtomixGlass>
21
+ * <div style={{ borderRadius: '12px' }}>Content with 12px radius</div>
22
+ * </AtomixGlass>
23
+ *
24
+ * @example
25
+ * // Manual border-radius override
26
+ * <AtomixGlass cornerRadius={20}>
27
+ * <div>Content with 20px glass radius</div>
28
+ * </AtomixGlass>
29
+ */
30
+ export function AtomixGlass({
31
+ children,
32
+ displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE,
33
+ blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT,
34
+ saturation = ATOMIX_GLASS.DEFAULTS.SATURATION,
35
+ aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY,
36
+ elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY,
37
+ borderRadius,
38
+ globalMousePosition: externalGlobalMousePosition,
39
+ mouseOffset: externalMouseOffset,
40
+ mouseContainer = null,
41
+ className = '',
42
+ padding = ATOMIX_GLASS.DEFAULTS.PADDING,
43
+ overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT,
44
+ style = {},
45
+ mode = ATOMIX_GLASS.DEFAULTS.MODE,
46
+ onClick,
47
+ shaderVariant = 'liquidGlass',
48
+ 'aria-label': ariaLabel,
49
+ 'aria-describedby': ariaDescribedBy,
50
+ role,
51
+ tabIndex,
52
+ reducedMotion = false,
53
+ highContrast = false,
54
+ withoutEffects = false,
55
+ withLiquidBlur = false,
56
+ withBorder = true,
57
+ withOverLightLayers = false,
58
+ debugBorderRadius = false,
59
+ }: AtomixGlassProps) {
60
+ const glassRef = useRef<HTMLDivElement>(null);
61
+ const contentRef = useRef<HTMLDivElement>(null);
62
+
63
+ // Use composable hook for all state and logic
64
+ const {
65
+ isHovered,
66
+ isActive,
67
+ glassSize,
68
+ effectiveBorderRadius,
69
+ effectiveReducedMotion,
70
+ effectiveHighContrast,
71
+ effectiveWithoutEffects,
72
+ overLightConfig,
73
+ globalMousePosition,
74
+ mouseOffset,
75
+ transformStyle,
76
+ handleMouseEnter,
77
+ handleMouseLeave,
78
+ handleMouseDown,
79
+ handleMouseUp,
80
+ handleKeyDown,
81
+ } = useAtomixGlass({
82
+ glassRef,
83
+ contentRef,
84
+ borderRadius,
85
+ globalMousePosition: externalGlobalMousePosition,
86
+ mouseOffset: externalMouseOffset,
87
+ mouseContainer,
88
+ overLight,
89
+ reducedMotion,
90
+ highContrast,
91
+ withoutEffects,
92
+ elasticity,
93
+ onClick,
94
+ debugBorderRadius,
95
+ children,
96
+ });
97
+
98
+ // Calculate base style with transforms
99
+ const baseStyle = useMemo(
100
+ () => ({
101
+ ...style,
102
+ ...(elasticity !== 0 && {
103
+ transform: transformStyle,
104
+ transition: effectiveReducedMotion ? 'none' : 'all ease-out 0.2s',
105
+ willChange: effectiveWithoutEffects ? 'auto' : 'transform',
106
+ }),
107
+ ...(effectiveHighContrast && {
108
+ border: '2px solid currentColor',
109
+ outline: '2px solid transparent',
110
+ outlineOffset: '2px',
111
+ }),
112
+ }),
113
+ [
114
+ style,
115
+ transformStyle,
116
+ effectiveReducedMotion,
117
+ effectiveWithoutEffects,
118
+ effectiveHighContrast,
119
+ elasticity,
120
+ ]
121
+ );
122
+
123
+ // Calculate position and size styles
124
+ const positionStyles = useMemo(
125
+ () => ({
126
+ position: (baseStyle.position || 'absolute') as React.CSSProperties['position'],
127
+ top: baseStyle.top || 0,
128
+ left: baseStyle.left || 0,
129
+ }),
130
+ [baseStyle]
131
+ );
132
+
133
+ const adjustedSize = useMemo(
134
+ () => ({
135
+ width:
136
+ baseStyle.position !== 'fixed'
137
+ ? '100%'
138
+ : baseStyle.width
139
+ ? baseStyle.width
140
+ : Math.max(glassSize.width, 0),
141
+ height:
142
+ baseStyle.position !== 'fixed'
143
+ ? '100%'
144
+ : baseStyle.height
145
+ ? baseStyle.height
146
+ : Math.max(glassSize.height, 0),
147
+ }),
148
+ [baseStyle, glassSize]
149
+ );
150
+
151
+ // Generate CSS variables for layers
152
+ const glassId = useId();
153
+ const glassVars = useMemo(() => {
154
+ const isOverLight = overLightConfig?.isOverLight ?? false;
155
+ const mx = mouseOffset.x;
156
+ const my = mouseOffset.y;
157
+ const scopedId = `ag-${glassId.replace(/:/g, '')}`;
158
+
159
+ return {
160
+ [`--${scopedId}-pos`]: positionStyles.position,
161
+ [`--${scopedId}-top`]: positionStyles.top !== 'fixed' ? `${positionStyles.top}px` : '0',
162
+ [`--${scopedId}-left`]: positionStyles.left !== 'fixed' ? `${positionStyles.left}px` : '0',
163
+ [`--${scopedId}-w`]:
164
+ baseStyle.position !== 'fixed' ? adjustedSize.width : `${adjustedSize.width}px`,
165
+ [`--${scopedId}-h`]:
166
+ baseStyle.position !== 'fixed' ? adjustedSize.height : `${adjustedSize.height}px`,
167
+ [`--${scopedId}-r`]: `${effectiveBorderRadius}px`,
168
+ [`--${scopedId}-t`]: baseStyle.transform,
169
+ [`--${scopedId}-tr`]: effectiveReducedMotion ? 'none' : baseStyle.transition,
170
+ [`--${scopedId}-blend`]: isOverLight ? 'multiply' : 'overlay',
171
+ [`--${scopedId}-b1`]: `linear-gradient(${135 + mx * 1.2}deg, rgba(255,255,255,0) 0%, rgba(255,255,255,${0.12 + Math.abs(mx) * 0.008}) ${Math.max(10, 33 + my * 0.3)}%, rgba(255,255,255,${0.4 + Math.abs(mx) * 0.012}) ${Math.min(90, 66 + my * 0.4)}%, rgba(255,255,255,0) 100%)`,
172
+ [`--${scopedId}-b2`]: `linear-gradient(${135 + mx * 1.2}deg, rgba(255,255,255,0) 0%, rgba(255,255,255,${0.32 + Math.abs(mx) * 0.008}) ${Math.max(10, 33 + my * 0.3)}%, rgba(255,255,255,${0.6 + Math.abs(mx) * 0.012}) ${Math.min(90, 66 + my * 0.4)}%, rgba(255,255,255,0) 100%)`,
173
+ [`--${scopedId}-h1-o`]: isHovered || isActive ? (isOverLight ? 0.3 : 0.5) : 0,
174
+ [`--${scopedId}-h1`]: isOverLight
175
+ ? `radial-gradient(circle at ${50 + mx / 2}% ${50 + my / 2}%, rgba(0,0,0,0.2) 0%, rgba(0,0,0,0.05) 30%, rgba(0,0,0,0) 60%)`
176
+ : `radial-gradient(circle at ${50 + mx / 2}% ${50 + my / 2}%, rgba(255,255,255,0.5) 0%, rgba(255,255,255,0) 50%)`,
177
+ [`--${scopedId}-h2-o`]: isActive ? (isOverLight ? 0.4 : 0.5) : 0,
178
+ [`--${scopedId}-h2`]: isOverLight
179
+ ? `radial-gradient(circle at ${50 + mx / 1.5}% ${50 + my / 1.5}%, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.1) 40%, rgba(0,0,0,0) 80%)`
180
+ : `radial-gradient(circle at ${50 + mx / 1.5}% ${50 + my / 1.5}%, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 80%)`,
181
+ [`--${scopedId}-h3-o`]: isHovered
182
+ ? isOverLight
183
+ ? 0.25
184
+ : 0.4
185
+ : isActive
186
+ ? isOverLight
187
+ ? 0.5
188
+ : 0.8
189
+ : 0,
190
+ [`--${scopedId}-h3`]: isOverLight
191
+ ? `radial-gradient(circle at ${50 + mx}% ${50 + my}%, rgba(0,0,0,0.4) 0%, rgba(0,0,0,0.1) 50%, rgba(0,0,0,0) 100%)`
192
+ : `radial-gradient(circle at ${50 + mx}% ${50 + my}%, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%)`,
193
+ [`--${scopedId}-base-o`]: isOverLight ? overLightConfig.opacity : 0,
194
+ [`--${scopedId}-base`]: isOverLight
195
+ ? `linear-gradient(135deg, rgba(0,0,0,${0.12 + mx * 0.002}) 0%, rgba(0,0,0,${0.08 + my * 0.001}) 50%, rgba(0,0,0,${0.15 + Math.abs(mx) * 0.003}) 100%)`
196
+ : 'rgba(255,255,255,0.1)',
197
+ [`--${scopedId}-over-o`]: isOverLight ? overLightConfig.opacity * 0.9 : 0,
198
+ [`--${scopedId}-over`]: isOverLight
199
+ ? `radial-gradient(circle at ${50 + mx * 0.5}% ${50 + my * 0.5}%, rgba(0,0,0,${0.08 + Math.abs(mx) * 0.002}) 0%, rgba(0,0,0,0.04) 40%, rgba(0,0,0,${0.12 + Math.abs(my) * 0.002}) 100%)`
200
+ : 'rgba(255,255,255,0.05)',
201
+ '--ag-scoped-id': scopedId,
202
+ } as React.CSSProperties;
203
+ }, [
204
+ glassId,
205
+ positionStyles,
206
+ adjustedSize,
207
+ effectiveBorderRadius,
208
+ baseStyle,
209
+ effectiveReducedMotion,
210
+ mouseOffset,
211
+ isHovered,
212
+ isActive,
213
+ overLightConfig,
214
+ ]);
215
+
216
+ const scopedId = `ag-${glassId.replace(/:/g, '')}`;
217
+
218
+ return (
219
+ <div
220
+ className={`${ATOMIX_GLASS.BASE_CLASS} ${className}`}
221
+ style={{ ...positionStyles, position: 'relative', ...glassVars }}
222
+ role={role || (onClick ? 'button' : undefined)}
223
+ tabIndex={onClick ? (tabIndex ?? 0) : tabIndex}
224
+ aria-label={ariaLabel}
225
+ aria-describedby={ariaDescribedBy}
226
+ aria-disabled={onClick ? false : undefined}
227
+ onKeyDown={onClick ? handleKeyDown : undefined}
228
+ >
229
+ <AtomixGlassContainer
230
+ ref={glassRef}
231
+ contentRef={contentRef}
232
+ className={className}
233
+ style={baseStyle}
234
+ borderRadius={effectiveBorderRadius}
235
+ displacementScale={
236
+ effectiveWithoutEffects
237
+ ? 0
238
+ : mode === 'shader'
239
+ ? displacementScale * 0.8
240
+ : overLightConfig.isOverLight
241
+ ? displacementScale * 0.6
242
+ : displacementScale
243
+ }
244
+ blurAmount={effectiveWithoutEffects ? 0 : blurAmount}
245
+ saturation={
246
+ effectiveHighContrast
247
+ ? 200
248
+ : overLightConfig.isOverLight
249
+ ? saturation * overLightConfig.saturationBoost
250
+ : saturation
251
+ }
252
+ aberrationIntensity={
253
+ effectiveWithoutEffects
254
+ ? 0
255
+ : mode === 'shader'
256
+ ? aberrationIntensity * 0.7
257
+ : aberrationIntensity
258
+ }
259
+ glassSize={glassSize}
260
+ padding={padding}
261
+ mouseOffset={effectiveWithoutEffects ? { x: 0, y: 0 } : mouseOffset}
262
+ globalMousePosition={effectiveWithoutEffects ? { x: 0, y: 0 } : globalMousePosition}
263
+ onMouseEnter={handleMouseEnter}
264
+ onMouseLeave={handleMouseLeave}
265
+ onMouseDown={handleMouseDown}
266
+ onMouseUp={handleMouseUp}
267
+ isHovered={isHovered}
268
+ isActive={isActive}
269
+ overLight={overLightConfig?.isOverLight || false}
270
+ onClick={onClick}
271
+ mode={mode}
272
+ transform={baseStyle.transform}
273
+ effectiveWithoutEffects={effectiveWithoutEffects}
274
+ effectiveReducedMotion={effectiveReducedMotion}
275
+ shaderVariant={shaderVariant}
276
+ elasticity={elasticity}
277
+ withLiquidBlur={withLiquidBlur}
278
+ >
279
+ {children}
280
+ </AtomixGlassContainer>
281
+ {withBorder && (
282
+ <>
283
+ <span
284
+ className={ATOMIX_GLASS.BORDER_1_CLASS}
285
+ style={{
286
+ position: `var(--${scopedId}-pos)` as any,
287
+ top: `var(--${scopedId}-top)`,
288
+ left: `var(--${scopedId}-left)`,
289
+ width: `var(--${scopedId}-w)`,
290
+ height: `var(--${scopedId}-h)`,
291
+ borderRadius: `var(--${scopedId}-r)`,
292
+ transform: `var(--${scopedId}-t)`,
293
+ transition: `var(--${scopedId}-tr)`,
294
+ background: `var(--${scopedId}-b1)`,
295
+ }}
296
+ />
297
+ <span
298
+ className={ATOMIX_GLASS.BORDER_2_CLASS}
299
+ style={{
300
+ position: `var(--${scopedId}-pos)` as any,
301
+ top: `var(--${scopedId}-top)`,
302
+ left: `var(--${scopedId}-left)`,
303
+ width: `var(--${scopedId}-w)`,
304
+ height: `var(--${scopedId}-h)`,
305
+ borderRadius: `var(--${scopedId}-r)`,
306
+ transform: `var(--${scopedId}-t)`,
307
+ transition: `var(--${scopedId}-tr)`,
308
+ mixBlendMode: `var(--${scopedId}-blend)` as any,
309
+ background: `var(--${scopedId}-b2)`,
310
+ }}
311
+ />
312
+ </>
313
+ )}
314
+ {Boolean(onClick) && (
315
+ <>
316
+ <div
317
+ className={ATOMIX_GLASS.HOVER_1_CLASS}
318
+ style={{
319
+ position: 'absolute',
320
+ inset: 0,
321
+ borderRadius: `var(--${scopedId}-r)`,
322
+ transform: `var(--${scopedId}-t)`,
323
+ transition: `var(--${scopedId}-tr)`,
324
+ mixBlendMode: `var(--${scopedId}-blend)` as any,
325
+ opacity: `var(--${scopedId}-h1-o)`,
326
+ background: `var(--${scopedId}-h1)`,
327
+ }}
328
+ />
329
+ <div
330
+ className={ATOMIX_GLASS.HOVER_2_CLASS}
331
+ style={{
332
+ position: 'absolute',
333
+ inset: 0,
334
+ borderRadius: `var(--${scopedId}-r)`,
335
+ transform: `var(--${scopedId}-t)`,
336
+ transition: `var(--${scopedId}-tr)`,
337
+ mixBlendMode: `var(--${scopedId}-blend)` as any,
338
+ opacity: `var(--${scopedId}-h2-o)`,
339
+ background: `var(--${scopedId}-h2)`,
340
+ }}
341
+ />
342
+ <div
343
+ className={ATOMIX_GLASS.HOVER_3_CLASS}
344
+ style={{
345
+ position: 'absolute',
346
+ inset: 0,
347
+ borderRadius: `var(--${scopedId}-r)`,
348
+ transform: `var(--${scopedId}-t)`,
349
+ transition: `var(--${scopedId}-tr)`,
350
+ mixBlendMode: `var(--${scopedId}-blend)` as any,
351
+ opacity: `var(--${scopedId}-h3-o)`,
352
+ background: `var(--${scopedId}-h3)`,
353
+ }}
354
+ />
355
+ </>
356
+ )}
357
+ {withOverLightLayers && (
358
+ <>
359
+ <div
360
+ className={ATOMIX_GLASS.BASE_LAYER_CLASS}
361
+ style={{
362
+ position: 'absolute',
363
+ inset: 0,
364
+ borderRadius: `var(--${scopedId}-r)`,
365
+ transform: `var(--${scopedId}-t)`,
366
+ transition: `var(--${scopedId}-tr)`,
367
+ opacity: `var(--${scopedId}-base-o)`,
368
+ background: `var(--${scopedId}-base)`,
369
+ }}
370
+ />
371
+ <div
372
+ className={ATOMIX_GLASS.OVERLAY_LAYER_CLASS}
373
+ style={{
374
+ position: 'absolute',
375
+ inset: 0,
376
+ borderRadius: `var(--${scopedId}-r)`,
377
+ transform: `var(--${scopedId}-t)`,
378
+ transition: `var(--${scopedId}-tr)`,
379
+ opacity: `var(--${scopedId}-over-o)`,
380
+ background: `var(--${scopedId}-over)`,
381
+ }}
382
+ />
383
+ </>
384
+ )}
385
+ </div>
386
+ );
387
+ }
388
+
389
+ export default AtomixGlass;
390
+
@@ -251,6 +251,35 @@ export const softClamp = (value: number, max: number): number => {
251
251
  return max * (1 - Math.exp(-value / max));
252
252
  };
253
253
 
254
+ /**
255
+ * Spring-damper integration helper
256
+ * Calculates the next value based on velocity, stiffness, and damping.
257
+ */
258
+ export const calculateSpring = (
259
+ current: number,
260
+ target: number,
261
+ velocity: number,
262
+ stiffness: number = 0.1,
263
+ damping: number = 0.8
264
+ ): { value: number; velocity: number } => {
265
+ const force = (target - current) * stiffness;
266
+ const newVelocity = (velocity + force) * damping;
267
+ const newValue = current + newVelocity;
268
+ return { value: newValue, velocity: newVelocity };
269
+ };
270
+
271
+ /**
272
+ * Calculate velocity from position delta and time
273
+ */
274
+ export const calculateVelocity = (
275
+ current: number,
276
+ previous: number,
277
+ deltaTime: number
278
+ ): number => {
279
+ if (deltaTime <= 0) return 0;
280
+ return (current - previous) / deltaTime;
281
+ };
282
+
254
283
  /**
255
284
  * Get displacement map URL based on mode
256
285
  */
@@ -402,7 +402,7 @@ export const Playground: Story = {
402
402
  name: 'Standard',
403
403
  icon: '⚖️',
404
404
  settings: {
405
- displacementScale: 120,
405
+ displacementScale: 80,
406
406
  blurAmount: 1,
407
407
  saturation: 140,
408
408
  aberrationIntensity: 2,
@@ -429,6 +429,37 @@ export const Playground: Story = {
429
429
  mode: 'standard' as const,
430
430
  shader: 'liquidGlass' as const,
431
431
  },
432
+ liquid: {
433
+ name: 'Liquid Glass',
434
+ icon: '💧',
435
+ settings: {
436
+ displacementScale: 150,
437
+ blurAmount: 2.5,
438
+ saturation: 180,
439
+ aberrationIntensity: 4.0,
440
+ elasticity: 0.35,
441
+ borderRadius: 40,
442
+ overLight: false,
443
+ reducedMotion: false,
444
+ highContrast: false,
445
+ withoutEffects: false,
446
+ withLiquidBlur: true,
447
+ withBorder: true,
448
+ withTimeAnimation: true,
449
+ animationSpeed: 1.2,
450
+ withMultiLayerDistortion: true,
451
+ distortionOctaves: 4,
452
+ distortionLacunarity: 2.2,
453
+ distortionGain: 0.55,
454
+ distortionQuality: 'high' as const,
455
+ devicePreset: 'quality' as const,
456
+ disableResponsiveBreakpoints: false,
457
+ debugPerformance: false,
458
+ debugOverLight: false,
459
+ },
460
+ mode: 'prominent' as const,
461
+ shader: 'appleFluid' as const,
462
+ },
432
463
  premium: {
433
464
  name: 'Premium',
434
465
  icon: '💎',
@@ -351,7 +351,7 @@ export const AllOutlineVariants: Story = {
351
351
  <Button label="Outline Success" variant="outline-success" />
352
352
  <Button label="Outline Info" variant="outline-info" />
353
353
  <Button label="Outline Warning" variant="outline-warning" />
354
- <Button label="Outline Danger" variant="outline-danger" />
354
+ <Button label="Outline Danger" variant="outline-error" />
355
355
  <Button label="Outline Light" variant="outline-light" />
356
356
  <Button label="Outline Dark" variant="outline-dark" />
357
357
  </div>
@@ -172,21 +172,23 @@ export const Button = React.memo(
172
172
  size: spinnerSize,
173
173
  variant:
174
174
  variant === 'link' ||
175
+ variant === 'ghost' ||
175
176
  (typeof variant === 'string' && variant.startsWith('outline-'))
176
177
  ? 'primary'
177
178
  : variant === 'danger'
178
- ? 'error'
179
- : variant,
179
+ ? 'danger'
180
+ : variant as any,
180
181
  },
181
182
  <Spinner
182
183
  size={spinnerSize}
183
184
  variant={
184
185
  variant === 'link' ||
186
+ variant === 'ghost' ||
185
187
  (typeof variant === 'string' && variant.startsWith('outline-'))
186
188
  ? 'primary'
187
189
  : variant === 'danger'
188
- ? 'error'
189
- : variant
190
+ ? 'danger'
191
+ : variant as any
190
192
  }
191
193
  />
192
194
  )}
@@ -323,7 +325,6 @@ export const Button = React.memo(
323
325
  displacementScale: 20,
324
326
  blurAmount: 0,
325
327
  saturation: 200,
326
- elasticity: 0,
327
328
  };
328
329
  const glassProps = glass === true ? defaultGlassProps : { ...defaultGlassProps, ...glass };
329
330
  return <AtomixGlass {...glassProps}>{buttonChildren}</AtomixGlass>;
@@ -377,7 +377,7 @@ const CardImpl = React.memo(
377
377
 
378
378
  if (glass) {
379
379
  const glassProps = glass === true ? {} : glass;
380
- return <AtomixGlass {...{ ...glassProps, elasticity: 0 }}>{anchorElement}</AtomixGlass>;
380
+ return <AtomixGlass {...glassProps}>{anchorElement}</AtomixGlass>;
381
381
  }
382
382
 
383
383
  return anchorElement;
@@ -392,7 +392,7 @@ const CardImpl = React.memo(
392
392
 
393
393
  if (glass) {
394
394
  const glassProps = glass === true ? {} : glass;
395
- return <AtomixGlass {...{ ...glassProps, elasticity: 0 }}>{divElement}</AtomixGlass>;
395
+ return <AtomixGlass {...glassProps}>{divElement}</AtomixGlass>;
396
396
  }
397
397
 
398
398
  return divElement;
@@ -36,6 +36,7 @@ type ExtendedComponentType<P = {}> = ComponentType<P> & {
36
36
  interface DropdownTriggerProps extends React.HTMLAttributes<HTMLDivElement> {
37
37
  onClick?: (e: React.MouseEvent) => void;
38
38
  onKeyDown?: (e: React.KeyboardEvent) => void;
39
+ ref?: React.Ref<HTMLDivElement>;
39
40
  }
40
41
 
41
42
  interface DropdownMenuProps extends React.HTMLAttributes<HTMLUListElement> {}
@@ -140,9 +140,7 @@ const EdgePanelComponentBase = ({
140
140
  return null;
141
141
  }
142
142
 
143
- const defaultGlassProps = {
144
- elasticity: 0,
145
- };
143
+ const defaultGlassProps = {};
146
144
 
147
145
  const glassProps = glass === true ? defaultGlassProps : { ...defaultGlassProps, ...glass };
148
146