@kushagradhawan/kookie-ui 0.1.22 → 0.1.23

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 (94) hide show
  1. package/components.css +748 -612
  2. package/dist/cjs/components/_internal/base-checkbox.props.d.ts +2 -2
  3. package/dist/cjs/components/_internal/base-checkbox.props.js +1 -1
  4. package/dist/cjs/components/_internal/base-checkbox.props.js.map +2 -2
  5. package/dist/cjs/components/_internal/base-radio.props.d.ts +2 -2
  6. package/dist/cjs/components/_internal/base-radio.props.js +1 -1
  7. package/dist/cjs/components/_internal/base-radio.props.js.map +2 -2
  8. package/dist/cjs/components/checkbox-cards.d.ts.map +1 -1
  9. package/dist/cjs/components/checkbox-cards.js +1 -1
  10. package/dist/cjs/components/checkbox-cards.js.map +3 -3
  11. package/dist/cjs/components/checkbox-cards.props.d.ts +5 -0
  12. package/dist/cjs/components/checkbox-cards.props.d.ts.map +1 -1
  13. package/dist/cjs/components/checkbox-cards.props.js +1 -1
  14. package/dist/cjs/components/checkbox-cards.props.js.map +3 -3
  15. package/dist/cjs/components/checkbox-group.props.d.ts +2 -2
  16. package/dist/cjs/components/image.d.ts.map +1 -1
  17. package/dist/cjs/components/image.js +1 -1
  18. package/dist/cjs/components/image.js.map +2 -2
  19. package/dist/cjs/components/radio-cards.d.ts.map +1 -1
  20. package/dist/cjs/components/radio-cards.js +1 -1
  21. package/dist/cjs/components/radio-cards.js.map +3 -3
  22. package/dist/cjs/components/radio-cards.props.d.ts +5 -0
  23. package/dist/cjs/components/radio-cards.props.d.ts.map +1 -1
  24. package/dist/cjs/components/radio-cards.props.js +1 -1
  25. package/dist/cjs/components/radio-cards.props.js.map +3 -3
  26. package/dist/cjs/components/radio-group.props.d.ts +2 -2
  27. package/dist/cjs/components/radio-group.props.js +1 -1
  28. package/dist/cjs/components/radio-group.props.js.map +2 -2
  29. package/dist/cjs/components/segmented-control.props.d.ts +5 -0
  30. package/dist/cjs/components/segmented-control.props.d.ts.map +1 -1
  31. package/dist/cjs/components/segmented-control.props.js +1 -1
  32. package/dist/cjs/components/segmented-control.props.js.map +2 -2
  33. package/dist/esm/components/_internal/base-checkbox.props.d.ts +2 -2
  34. package/dist/esm/components/_internal/base-checkbox.props.js +1 -1
  35. package/dist/esm/components/_internal/base-checkbox.props.js.map +2 -2
  36. package/dist/esm/components/_internal/base-radio.props.d.ts +2 -2
  37. package/dist/esm/components/_internal/base-radio.props.js +1 -1
  38. package/dist/esm/components/_internal/base-radio.props.js.map +2 -2
  39. package/dist/esm/components/checkbox-cards.d.ts.map +1 -1
  40. package/dist/esm/components/checkbox-cards.js +1 -1
  41. package/dist/esm/components/checkbox-cards.js.map +3 -3
  42. package/dist/esm/components/checkbox-cards.props.d.ts +5 -0
  43. package/dist/esm/components/checkbox-cards.props.d.ts.map +1 -1
  44. package/dist/esm/components/checkbox-cards.props.js +1 -1
  45. package/dist/esm/components/checkbox-cards.props.js.map +3 -3
  46. package/dist/esm/components/checkbox-group.props.d.ts +2 -2
  47. package/dist/esm/components/image.d.ts.map +1 -1
  48. package/dist/esm/components/image.js +1 -1
  49. package/dist/esm/components/image.js.map +2 -2
  50. package/dist/esm/components/radio-cards.d.ts.map +1 -1
  51. package/dist/esm/components/radio-cards.js +1 -1
  52. package/dist/esm/components/radio-cards.js.map +3 -3
  53. package/dist/esm/components/radio-cards.props.d.ts +5 -0
  54. package/dist/esm/components/radio-cards.props.d.ts.map +1 -1
  55. package/dist/esm/components/radio-cards.props.js +1 -1
  56. package/dist/esm/components/radio-cards.props.js.map +3 -3
  57. package/dist/esm/components/radio-group.props.d.ts +2 -2
  58. package/dist/esm/components/radio-group.props.js +1 -1
  59. package/dist/esm/components/radio-group.props.js.map +2 -2
  60. package/dist/esm/components/segmented-control.props.d.ts +5 -0
  61. package/dist/esm/components/segmented-control.props.d.ts.map +1 -1
  62. package/dist/esm/components/segmented-control.props.js +1 -1
  63. package/dist/esm/components/segmented-control.props.js.map +2 -2
  64. package/package.json +1 -1
  65. package/src/components/_internal/base-button.css +1 -7
  66. package/src/components/_internal/base-card.css +31 -0
  67. package/src/components/_internal/base-checkbox.css +84 -24
  68. package/src/components/_internal/base-checkbox.props.ts +2 -2
  69. package/src/components/_internal/base-radio.css +68 -12
  70. package/src/components/_internal/base-radio.props.ts +2 -2
  71. package/src/components/badge.css +1 -1
  72. package/src/components/card.css +23 -60
  73. package/src/components/checkbox-cards.css +36 -14
  74. package/src/components/checkbox-cards.props.tsx +3 -0
  75. package/src/components/checkbox-cards.tsx +13 -6
  76. package/src/components/image.css +33 -9
  77. package/src/components/image.tsx +2 -1
  78. package/src/components/progress.css +29 -27
  79. package/src/components/radio-cards.css +33 -9
  80. package/src/components/radio-cards.props.tsx +3 -0
  81. package/src/components/radio-cards.tsx +10 -5
  82. package/src/components/radio-group.props.tsx +2 -2
  83. package/src/components/segmented-control.css +71 -26
  84. package/src/components/segmented-control.props.tsx +6 -0
  85. package/src/components/select.css +32 -32
  86. package/src/components/slider.css +19 -19
  87. package/src/components/switch.css +6 -6
  88. package/src/components/text-area.css +11 -11
  89. package/src/components/text-field.css +11 -11
  90. package/src/styles/tokens/constants.css +130 -15
  91. package/src/styles/tokens/transition.css +19 -0
  92. package/styles.css +827 -623
  93. package/tokens/base.css +8 -0
  94. package/tokens.css +79 -11
