@shohojdhara/atomix 0.6.4 → 0.6.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 (83) hide show
  1. package/dist/atomix.css +117 -38
  2. package/dist/atomix.css.map +1 -1
  3. package/dist/atomix.min.css +1 -1
  4. package/dist/atomix.min.css.map +1 -1
  5. package/dist/atomix.umd.js +1 -1
  6. package/dist/atomix.umd.js.map +1 -1
  7. package/dist/atomix.umd.min.js +1 -1
  8. package/dist/charts.d.ts +30 -1
  9. package/dist/charts.js +625 -846
  10. package/dist/charts.js.map +1 -1
  11. package/dist/core.d.ts +30 -1
  12. package/dist/core.js +659 -873
  13. package/dist/core.js.map +1 -1
  14. package/dist/forms.d.ts +30 -1
  15. package/dist/forms.js +1171 -1402
  16. package/dist/forms.js.map +1 -1
  17. package/dist/heavy.d.ts +31 -89
  18. package/dist/heavy.js +975 -1195
  19. package/dist/heavy.js.map +1 -1
  20. package/dist/index.d.ts +383 -140
  21. package/dist/index.esm.js +1567 -1679
  22. package/dist/index.esm.js.map +1 -1
  23. package/dist/index.js +1556 -1667
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.min.js +1 -1
  26. package/dist/index.min.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/components/Accordion/Accordion.tsx +2 -5
  29. package/src/components/AtomixGlass/AtomixGlass.test.tsx +14 -16
  30. package/src/components/AtomixGlass/AtomixGlass.tsx +137 -364
  31. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +32 -251
  32. package/src/components/AtomixGlass/GlassFilter.tsx +62 -68
  33. package/src/components/AtomixGlass/README.md +2 -1
  34. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +19 -18
  35. package/src/components/AtomixGlass/glass-border-styles.test.ts +58 -0
  36. package/src/components/AtomixGlass/glass-border-styles.ts +136 -0
  37. package/src/components/AtomixGlass/glass-utils.ts +456 -22
  38. package/src/components/AtomixGlass/shader-utils.ts +19 -77
  39. package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +158 -537
  40. package/src/components/AtomixGlass/stories/Border.stories.tsx +149 -0
  41. package/src/components/AtomixGlass/stories/Examples.stories.tsx +229 -89
  42. package/src/components/AtomixGlass/stories/Playground.stories.tsx +29 -340
  43. package/src/components/AtomixGlass/stories/argTypes.ts +30 -13
  44. package/src/components/AtomixGlass/stories/premium-presets.ts +206 -0
  45. package/src/components/AtomixGlass/stories/shared-components.tsx +52 -8
  46. package/src/components/Badge/Badge.tsx +4 -4
  47. package/src/components/Button/Button.tsx +2 -6
  48. package/src/components/Callout/Callout.test.tsx +4 -3
  49. package/src/components/Callout/Callout.tsx +2 -5
  50. package/src/components/Dropdown/Dropdown.tsx +3 -7
  51. package/src/components/Form/Checkbox.tsx +2 -8
  52. package/src/components/Form/Input.tsx +2 -9
  53. package/src/components/Form/Radio.tsx +2 -9
  54. package/src/components/Form/Select.test.tsx +6 -6
  55. package/src/components/Form/Select.tsx +2 -7
  56. package/src/components/Form/Textarea.stories.tsx +5 -5
  57. package/src/components/Form/Textarea.tsx +2 -9
  58. package/src/components/Messages/Messages.tsx +2 -8
  59. package/src/components/Modal/Modal.tsx +4 -5
  60. package/src/components/Navigation/Nav/Nav.tsx +2 -6
  61. package/src/components/Navigation/Navbar/Navbar.tsx +2 -9
  62. package/src/components/Navigation/SideMenu/SideMenu.tsx +2 -6
  63. package/src/components/Pagination/Pagination.tsx +2 -10
  64. package/src/components/Popover/Popover.tsx +2 -9
  65. package/src/components/Progress/Progress.tsx +2 -7
  66. package/src/components/Rating/Rating.tsx +2 -10
  67. package/src/components/Spinner/Spinner.tsx +2 -7
  68. package/src/components/Steps/Steps.tsx +2 -10
  69. package/src/components/Tabs/Tabs.tsx +2 -9
  70. package/src/components/Toggle/Toggle.tsx +2 -10
  71. package/src/components/Tooltip/Tooltip.tsx +2 -5
  72. package/src/lib/composables/useAtomixGlass.ts +42 -143
  73. package/src/lib/composables/useAtomixGlassStyles.ts +61 -77
  74. package/src/lib/composables/usePerformanceMonitor.ts +5 -66
  75. package/src/lib/constants/components.ts +363 -46
  76. package/src/lib/types/components.ts +33 -1
  77. package/src/styles/01-settings/_settings.atomix-glass.scss +66 -28
  78. package/src/styles/02-tools/_tools.button.scss +51 -42
  79. package/src/styles/02-tools/_tools.glass.scss +45 -3
  80. package/src/styles/06-components/_components.atomix-glass.scss +116 -79
  81. package/src/components/AtomixGlass/PerformanceDashboard.tsx +0 -171
  82. package/src/components/AtomixGlass/animation-system.ts +0 -578
  83. package/src/components/AtomixGlass/deprecated/AtomixGlass.deprecated.tsx +0 -390