@@ -16,23 +16,47 @@
16
16
 
17
17
  @media (hover: hover) {
18
18
  &:where(:hover) {
19
- transform: scale(1.02);
20
19
  box-shadow:
21
20
  var(--box-shadow, var(--shadow-2)),
22
21
  0 0 0 1px var(--gray-a4);
22
+ filter: brightness(1.05) contrast(1.02);
23
23
  }
24
24
  }
25
25
 
26
+ &:where(:active) {
27
+ filter: brightness(0.98) contrast(1.02);
28
+ }
29
+
26
30
  &:where(:focus-visible) {
27
31
  outline: 2px solid var(--focus-8);
28
- outline-offset: 2px;
32
+ outline-offset: -2px;
33
+ }
34
+ }
35
+
36
+ /* Interactive states for asChild usage - target the wrapper element */
37
+ :where(:any-link, button, label) .rt-Image {
38
+ cursor: pointer;
39
+
40
+ @media (hover: hover) {
41
+ &:where(:hover) {
42
+ box-shadow:
43
+ var(--box-shadow, var(--shadow-2)),
44
+ 0 0 0 1px var(--gray-a4);
45
+ filter: brightness(1.05) contrast(1.02);
46
+ }
29
47
  }
30
48
 
31
49
  &:where(:active) {
32
- transform: scale(0.98);
50
+ filter: brightness(0.98) contrast(1.02);
33
51
  }
34
52
  }
35
53
 
54
+ /* Focus states for asChild usage - apply to the wrapper */
55
+ :where(:any-link, button, label):where(:focus-visible) .rt-Image {
56
+ outline: 2px solid var(--focus-8);
57
+ outline-offset: -2px;
58
+ }
59
+
36
60
  /* Blur variant wrapper */
37
61
  .rt-variant-blur {
38
62
  position: relative;
@@ -46,17 +70,17 @@
46
70
 
47
71
  @media (hover: hover) {
48
72
  &:where(:hover) {
49
- transform: scale(1.02);
73
+ filter: brightness(1.05) contrast(1.02);
50
74
  }
51
75
  }
52
76
 
53
- &:where(:focus-visible) {
54
- outline: 2px solid var(--focus-8);
55
- outline-offset: 2px;
77
+ &:where(:active) {
78
+ filter: brightness(0.98) contrast(1.02);
56
79
  }
57
80
 
58
- &:where(:active) {
59
- transform: scale(0.98);
81
+ &:where(:focus-visible) {
82
+ outline: 2px solid var(--focus-8);
83
+ outline-offset: -2px;
60
84
  }
61
85
  }
62
86
 
@@ -287,7 +287,7 @@ const Image = React.forwardRef<ImageElement, ImageProps>((props, forwardedRef) =
287
287
  } else {
288
288
  // For surface variant with asChild
289
289
  return React.cloneElement(child, {
290
- className: classNames(child.props?.className, 'rt-Image'),
290
+ className: classNames(child.props?.className),
291
291
  style: {
292
292
  textDecoration: 'none', // Reset link underlines
293
293
  color: 'inherit', // Reset link colors
@@ -296,6 +296,7 @@ const Image = React.forwardRef<ImageElement, ImageProps>((props, forwardedRef) =
296
296
  padding: 0, // Reset button padding
297
297
  font: 'inherit', // Reset button fonts
298
298
  cursor: 'pointer', // Ensure interactive cursor
299
+ display: 'inline-block', // Ensure proper sizing
299
300
  ...child.props?.style, // Allow user overrides
300
301
  },
301
302
  children: imageWithPlaceholder,
@@ -1,14 +1,14 @@
1
1
  .rt-ProgressRoot {
2
2
  --progress-value: 0;
3
3
  --progress-max: 100;
4
- --progress-duration: 5s;
4
+ --progress-duration: var(--progress-default-duration);
5
5
  pointer-events: none;
6
6
  position: relative;
7
7
  overflow: hidden;
8
8
  flex-grow: 1;
9
9
  height: var(--progress-height);
10
10
  border-radius: max(
11
- calc(var(--radius-factor) * var(--progress-height) / 3),
11
+ calc(var(--radius-factor) * var(--progress-height) / var(--progress-border-radius-factor)),
12
12
  calc(var(--radius-factor) * var(--radius-thumb))
13
13
  );
14
14
 
@@ -30,18 +30,18 @@
30
30
  }
31
31
  .rt-ProgressIndicator {
32
32
  display: block;
33
- height: 100%;
34
- width: 100%;
33
+ height: var(--position-full);
34
+ width: var(--position-full);
35
35
 
36
36
  transform: scaleX(calc(var(--progress-value) / var(--progress-max)));
37
37
  transform-origin: left center;
38
- transition: transform 120ms;
38
+ transition: var(--transition-progress);
39
39
 
40
40
  &:where([data-state='indeterminate']) {
41
41
  animation-name: rt-progress-indicator-indeterminate-grow, var(--progress-indicator-indeterminate-animation-start),
42
42
  var(--progress-indicator-indeterminate-animation-repeat);
43
- animation-delay: 0s, calc(var(--progress-duration) + 5s), calc(var(--progress-duration) + 7.5s);
44
- animation-duration: var(--progress-duration), 2.5s, 5s;
43
+ animation-delay: 0s, calc(var(--progress-duration) + var(--progress-animation-delay-start)), calc(var(--progress-duration) + var(--progress-animation-delay-shine));
44
+ animation-duration: var(--progress-duration), var(--progress-animation-duration-fade), var(--progress-animation-duration-pulse);
45
45
  animation-iteration-count: 1, 1, infinite;
46
46
  animation-fill-mode: both, none, none;
47
47
  animation-direction: normal, normal, alternate;
@@ -51,19 +51,19 @@
51
51
  position: absolute;
52
52
  inset: 0;
53
53
  content: '';
54
- width: 400%;
54
+ width: calc(var(--position-full) * var(--progress-shine-width-multiplier));
55
55
 
56
56
  animation-name: rt-progress-indicator-indeterminate-shine-from-left;
57
- animation-delay: calc(var(--progress-duration) + 5s);
58
- animation-duration: 5s;
57
+ animation-delay: calc(var(--progress-duration) + var(--progress-animation-delay-start));
58
+ animation-duration: var(--progress-animation-duration-pulse);
59
59
  animation-fill-mode: backwards;
60
60
  animation-iteration-count: infinite;
61
61
 
62
62
  background-image: linear-gradient(
63
63
  to right,
64
- transparent 25%,
64
+ transparent var(--progress-gradient-stop-start),
65
65
  var(--progress-indicator-after-linear-gradient),
66
- transparent 75%
66
+ transparent var(--progress-gradient-stop-end)
67
67
  );
68
68
  }
69
69
  }
@@ -71,29 +71,29 @@
71
71
 
72
72
  @keyframes rt-progress-indicator-indeterminate-grow {
73
73
  0% {
74
- transform: scaleX(0.01);
74
+ transform: scaleX(var(--progress-scale-initial));
75
75
  }
76
76
  20% {
77
- transform: scaleX(0.1);
77
+ transform: scaleX(var(--progress-scale-step-1));
78
78
  }
79
79
  30% {
80
- transform: scaleX(0.6);
80
+ transform: scaleX(var(--progress-scale-step-2));
81
81
  }
82
82
  40%,
83
83
  50% {
84
- transform: scaleX(0.9);
84
+ transform: scaleX(var(--progress-scale-step-3));
85
85
  }
86
86
  100% {
87
- transform: scaleX(1);
87
+ transform: scaleX(var(--progress-scale-final));
88
88
  }
89
89
  }
90
90
 
91
91
  @keyframes rt-progress-indicator-indeterminate-shine-from-left {
92
92
  0% {
93
- transform: translateX(-100%);
93
+ transform: translateX(var(--position-negative-full));
94
94
  }
95
95
  100% {
96
- transform: translateX(0%);
96
+ transform: translateX(var(--position-zero));
97
97
  }
98
98
  }
99
99
 
@@ -109,7 +109,7 @@
109
109
  --progress-height: var(--space-1);
110
110
  }
111
111
  &:where(.rt-r-size-2) {
112
- --progress-height: calc(var(--space-2) * 0.75);
112
+ --progress-height: calc(var(--space-2) * var(--size-multiplier-small));
113
113
  }
114
114
  &:where(.rt-r-size-3) {
115
115
  --progress-height: var(--space-2);
@@ -131,7 +131,7 @@
131
131
  background-color: var(--gray-a3);
132
132
 
133
133
  &::after {
134
- box-shadow: inset 0 0 0 1px var(--gray-a4);
134
+ box-shadow: inset 0 0 0 var(--border-width-standard) var(--gray-a4);
135
135
  }
136
136
 
137
137
  & :where(.rt-ProgressIndicator) {
@@ -159,10 +159,12 @@
159
159
  .rt-ProgressRoot:where(.rt-variant-classic) {
160
160
  --progress-indicator-indeterminate-animation-start: rt-progress-indicator-classic-indeterminate-fade;
161
161
  --progress-indicator-indeterminate-animation-repeat: rt-progress-indicator-classic-indeterminate-pulse;
162
+ position: relative;
163
+ top: calc(var(--classic-elevation-offset) / var(--classic-elevation-factor-subtle));
162
164
  background-color: var(--gray-a3);
163
165
 
164
166
  &::after {
165
- box-shadow: var(--shadow-1);
167
+ box-shadow: var(--classic-inset-shadow-dark);
166
168
  }
167
169
 
168
170
  & :where(.rt-ProgressIndicator) {
@@ -199,7 +201,7 @@
199
201
  background-color: var(--accent-8);
200
202
 
201
203
  &::after {
202
- opacity: 0.75;
204
+ opacity: var(--opacity-soft-variant);
203
205
  }
204
206
  }
205
207
  }
@@ -228,22 +230,22 @@
228
230
  background-color: var(--accent-12);
229
231
 
230
232
  &::after {
231
- opacity: 0.75;
233
+ opacity: var(--opacity-soft-variant);
232
234
  }
233
235
  }
234
236
  }
235
237
 
236
238
  @keyframes rt-progress-indicator-high-contrast-indeterminate-fade {
237
239
  100% {
238
- opacity: 0.8;
240
+ opacity: var(--opacity-high-contrast);
239
241
  }
240
242
  }
241
243
 
242
244
  @keyframes rt-progress-indicator-high-contrast-indeterminate-pulse {
243
245
  0% {
244
- opacity: 0.8;
246
+ opacity: var(--opacity-high-contrast);
245
247
  }
246
248
  100% {
247
- opacity: 1;
249
+ opacity: var(--progress-scale-final);
248
250
  }
249
251
  }
@@ -1,4 +1,5 @@
1
1
  @import './_internal/base-card.css';
2
+ @import './_internal/base-radio.css';
2
3
 
3
4
  .rt-RadioCardsRoot {
4
5
  line-height: var(--line-height);
@@ -47,7 +48,7 @@
47
48
  --line-height: var(--line-height-2);
48
49
  --letter-spacing: var(--letter-spacing-2);
49
50
  --radio-cards-item-padding-x: var(--space-3);
50
- --radio-cards-item-padding-y: calc(var(--space-3) / 1.2);
51
+ --radio-cards-item-padding-y: calc(var(--space-3) * var(--spacing-multiplier-medium));
51
52
  --radio-cards-item-border-radius: var(--radius-3);
52
53
  }
53
54
  /* 48px height for the card with one line of text */
@@ -56,7 +57,7 @@
56
57
  --line-height: var(--line-height-2);
57
58
  --letter-spacing: var(--letter-spacing-2);
58
59
  --radio-cards-item-padding-x: var(--space-4);
59
- --radio-cards-item-padding-y: calc(var(--space-4) * 0.875);
60
+ --radio-cards-item-padding-y: calc(var(--space-4) * var(--spacing-multiplier-medium));
60
61
  --radio-cards-item-border-radius: var(--radius-3);
61
62
  }
62
63
  /* 64px height for the card with one line of text */
@@ -65,7 +66,7 @@
65
66
  --line-height: var(--line-height-3);
66
67
  --letter-spacing: var(--letter-spacing-3);
67
68
  --radio-cards-item-padding-x: var(--space-5);
68
- --radio-cards-item-padding-y: calc(var(--space-5) / 1.2);
69
+ --radio-cards-item-padding-y: calc(var(--space-5) * var(--spacing-multiplier-medium));
69
70
  --radio-cards-item-border-radius: var(--radius-4);
70
71
  }
71
72
  }
@@ -79,9 +80,11 @@
79
80
 
80
81
  :where(.rt-RadioCardsRoot.rt-variant-surface) {
81
82
  .rt-RadioCardsItem {
82
- --radio-cards-item-border-width: 1px;
83
+ --radio-cards-item-border-width: var(--border-width-standard);
83
84
  --radio-cards-item-background-color: var(--color-surface);
84
85
 
86
+ transition: var(--transition-card);
87
+
85
88
  &::before {
86
89
  background-color: var(--radio-cards-item-background-color);
87
90
  }
@@ -90,12 +93,22 @@
90
93
  }
91
94
  @media (hover: hover) {
92
95
  &:where(:not(:disabled):not([data-state='checked']):hover) {
96
+ transition-duration: var(--duration-1);
93
97
  &::after {
94
98
  box-shadow: var(--base-card-surface-hover-box-shadow);
95
99
  }
96
100
  }
97
101
  }
98
102
  }
103
+
104
+ /* Component-level panel background overrides (higher specificity) */
105
+ &:where([data-panel-background='solid']) .rt-RadioCardsItem {
106
+ --color-surface: var(--color-surface-solid);
107
+ }
108
+
109
+ &:where([data-panel-background='translucent']) .rt-RadioCardsItem {
110
+ --color-surface: var(--color-surface-translucent);
111
+ }
99
112
  }
100
113
 
101
114
  /* * * * * * * * * * * * * * * * * * * */
@@ -106,10 +119,10 @@
106
119
 
107
120
  :where(.rt-RadioCardsRoot.rt-variant-classic) {
108
121
  .rt-RadioCardsItem {
109
- --radio-cards-item-border-width: 1px;
122
+ --radio-cards-item-border-width: var(--border-width-standard);
110
123
  --radio-cards-item-background-color: var(--color-surface);
111
124
 
112
- transition: box-shadow 120ms;
125
+ transition: var(--transition-card);
113
126
  box-shadow: var(--base-card-classic-box-shadow-outer);
114
127
 
115
128
  &::before {
@@ -120,7 +133,7 @@
120
133
  }
121
134
  @media (hover: hover) {
122
135
  &:where(:not(:disabled):not([data-state='checked']):hover) {
123
- transition-duration: 40ms;
136
+ transition-duration: var(--duration-1);
124
137
  box-shadow: var(--base-card-classic-hover-box-shadow-outer);
125
138
  &::after {
126
139
  box-shadow: var(--base-card-classic-hover-box-shadow-inner);
@@ -128,6 +141,15 @@
128
141
  }
129
142
  }
130
143
  }
144
+
145
+ /* Component-level panel background overrides (higher specificity) */
146
+ &:where([data-panel-background='solid']) .rt-RadioCardsItem {
147
+ --color-surface: var(--color-surface-solid);
148
+ }
149
+
150
+ &:where([data-panel-background='translucent']) .rt-RadioCardsItem {
151
+ --color-surface: var(--color-surface-translucent);
152
+ }
131
153
  }
132
154
 
133
155
  /* * * * * * * * * * * * * * * * * * * */
@@ -137,8 +159,9 @@
137
159
  /* * * * * * * * * * * * * * * * * * * */
138
160
 
139
161
  .rt-RadioCardsItem:where([data-state='checked']) {
162
+ transition: var(--transition-fast);
140
163
  &::after {
141
- outline: 2px solid var(--accent-indicator);
164
+ outline: var(--focus-outline-width) solid var(--accent-indicator);
142
165
  }
143
166
  :where(.rt-RadioCardsRoot.rt-high-contrast) & {
144
167
  &::after {
@@ -154,8 +177,9 @@
154
177
  /* * * * * * * * * * * * * * * * * * * */
155
178
 
156
179
  .rt-RadioCardsItem:where(:focus-visible) {
180
+ transition: var(--transition-focus);
157
181
  &::after {
158
- outline: 2px solid var(--focus-8);
182
+ outline: var(--focus-outline-width) solid var(--focus-8);
159
183
  }
160
184
  &:where([data-state='checked']) {
161
185
  &::before {
@@ -7,11 +7,13 @@ import type { PropDef } from '../props/prop-def.js';
7
7
 
8
8
  const sizes = ['1', '2', '3'] as const;
9
9
  const variants = ['surface', 'classic'] as const;
10
+ const panelBackgrounds = ['solid', 'translucent'] as const;
10
11
 
11
12
  const radioCardsRootPropDefs = {
12
13
  ...asChildPropDef,
13
14
  size: { type: 'enum', className: 'rt-r-size', values: sizes, default: '2', responsive: true },
14
15
  variant: { type: 'enum', className: 'rt-variant', values: variants, default: 'surface' },
16
+ panelBackground: { type: 'enum', values: panelBackgrounds, default: undefined },
15
17
  ...colorPropDef,
16
18
  ...highContrastPropDef,
17
19
  columns: { ...gridPropDefs.columns, default: 'repeat(auto-fit, minmax(160px, 1fr))' },
@@ -19,6 +21,7 @@ const radioCardsRootPropDefs = {
19
21
  } satisfies {
20
22
  size: PropDef<(typeof sizes)[number]>;
21
23
  variant: PropDef<(typeof variants)[number]>;
24
+ panelBackground: PropDef<(typeof panelBackgrounds)[number] | undefined>;
22
25
  columns: PropDef<(typeof gridPropDefs.columns.values)[number]>;
23
26
  gap: PropDef<(typeof gridPropDefs.gap.values)[number]>;
24
27
  };
@@ -6,6 +6,7 @@ import { radioCardsRootPropDefs } from './radio-cards.props.js';
6
6
  import { Grid } from './grid.js';
7
7
  import { extractProps } from '../helpers/extract-props.js';
8
8
  import { marginPropDefs } from '../props/margin.props.js';
9
+ import { useThemeContext } from './theme.js';
9
10
 
10
11
  import type { MarginProps } from '../props/margin.props.js';
11
12
  import type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';
@@ -22,15 +23,19 @@ interface RadioCardsRootProps
22
23
  RadioCardsRootOwnProps {}
23
24
  const RadioCardsRoot = React.forwardRef<RadioCardsRootElement, RadioCardsRootProps>(
24
25
  (props, forwardedRef) => {
25
- const { className, color, ...rootProps } = extractProps(
26
- props,
27
- radioCardsRootPropDefs,
28
- marginPropDefs,
29
- );
26
+ const themeContext = useThemeContext();
27
+ const panelBackground = props.panelBackground ?? themeContext.panelBackground;
28
+ const {
29
+ className,
30
+ color,
31
+ panelBackground: _,
32
+ ...rootProps
33
+ } = extractProps(props, radioCardsRootPropDefs, marginPropDefs);
30
34
  return (
31
35
  <Grid asChild>
32
36
  <RadioGroupPrimitive.Root
33
37
  data-accent-color={color}
38
+ data-panel-background={panelBackground}
34
39
  {...rootProps}
35
40
  ref={forwardedRef}
36
41
  className={classNames('rt-RadioCardsRoot', className)}
@@ -5,12 +5,12 @@ import { highContrastPropDef } from '../props/high-contrast.prop.js';
5
5
  import type { PropDef } from '../props/prop-def.js';
6
6
 
7
7
  const sizes = ['1', '2', '3'] as const;
8
- const variants = ['classic', 'surface', 'soft'] as const;
8
+ const variants = ['classic', 'solid', 'soft'] as const;
9
9
 
10
10
  const radioGroupRootPropDefs = {
11
11
  ...asChildPropDef,
12
12
  size: { type: 'enum', className: 'rt-r-size', values: sizes, default: '2', responsive: true },
13
- variant: { type: 'enum', className: 'rt-variant', values: variants, default: 'surface' },
13
+ variant: { type: 'enum', className: 'rt-variant', values: variants, default: 'solid' },
14
14
  ...colorPropDef,
15
15
  ...highContrastPropDef,
16
16
  } satisfies {
@@ -1,5 +1,6 @@
1
1
  .radix-themes {
2
- --segmented-control-transition-duration: 100ms;
2
+ /* Use standard duration token instead of custom duration */
3
+ --segmented-control-transition-duration: var(--duration-1); /* 100ms - Fast transitions */
3
4
  }
4
5
 
5
6
  .rt-SegmentedControlRoot {
@@ -20,6 +21,33 @@
20
21
 
21
22
  /* Create a new stacking context */
22
23
  isolation: isolate;
24
+
25
+ /* Theme-level translucent override */
26
+ :where([data-panel-background='translucent']) & {
27
+ background-color: var(--color-surface-translucent);
28
+ background-image: linear-gradient(var(--gray-a3), var(--gray-a3));
29
+ backdrop-filter: var(--backdrop-filter-panel);
30
+ }
31
+
32
+ /* Component-level overrides (higher specificity) */
33
+ &:where([data-panel-background='solid']) {
34
+ background-color: var(--color-surface);
35
+ background-image: linear-gradient(var(--gray-a3), var(--gray-a3));
36
+ backdrop-filter: none;
37
+ --backdrop-filter-panel: none;
38
+ }
39
+
40
+ &:where([data-panel-background='translucent']) {
41
+ background-color: var(--color-surface-translucent);
42
+ background-image: linear-gradient(var(--gray-a3), var(--gray-a3));
43
+ backdrop-filter: var(--backdrop-filter-panel);
44
+ --backdrop-filter-panel: blur(var(--backdrop-blur-panel));
45
+ }
46
+
47
+ /* Disable backdrop-filter when inside elements that already have backdrop-filter */
48
+ :where(.rt-PopoverContent, .rt-BaseDialogContent, .rt-BaseMenuContent, .rt-DropdownMenuContent, .rt-ContextMenuContent, .rt-AlertDialogContent, .rt-HoverCardContent, .rt-TooltipContent, .rt-Card) & {
49
+ backdrop-filter: none !important;
50
+ }
23
51
  }
24
52
 
25
53
  .rt-SegmentedControlRoot:where([data-disabled]) {
@@ -42,8 +70,8 @@
42
70
  }
43
71
  &:where(:focus-visible) {
44
72
  border-radius: inherit;
45
- outline: 2px solid var(--focus-8);
46
- outline-offset: -1px;
73
+ outline: var(--focus-outline-width) solid var(--focus-8);
74
+ outline-offset: var(--focus-outline-offset-inset);
47
75
  }
48
76
  }
49
77
 
@@ -70,30 +98,30 @@
70
98
  .rt-SegmentedControlItemLabelInactive {
71
99
  position: absolute;
72
100
 
73
- transition: opacity calc(0.8 * var(--segmented-control-transition-duration));
101
+ transition: var(--transition-tabs);
74
102
  font-weight: var(--font-weight-regular);
75
103
  letter-spacing: var(--tab-inactive-letter-spacing);
76
104
  word-spacing: var(--tab-inactive-word-spacing);
77
105
 
78
106
  opacity: 1;
79
- transition-timing-function: ease-out;
107
+ transition-delay: var(--duration-1); /* Staggered effect like tabs */
80
108
  :where(.rt-SegmentedControlItem[data-state='on']) & {
81
109
  opacity: 0;
82
- transition-timing-function: ease-in;
110
+ transition-delay: 0ms; /* Immediate transition for state change */
83
111
  }
84
112
  }
85
113
 
86
114
  .rt-SegmentedControlItemLabelActive {
87
- transition: opacity calc(0.8 * var(--segmented-control-transition-duration));
115
+ transition: var(--transition-tabs);
88
116
  font-weight: var(--font-weight-medium);
89
117
  letter-spacing: var(--tab-active-letter-spacing);
90
118
  word-spacing: var(--tab-active-word-spacing);
91
119
 
92
120
  opacity: 0;
93
- transition-timing-function: ease-in;
121
+ transition-delay: 0ms; /* Immediate transition for active state like tabs */
94
122
  :where(.rt-SegmentedControlItem[data-state='on']) & {
95
123
  opacity: 1;
96
- transition-timing-function: ease-out;
124
+ transition-delay: 0ms; /* Immediate transition for active state */
97
125
  }
98
126
  }
99
127
 
@@ -105,22 +133,21 @@
105
133
  */
106
134
  z-index: -1;
107
135
 
108
- margin-top: 3px;
109
- margin-bottom: 3px;
110
- margin-left: -0.5px;
111
- margin-right: -0.5px;
112
- width: 1px;
136
+ margin-top: calc(var(--space-1) * 0.75); /* 3px - slightly smaller than space-1 */
137
+ margin-bottom: calc(var(--space-1) * 0.75); /* 3px */
138
+ margin-left: calc(-1 * var(--border-width-standard) * 0.5); /* -0.5px */
139
+ margin-right: calc(-1 * var(--border-width-standard) * 0.5); /* -0.5px */
140
+ width: var(--border-width-standard); /* 1px */
113
141
  background-color: var(--gray-a4);
114
- transition: opacity calc(0.8 * var(--segmented-control-transition-duration));
142
+ transition: opacity calc(0.8 * var(--segmented-control-transition-duration)) var(--ease-1);
115
143
 
116
144
  /* Make separators slow to disappear and fast to appear, syncing it well with the indicator motion */
117
- transition-timing-function: ease-out;
118
145
 
119
146
  :where(.rt-SegmentedControlItem:first-child) &,
120
147
  :where(.rt-SegmentedControlItem:where([data-state='on'], :focus-visible)) &,
121
148
  :where(.rt-SegmentedControlItem:where([data-state='on'], :focus-visible)) + * & {
122
149
  opacity: 0;
123
- transition-timing-function: ease-in;
150
+ transition-timing-function: var(--ease-1);
124
151
  }
125
152
  /* Don't transition when the separator is hidden because of the focus outline */
126
153
  :where(.rt-SegmentedControlRoot:has(:focus-visible)) & {
@@ -144,14 +171,12 @@
144
171
  left: 0;
145
172
  height: 100%;
146
173
  pointer-events: none;
147
- transition-property: transform;
148
- transition-timing-function: cubic-bezier(0.445, 0.05, 0.55, 0.95);
149
- transition-duration: var(--segmented-control-transition-duration);
174
+ transition: transform var(--segmented-control-transition-duration) var(--ease-3);
150
175
 
151
176
  &::before {
152
- inset: 1px;
177
+ inset: var(--border-width-standard); /* 1px */
153
178
  position: absolute;
154
- border-radius: max(0.5px, calc(var(--segmented-control-border-radius) - 1px));
179
+ border-radius: max(calc(var(--border-width-standard) * 0.5), calc(var(--segmented-control-border-radius) - var(--border-width-standard)));
155
180
  background-color: var(--segmented-control-indicator-background-color);
156
181
  content: '';
157
182
  }
@@ -164,7 +189,7 @@
164
189
  --segmented-control-indicator-background-color: var(--gray-a3);
165
190
 
166
191
  &::before {
167
- inset: 0px;
192
+ inset: 0;
168
193
  box-shadow: none;
169
194
  }
170
195
  }
@@ -248,7 +273,7 @@
248
273
  @breakpoints {
249
274
  .rt-SegmentedControlRoot {
250
275
  &:where(.rt-r-size-1) {
251
- --segmented-control-border-radius: max(var(--radius-2), var(--radius-full));
276
+ --segmented-control-border-radius: max(calc(var(--radius-1) * var(--spacing-multiplier-large)), var(--radius-full));
252
277
  height: var(--space-5);
253
278
 
254
279
  & :where(.rt-SegmentedControlItemLabel) {
@@ -295,7 +320,7 @@
295
320
  .rt-SegmentedControlRoot:where(.rt-variant-surface) {
296
321
  & :where(.rt-SegmentedControlItem:not([disabled])) ~ :where(.rt-SegmentedControlIndicator) {
297
322
  &::before {
298
- box-shadow: 0 0 0 1px var(--gray-a4);
323
+ box-shadow: 0 0 0 var(--border-width-standard) var(--gray-a4);
299
324
  }
300
325
  }
301
326
  }
@@ -309,7 +334,27 @@
309
334
  .rt-SegmentedControlRoot:where(.rt-variant-classic) {
310
335
  & :where(.rt-SegmentedControlItem:not([disabled])) ~ :where(.rt-SegmentedControlIndicator) {
311
336
  &::before {
312
- box-shadow: var(--shadow-2);
337
+ /* Use the same elevated 3D effect as Button classic variant */
338
+ /* prettier-ignore */
339
+ box-shadow:
340
+ inset 0 calc(-1 * var(--classic-border-width)) var(--classic-shadow-blur-large) var(--gray-a2),
341
+ inset 0 var(--classic-border-width) var(--white-a12),
342
+ inset 0 var(--classic-shadow-blur-medium) var(--classic-shadow-blur-large) var(--gray-a2),
343
+ inset 0 calc(-1 * var(--classic-border-width)) var(--gray-a6),
344
+ 0 0 0 var(--classic-border-width) var(--gray-a5),
345
+ 0 var(--classic-shadow-offset-y) var(--classic-shadow-blur-small) var(--gray-a7);
346
+
347
+ :where(.dark, .dark-theme) &,
348
+ :where(.dark, .dark-theme) :where(.radix-themes:not(.light, .light-theme)) & {
349
+ /* prettier-ignore */
350
+ box-shadow:
351
+ inset 0 calc(-1 * var(--classic-border-width)) var(--classic-shadow-blur-large) var(--gray-a3),
352
+ inset 0 var(--classic-border-width) var(--gray-a11),
353
+ inset 0 var(--classic-shadow-blur-medium) var(--classic-shadow-blur-large) var(--gray-a2),
354
+ inset 0 calc(-2 * var(--classic-border-width)) var(--black-a11),
355
+ 0 0 0 var(--classic-border-width-thick) var(--gray-a7),
356
+ 0 var(--classic-shadow-offset-y) var(--classic-shadow-blur-small) var(--black-a12);
357
+ }
313
358
  }
314
359
  }
315
360
  }
@@ -9,11 +9,17 @@ const segmentedControlRootPropDefs = {
9
9
  disabled: { type: 'boolean', className: 'disabled', default: false },
10
10
  size: { type: 'enum', className: 'rt-r-size', values: sizes, default: '2', responsive: true },
11
11
  variant: { type: 'enum', className: 'rt-variant', values: variants, default: 'surface' },
12
+ panelBackground: {
13
+ type: 'enum',
14
+ className: 'rt-panel-background',
15
+ values: ['solid', 'translucent'],
16
+ },
12
17
  ...radiusPropDef,
13
18
  } satisfies {
14
19
  disabled?: PropDef<boolean>;
15
20
  size: PropDef<(typeof sizes)[number]>;
16
21
  variant: PropDef<(typeof variants)[number]>;
22
+ panelBackground: PropDef<'solid' | 'translucent'>;
17
23
  };
18
24
 
19
25
  export { segmentedControlRootPropDefs };