@@ -65,54 +65,63 @@
65
65
  $active-border: null
66
66
  ) {
67
67
  $btn-color: var(--#{config.$prefix}#{$color}, #{map.get(tokens.$theme-colors, $color)});
68
- $btn-hover-color: if(
69
- $color-hover,
70
- var(--#{config.$prefix}#{$color-hover}, #{map.get(tokens.$theme-colors, $color-hover)}),
71
- var(--#{config.$prefix}white, #{colors.$white})
68
+ $btn-hover-color: var(--#{config.$prefix}white, #{colors.$white});
69
+ $btn-hover-bg: var(
70
+ --#{config.$prefix}#{$color}-hover,
71
+ #{color.scale(map.get(tokens.$theme-colors, $color), $lightness: -15%)}
72
72
  );
73
- $btn-hover-bg: if(
74
- $hover-background,
75
- var(
76
- --#{config.$prefix}#{$hover-background},
77
- #{map.get(tokens.$theme-colors, $hover-background)}
78
- ),
79
- var(
80
- --#{config.$prefix}#{$color}-hover,
81
- #{color.scale(map.get(tokens.$theme-colors, $color), $lightness: -15%)}
82
- )
73
+ $btn-hover-border: var(
74
+ --#{config.$prefix}#{$color}-hover,
75
+ #{color.scale(map.get(tokens.$theme-colors, $color), $lightness: -10%)}
83
76
  );
84
- $btn-hover-border: if(
85
- $hover-border,
86
- var(--#{config.$prefix}#{$hover-border}, #{map.get(tokens.$theme-colors, $hover-border)}),
87
- var(
88
- --#{config.$prefix}#{$color}-hover,
89
- #{color.scale(map.get(tokens.$theme-colors, $color), $lightness: -10%)}
90
- )
77
+ $btn-active-color: var(--#{config.$prefix}white, #{colors.$white});
78
+ $btn-active-bg: var(
79
+ --#{config.$prefix}#{$color}-hover,
80
+ #{color.scale(map.get(tokens.$theme-colors, $color), $lightness: -20%)}
91
81
  );
92
- $btn-active-color: if(
93
- $color-hover,
94
- var(--#{config.$prefix}#{$color-hover}, #{map.get(tokens.$theme-colors, $color-hover)}),
95
- var(--#{config.$prefix}white, #{colors.$white})
82
+ $btn-active-border: var(
83
+ --#{config.$prefix}#{$color}-hover,
84
+ #{color.scale(map.get(tokens.$theme-colors, $color), $lightness: -25%)}
96
85
  );
97
- $btn-active-bg: if(
98
- $active-background,
99
- var(
86
+
87
+ @if $color-hover {
88
+ $btn-hover-color: var(
89
+ --#{config.$prefix}#{$color-hover},
90
+ #{map.get(tokens.$theme-colors, $color-hover)}
91
+ );
92
+ $btn-active-color: var(
93
+ --#{config.$prefix}#{$color-hover},
94
+ #{map.get(tokens.$theme-colors, $color-hover)}
95
+ );
96
+ }
97
+
98
+ @if $hover-background {
99
+ $btn-hover-bg: var(
100
+ --#{config.$prefix}#{$hover-background},
101
+ #{map.get(tokens.$theme-colors, $hover-background)}
102
+ );
103
+ }
104
+
105
+ @if $hover-border {
106
+ $btn-hover-border: var(
107
+ --#{config.$prefix}#{$hover-border},
108
+ #{map.get(tokens.$theme-colors, $hover-border)}
109
+ );
110
+ }
111
+
112
+ @if $active-background {
113
+ $btn-active-bg: var(
100
114
  --#{config.$prefix}#{$active-background},
101
115
  #{map.get(tokens.$theme-colors, $active-background)}
102
- ),
103
- var(
104
- --#{config.$prefix}#{$color}-hover,
105
- #{color.scale(map.get(tokens.$theme-colors, $color), $lightness: -20%)}
106
- )
107
- );
108
- $btn-active-border: if(
109
- $active-border,
110
- var(--#{config.$prefix}#{$active-border}, #{map.get(tokens.$theme-colors, $active-border)}),
111
- var(
112
- --#{config.$prefix}#{$color}-hover,
113
- #{color.scale(map.get(tokens.$theme-colors, $color), $lightness: -25%)}
114
- )
115
- );
116
+ );
117
+ }
118
+
119
+ @if $active-border {
120
+ $btn-active-border: var(
121
+ --#{config.$prefix}#{$active-border},
122
+ #{map.get(tokens.$theme-colors, $active-border)}
123
+ );
124
+ }
116
125
 
117
126
  --#{config.$prefix}btn-color: #{$btn-color};
118
127
  --#{config.$prefix}btn-bg: transparent;
@@ -1,6 +1,48 @@
1
1
  // AtomixGlass Tools
2
2
  // =============================================================================
3
- // Glass-specific mixins and utilities
4
- // Note: Focus ring and other general mixins are available in tools.component
3
+ // Liquid glass border ring mixins
5
4
 
6
- @use 'tools.component' as *;
5
+ @use '../01-settings/settings.atomix-glass' as *;
6
+
7
+ /// Shared geometry for border effect layers (backdrop + gradient rings).
8
+ @mixin liquid-glass-border-layer {
9
+ display: block;
10
+ box-sizing: border-box;
11
+ pointer-events: none;
12
+ position: var(--atomix-glass-position);
13
+ top: var(--atomix-glass-top);
14
+ left: var(--atomix-glass-left);
15
+ right: var(--atomix-glass-right);
16
+ bottom: var(--atomix-glass-bottom);
17
+ width: var(--atomix-glass-width);
18
+ height: var(--atomix-glass-height);
19
+ border-radius: var(--_glass-radius);
20
+ transform: var(--_glass-transform);
21
+ transition: var(--_glass-transition);
22
+ }
23
+
24
+ /// Hollow ring mask — clips content to the border band only (padding-box XOR border-box).
25
+ /// Do not set overflow: hidden here; it breaks mask-composite at rounded corners.
26
+ @mixin liquid-glass-border-ring-mask {
27
+ padding: var(--atomix-glass-border-width, #{$glass-border-width});
28
+ -webkit-mask:
29
+ linear-gradient(#fff 0 0) content-box,
30
+ linear-gradient(#fff 0 0);
31
+ -webkit-mask-composite: xor;
32
+ mask:
33
+ linear-gradient(#fff 0 0) content-box,
34
+ linear-gradient(#fff 0 0);
35
+ mask-composite: exclude;
36
+ }
37
+
38
+ /// Gradient / painted rim — mask ring + background (conic or JS linear-gradient).
39
+ @mixin liquid-glass-border-painted-ring {
40
+ @include liquid-glass-border-layer;
41
+ @include liquid-glass-border-ring-mask;
42
+ }
43
+
44
+ /// Backdrop sampling ring — same mask geometry, backdrop-filter on the band only.
45
+ @mixin liquid-glass-border-backdrop-ring {
46
+ @include liquid-glass-border-layer;
47
+ @include liquid-glass-border-ring-mask;
48
+ }
@@ -3,6 +3,28 @@
3
3
 
4
4
  @use '../01-settings/settings.atomix-glass' as *;
5
5
  @use '../02-tools/tools.component' as *;
6
+ @use '../02-tools/tools.glass' as glass;
7
+
8
+ // ─── @property registrations ─────────────────────────────────────────────────
9
+ // Typed custom properties let the browser interpolate these values in
10
+ // CSS transitions without needing JS class-toggling.
11
+ @property --atomix-glass-hover-1-opacity {
12
+ syntax: '<number>';
13
+ inherits: false;
14
+ initial-value: 0;
15
+ }
16
+
17
+ @property --atomix-glass-hover-2-opacity {
18
+ syntax: '<number>';
19
+ inherits: false;
20
+ initial-value: 0;
21
+ }
22
+
23
+ @property --atomix-glass-hover-3-opacity {
24
+ syntax: '<number>';
25
+ inherits: false;
26
+ initial-value: 0;
27
+ }
6
28
 
7
29
  .c-atomix-glass {
8
30
  position: relative;
@@ -10,9 +32,11 @@
10
32
  // Local, sane defaults (kept minimal)
11
33
  --_glass-radius: var(--atomix-glass-radius, var(--atomix-radius-md, 0.75rem));
12
34
  --_glass-transform: var(--atomix-glass-transform, translateZ(0));
35
+ --_glass-backdrop: #{$glass-backdrop-filter};
13
36
 
14
37
  --atomix-glass-position: absolute;
15
- --atomix-glass-border-width: var(--atomix-spacing-0-5, 0.125rem);
38
+ --atomix-glass-border-width: #{$glass-border-width};
39
+ --atomix-glass-border-backdrop-filter: #{$glass-border-backdrop-filter};
16
40
  --atomix-glass-top: 0;
17
41
  --atomix-glass-left: 0;
18
42
  --atomix-glass-right: auto;
@@ -52,13 +76,12 @@
52
76
 
53
77
  --atomix-glass-border-shadow:
54
78
  0 0 0 0.5px var(--atomix-glass-border-color, #{$glass-border-color}) inset,
55
- 0 1px 2px var(--atomix-glass-inner-shadow-color, #{$glass-inner-shadow-color}) inset,
56
- 0 2px 6px var(--atomix-glass-outer-shadow-color, #{$glass-outer-shadow-color});
79
+ 0 1px 1px var(--atomix-glass-inner-shadow-color, #{$glass-inner-shadow-color}) inset,
80
+ 0 1px 3px var(--atomix-glass-outer-shadow-color, #{$glass-outer-shadow-color});
57
81
 
58
- // Base layer styles for effect layers
59
- &__hover-1,
60
- &__hover-2,
61
- &__hover-3,
82
+ // ── Over-light decorative layers (base, overlay) ─────────────────────────
83
+ // These use var-based positioning so they correctly follow the container in
84
+ // fixed / sticky layouts where the container may have explicit pixel offsets.
62
85
  &__base,
63
86
  &__overlay {
64
87
  position: var(--atomix-glass-position);
@@ -72,65 +95,74 @@
72
95
  border-radius: var(--_glass-radius);
73
96
  transform: var(--_glass-transform);
74
97
  transition: var(--_glass-transition);
75
- }
76
-
77
- &__hover-1,
78
- &__hover-2,
79
- &__hover-3 {
80
- z-index: var(--_glass-z-hover);
81
- }
82
-
83
- &__base,
84
- &__overlay {
85
98
  z-index: var(--_glass-z-effect);
86
99
  }
87
100
 
88
- // Interactive hover effects
101
+ // ── Interactive hover / press layers ─────────────────────────────────────
102
+ // Always fill the glass surface with inset: 0. Move in sync with the
103
+ // elastic spring via the shared --atomix-glass-transform var.
104
+ // Opacity is driven via typed @property vars so CSS transitions interpolate.
89
105
  &__hover-1,
90
106
  &__hover-2,
91
107
  &__hover-3 {
92
- mix-blend-mode: overlay;
108
+ position: absolute;
109
+ inset: 0;
110
+ pointer-events: none;
111
+ border-radius: var(--_glass-radius);
112
+ transform: var(--_glass-transform);
113
+ // Opacity transition — works because @property declares the var as <number>
114
+ transition:
115
+ opacity #{$glass-transition-duration} #{$glass-easing},
116
+ border-radius #{$glass-transition-duration} #{$glass-easing};
117
+ z-index: var(--_glass-z-hover);
93
118
  }
94
119
 
120
+ // hover-1: ambient cursor-tracking highlight (white overlay glow)
95
121
  &__hover-1 {
96
122
  opacity: var(--atomix-glass-hover-1-opacity, 0);
123
+ mix-blend-mode: overlay;
97
124
  background: var(
98
125
  --atomix-glass-hover-1-gradient,
99
126
  radial-gradient(
100
- 60% 60% at 50% 0%,
101
- var(--atomix-glass-hover-1-start-color, #{$glass-hover-1-start-color}) 0%,
102
- var(--atomix-glass-hover-1-end-color, #{$glass-hover-1-end-color}) 60%
127
+ 65% 55% at 50% 30%,
128
+ rgba(255, 255, 255, 0.22) 0%,
129
+ rgba(255, 255, 255, 0) 72%
103
130
  )
104
131
  );
105
132
  }
106
133
 
134
+ // hover-2: press depth — subtle shadow at the press point (darken only on active)
107
135
  &__hover-2 {
108
136
  opacity: var(--atomix-glass-hover-2-opacity, 0);
137
+ mix-blend-mode: multiply;
109
138
  background: var(
110
139
  --atomix-glass-hover-2-gradient,
111
140
  radial-gradient(
112
- 80% 80% at 50% 100%,
113
- var(--atomix-glass-hover-2-start-color, #{$glass-hover-2-start-color}) 0%,
114
- var(--atomix-glass-hover-2-end-color, #{$glass-hover-2-end-color}) 60%
141
+ 70% 60% at 50% 60%,
142
+ rgba(0, 0, 0, 0.18) 0%,
143
+ rgba(0, 0, 0, 0) 72%
115
144
  )
116
145
  );
117
146
  }
118
147
 
148
+ // hover-3: global soft-light tint shift — full surface brightness on hover/press
119
149
  &__hover-3 {
120
150
  opacity: var(--atomix-glass-hover-3-opacity, 0);
151
+ mix-blend-mode: soft-light;
121
152
  background: var(
122
153
  --atomix-glass-hover-3-gradient,
123
154
  linear-gradient(
124
- 180deg,
125
- var(--atomix-glass-hover-3-start-color, #{$glass-hover-3-start-color}) 0%,
126
- var(--atomix-glass-hover-3-end-color, #{$glass-hover-3-end-color}) 100%
155
+ 160deg,
156
+ rgba(255, 255, 255, 0.12) 0%,
157
+ rgba(255, 255, 255, 0.04) 55%,
158
+ rgba(255, 255, 255, 0) 100%
127
159
  )
128
160
  );
129
161
  }
130
162
 
131
163
  &__base {
132
164
  mix-blend-mode: soft-light;
133
- opacity: var(--atomix-glass-base-opacity, 0.6);
165
+ opacity: var(--atomix-glass-base-opacity, #{$glass-base-opacity});
134
166
  background: var(
135
167
  --atomix-glass-base-gradient,
136
168
  linear-gradient(
@@ -143,7 +175,7 @@
143
175
 
144
176
  &__overlay {
145
177
  mix-blend-mode: overlay;
146
- opacity: var(--atomix-glass-overlay-opacity, 0.35);
178
+ opacity: var(--atomix-glass-overlay-opacity, #{$glass-overlay-opacity});
147
179
  background: var(
148
180
  --atomix-glass-overlay-gradient,
149
181
  radial-gradient(
@@ -164,69 +196,59 @@
164
196
  transition: var(--_glass-transition);
165
197
  mix-blend-mode: screen;
166
198
  z-index: var(--_glass-z-overlay-highlight);
167
- opacity: var(--atomix-glass-overlay-highlight-opacity, 0.25);
199
+ opacity: var(--atomix-glass-overlay-highlight-opacity, #{$glass-overlay-highlight-opacity});
168
200
  background: var(
169
201
  --atomix-glass-overlay-highlight-bg,
170
- linear-gradient(
171
- 180deg,
202
+ radial-gradient(
203
+ 90% 55% at 50% 0%,
172
204
  var(--atomix-glass-highlight-start-color, #{$glass-highlight-start-color}) 0%,
173
- var(--atomix-glass-highlight-end-color, #{$glass-highlight-end-color}) 60%
205
+ var(--atomix-glass-highlight-end-color, #{$glass-highlight-end-color}) 72%
174
206
  )
175
207
  );
176
208
  }
177
209
 
178
- // Border effect layers - matching old version exactly
179
- &__border-backdrop,
180
- &__border-1,
181
- &__border-2 {
182
- // Static styles
183
- padding: var(--atomix-glass-border-width);
184
- box-sizing: border-box;
185
- overflow: hidden;
186
- pointer-events: none;
187
- /* autoprefixer: ignore next */
188
- -webkit-mask:
189
- linear-gradient(var(--atomix-black, #000000) 0 0) content-box,
190
- linear-gradient(var(--atomix-black, #000000) 0 0);
191
- /* autoprefixer: ignore next */
192
- -webkit-mask-composite: xor;
193
- /* autoprefixer: ignore next */
194
- mask:
195
- linear-gradient(var(--atomix-black, #000000) 0 0) content-box,
196
- linear-gradient(var(--atomix-black, #000000) 0 0);
197
- /* autoprefixer: ignore next */
198
- mask-composite: exclude;
199
-
200
- position: var(--atomix-glass-position);
201
- top: var(--atomix-glass-top);
202
- left: var(--atomix-glass-left);
203
- right: var(--atomix-glass-right);
204
- bottom: var(--atomix-glass-bottom);
205
- width: var(--atomix-glass-width);
206
- height: var(--atomix-glass-height);
207
- border-radius: var(--_glass-radius);
208
- transform: var(--_glass-transform);
209
- transition: var(--_glass-transition);
210
- }
211
-
210
+ // Border effect layers liquid glass rim (see tools.glass mixins)
212
211
  &__border-backdrop {
213
- mix-blend-mode: overlay;
212
+ @include glass.liquid-glass-border-backdrop-ring;
213
+
214
+ mix-blend-mode: #{$glass-border-backdrop-blend-mode};
214
215
  z-index: var(--_glass-z-border-1);
215
- backdrop-filter: #{$glass-backdrop-filter};
216
- // box-shadow: var(--atomix-glass-border-shadow);
216
+ backdrop-filter: var(--atomix-glass-border-backdrop-filter, #{$glass-border-backdrop-filter});
217
+ box-shadow: var(--atomix-glass-border-shadow);
217
218
  }
218
219
 
219
220
  &__border-1 {
220
- opacity: var(--atomix-glass-border-1-opacity, var(--atomix-opacity-18, 0.18));
221
- mix-blend-mode: screen;
221
+ @include glass.liquid-glass-border-painted-ring;
222
+
223
+ background: var(--atomix-glass-border-gradient-1, #{$glass-border-fallback-rim});
224
+ opacity: var(--atomix-glass-border-1-opacity, #{$glass-border-1-opacity});
225
+ mix-blend-mode: #{$glass-border-1-blend-mode};
222
226
  z-index: var(--_glass-z-border-2);
223
- background: var(--atomix-glass-border-gradient-1, none);
224
227
  }
225
228
 
226
229
  &__border-2 {
227
- mix-blend-mode: overlay;
230
+ @include glass.liquid-glass-border-painted-ring;
231
+
232
+ background: var(--atomix-glass-border-gradient-2, #{$glass-border-fallback-inner-highlight});
233
+ mix-blend-mode: #{$glass-border-2-blend-mode};
228
234
  z-index: var(--_glass-z-border-3);
229
- background: var(--atomix-glass-border-gradient-2, none);
235
+ }
236
+
237
+ // Over-light: darker conic rim + brighter top-left inner catch
238
+ &:has(.c-atomix-glass__container--over-light) {
239
+ .c-atomix-glass__border-1 {
240
+ background: var(
241
+ --atomix-glass-border-gradient-1,
242
+ #{$glass-border-fallback-rim-over-light}
243
+ );
244
+ }
245
+
246
+ .c-atomix-glass__border-2 {
247
+ background: var(
248
+ --atomix-glass-border-gradient-2,
249
+ #{$glass-border-fallback-inner-over-light}
250
+ );
251
+ }
230
252
  }
231
253
 
232
254
  &__container {
@@ -274,7 +296,7 @@
274
296
  position: absolute;
275
297
  inset: var(--atomix-glass-border-width);
276
298
  pointer-events: none;
277
- border-radius: var(--_glass-radius);
299
+ border-radius: max(0px, calc(var(--_glass-radius) - var(--atomix-glass-border-width)));
278
300
  box-shadow: var(--atomix-glass-container-shadow);
279
301
  opacity: var(--atomix-glass-container-shadow-opacity);
280
302
  background: var(--atomix-glass-container-bg);
@@ -345,17 +367,30 @@
345
367
  &--disabled-effects {
346
368
  --atomix-glass-transform: none;
347
369
  --atomix-glass-transition: none;
370
+ --_glass-transition: none;
348
371
  }
349
372
 
350
- // Focus ring for interactive elements (when onClick is provided)
373
+ // ── Interactive glass (onClick provided) ─────────────────────────────────
351
374
  &[role='button'],
352
375
  &[tabindex]:not([tabindex='-1']) {
376
+ cursor: pointer;
377
+ user-select: none;
378
+ -webkit-tap-highlight-color: transparent;
379
+
353
380
  @include focus-ring;
381
+
382
+ // CSS-level press scale fires instantly on :active (before the JS spring
383
+ // takes over) for zero-latency tactile feedback.
384
+ &:active > .c-atomix-glass__container {
385
+ transform: scale(0.985);
386
+ transition: transform 0.06s cubic-bezier(0.4, 0, 1, 1);
387
+ }
354
388
  }
355
389
 
356
390
  // Responsive and accessibility
357
391
  @media (prefers-reduced-motion: reduce) {
358
392
  --atomix-glass-transition: none;
393
+ --_glass-transition: none;
359
394
 
360
395
  * {
361
396
  transition: none !important;
@@ -363,6 +398,8 @@
363
398
  }
364
399
 
365
400
  @media (prefers-contrast: high) {
366
- border-width: var(--atomix-spacing-0-5, 0.125rem);
401
+ border: var(--atomix-spacing-0-5, 0.125rem) solid currentColor;
402
+ outline: var(--atomix-spacing-0-5, 0.125rem) solid transparent;
403
+ outline-offset: var(--atomix-spacing-0-5, 0.125rem);
367
404
  }
368
405
  }
@@ -1,171 +0,0 @@
1
- import React, { memo } from 'react';
2
- import type { PerformanceMetrics } from '../../lib/composables/usePerformanceMonitor';
3
-
4
- interface PerformanceDashboardProps {
5
- metrics: PerformanceMetrics;
6
- isVisible?: boolean;
7
- onClose?: () => void;
8
- }
9
-
10
- /** Map an FPS value to a semantic color token string. */
11
- const getFpsColor = (fps: number): string => {
12
- if (fps >= 58) return 'var(--atomix-color-success, #4ade80)';
13
- if (fps >= 45) return 'var(--atomix-color-warning, #fbbf24)';
14
- return 'var(--atomix-color-danger, #ef4444)';
15
- };
16
-
17
- /** Map a quality level string to a semantic color token string. */
18
- const getQualityColor = (quality: string): string => {
19
- switch (quality) {
20
- case 'high': return 'var(--atomix-color-success, #4ade80)';
21
- case 'medium': return 'var(--atomix-color-warning, #fbbf24)';
22
- case 'low': return 'var(--atomix-color-danger, #ef4444)';
23
- default: return '#9ca3af';
24
- }
25
- };
26
-
27
- const getFpsLabel = (fps: number): string => {
28
- if (fps >= 58) return 'Optimal';
29
- if (fps >= 45) return 'Warning';
30
- return 'Critical';
31
- };
32
-
33
- // Keyframes for pulse animation (injected via style tag)
34
- const keyframesStyle = `
35
- @keyframes perf-dashboard-pulse {
36
- 0%, 100% { opacity: 1; }
37
- 50% { opacity: 0.5; }
38
- }
39
- `;
40
-
41
- // Inject keyframes once
42
- if (typeof document !== 'undefined') {
43
- const styleId = 'perf-dashboard-keyframes';
44
- if (!document.getElementById(styleId)) {
45
- const styleEl = document.createElement('style');
46
- styleEl.id = styleId;
47
- styleEl.textContent = keyframesStyle;
48
- document.head.appendChild(styleEl);
49
- }
50
- }
51
-
52
- /**
53
- * PerformanceDashboard - Real-time performance monitoring overlay.
54
- *
55
- * Displays FPS, frame time, quality level, GPU memory, and auto-scaling status.
56
- * Rendered only when `debugPerformance={true}` on the parent `AtomixGlass`.
57
- */
58
- export const PerformanceDashboard: React.FC<PerformanceDashboardProps> = memo(
59
- ({ metrics, isVisible = true, onClose }) => {
60
- if (!isVisible) return null;
61
-
62
- const fpsColor = getFpsColor(metrics.fps);
63
- const isCritical = metrics.fps < 45;
64
-
65
- return (
66
- <div
67
- className="c-perf-dashboard u-position-fixed u-top-4 u-end-4 u-p-3 u-px-4 u-text-xs u-font-mono u-text-white u-rounded-md u-border u-border-white-alpha-10 u-shadow-lg"
68
- style={{
69
- zIndex: 9999,
70
- minWidth: '12.5rem', // 200px
71
- backgroundColor: 'rgba(17, 24, 39, 0.95)',
72
- backdropFilter: 'blur(8px)',
73
- transition: 'opacity 0.3s ease',
74
- }}
75
- >
76
- {/* Header */}
77
- <div className="u-flex u-items-center u-justify-between u-mb-2 u-pb-2 u-border-b u-border-white-alpha-10">
78
- <span className="u-text-sm u-font-bold u-text-white">Performance Monitor</span>
79
- {onClose && (
80
- <button
81
- className="u-bg-transparent u-border-none u-p-0 u-line-height-1 u-text-base u-text-gray-400 u-cursor-pointer hover:u-text-white"
82
- onClick={onClose}
83
- aria-label="Close performance dashboard"
84
- style={{ transition: 'color 0.2s ease' }}
85
- >
86
- ×
87
- </button>
88
- )}
89
- </div>
90
-
91
- {/* FPS */}
92
- <div className="u-flex u-items-center u-justify-between u-mb-1-5">
93
- <span className="u-text-gray-400 u-me-3">FPS</span>
94
- <span className="u-font-bold" style={{ color: fpsColor }}>
95
- {Math.round(metrics.fps)}
96
- </span>
97
- </div>
98
-
99
- {/* Frame Time */}
100
- <div className="u-flex u-items-center u-justify-between u-mb-1-5">
101
- <span className="u-text-gray-400 u-me-3">Frame Time</span>
102
- <span className="u-font-bold">
103
- {metrics.frameTime.toFixed(2)}ms
104
- </span>
105
- </div>
106
-
107
- {/* Quality Level */}
108
- <div className="u-flex u-items-center u-justify-between u-mb-1-5">
109
- <span className="u-text-gray-400 u-me-3">Quality</span>
110
- <span
111
- className="u-font-bold u-text-uppercase"
112
- style={{
113
- fontSize: '0.6875rem', // 11px
114
- color: getQualityColor(metrics.qualityLevel)
115
- }}
116
- >
117
- {metrics.qualityLevel}
118
- </span>
119
- </div>
120
-
121
- {/* GPU Memory (if available) */}
122
- {metrics.gpuMemory && (
123
- <div className="u-flex u-items-center u-justify-between u-mb-1-5">
124
- <span className="u-text-gray-400 u-me-3">GPU Memory</span>
125
- <span className="u-font-bold">
126
- ~{Math.round(metrics.gpuMemory / 1024)}MB
127
- </span>
128
- </div>
129
- )}
130
-
131
- {/* Auto-scaling notice */}
132
- {metrics.isAutoScaling && (
133
- <div
134
- className="u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10 u-text-center"
135
- style={{
136
- fontSize: '0.625rem', // 10px
137
- color: '#6b7280',
138
- }}
139
- >
140
- Auto-scaling active
141
- </div>
142
- )}
143
-
144
- {/* Status indicator */}
145
- <div className="u-flex u-items-center u-gap-2 u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10">
146
- <div
147
- className="u-rounded-full"
148
- style={{
149
- width: '0.5rem',
150
- height: '0.5rem',
151
- flexShrink: 0,
152
- backgroundColor: fpsColor,
153
- ...(isCritical && { animation: 'perf-dashboard-pulse 1s infinite' }),
154
- }}
155
- />
156
- <span
157
- className="u-text-xs"
158
- style={{
159
- fontSize: '0.625rem', // 10px
160
- color: fpsColor
161
- }}
162
- >
163
- {getFpsLabel(metrics.fps)}
164
- </span>
165
- </div>
166
- </div>
167
- );
168
- }
169
- );
170
-
171
- PerformanceDashboard.displayName = 'PerformanceDashboard';