@kushagradhawan/kookie-ui 0.1.78 → 0.1.79

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 (38) hide show
  1. package/components.css +69 -29
  2. package/dist/cjs/components/combobox.d.ts +57 -7
  3. package/dist/cjs/components/combobox.d.ts.map +1 -1
  4. package/dist/cjs/components/combobox.js +1 -1
  5. package/dist/cjs/components/combobox.js.map +3 -3
  6. package/dist/cjs/components/text-field.d.ts +2 -2
  7. package/dist/cjs/components/text-field.d.ts.map +1 -1
  8. package/dist/cjs/components/text-field.js +2 -2
  9. package/dist/cjs/components/text-field.js.map +3 -3
  10. package/dist/cjs/components/text-field.props.d.ts +26 -0
  11. package/dist/cjs/components/text-field.props.d.ts.map +1 -1
  12. package/dist/cjs/components/text-field.props.js +1 -1
  13. package/dist/cjs/components/text-field.props.js.map +1 -1
  14. package/dist/esm/components/combobox.d.ts +57 -7
  15. package/dist/esm/components/combobox.d.ts.map +1 -1
  16. package/dist/esm/components/combobox.js +1 -1
  17. package/dist/esm/components/combobox.js.map +3 -3
  18. package/dist/esm/components/text-field.d.ts +2 -2
  19. package/dist/esm/components/text-field.d.ts.map +1 -1
  20. package/dist/esm/components/text-field.js +2 -2
  21. package/dist/esm/components/text-field.js.map +3 -3
  22. package/dist/esm/components/text-field.props.d.ts +26 -0
  23. package/dist/esm/components/text-field.props.d.ts.map +1 -1
  24. package/dist/esm/components/text-field.props.js +1 -1
  25. package/dist/esm/components/text-field.props.js.map +1 -1
  26. package/package.json +2 -2
  27. package/schemas/base-button.json +1 -1
  28. package/schemas/button.json +1 -1
  29. package/schemas/icon-button.json +1 -1
  30. package/schemas/index.json +6 -6
  31. package/schemas/toggle-button.json +1 -1
  32. package/schemas/toggle-icon-button.json +1 -1
  33. package/src/components/combobox.css +56 -55
  34. package/src/components/combobox.tsx +305 -73
  35. package/src/components/text-field.css +83 -0
  36. package/src/components/text-field.props.tsx +28 -0
  37. package/src/components/text-field.tsx +222 -5
  38. package/styles.css +69 -29
@@ -55,4 +55,32 @@ const textFieldSlotPropDefs = {
55
55
  pr: typeof paddingPropDefs.pr;
56
56
  };
57
57
 
58
+ /** Scrubbing props for TextField.Slot - handled separately from PropDef system */
59
+ interface TextFieldSlotScrubProps {
60
+ /** Enable scrubbing behavior on this slot */
61
+ scrub?: boolean;
62
+ /** Current value (required for min/max clamping to work correctly) */
63
+ scrubValue?: number;
64
+ /** Base value change per movement unit (default: 1) */
65
+ scrubStep?: number;
66
+ /** Pixels of movement per step - higher = less sensitive (default: 1) */
67
+ scrubSensitivity?: number;
68
+ /** Minimum allowed value */
69
+ scrubMin?: number;
70
+ /** Maximum allowed value */
71
+ scrubMax?: number;
72
+ /** Step multiplier when Shift is held (default: 10) */
73
+ scrubShiftMultiplier?: number;
74
+ /** Step multiplier when Alt/Option is held (default: 0.1) */
75
+ scrubAltMultiplier?: number;
76
+ /**
77
+ * Callback fired during scrubbing with the value delta
78
+ * @param delta - The change in value
79
+ * @param isChanging - true while dragging, false when released
80
+ */
81
+ onScrub?: (delta: number, isChanging: boolean) => void;
82
+ }
83
+
84
+ export type { TextFieldSlotScrubProps };
85
+
58
86
  export { textFieldRootPropDefs, textFieldSlotPropDefs };
@@ -1,10 +1,15 @@
1
1
  'use client';
2
2
 
3
3
  import * as React from 'react';
4
+ import * as ReactDOM from 'react-dom';
4
5
  import classNames from 'classnames';
5
6
  import { composeRefs } from 'radix-ui/internal';
6
7
 
7
- import { textFieldRootPropDefs, textFieldSlotPropDefs } from './text-field.props.js';
8
+ import {
9
+ textFieldRootPropDefs,
10
+ textFieldSlotPropDefs,
11
+ type TextFieldSlotScrubProps,
12
+ } from './text-field.props.js';
8
13
  import { extractProps } from '../helpers/extract-props.js';
9
14
  import { marginPropDefs } from '../props/margin.props.js';
10
15
 
@@ -139,21 +144,233 @@ const TextFieldRoot = React.forwardRef<TextFieldRootElement, TextFieldRootProps>
139
144
  TextFieldRoot.displayName = 'TextField.Root';
140
145
 
141
146
  type TextFieldSlotElement = React.ElementRef<'div'>;
142
- type TextFieldSlotOwnProps = GetPropDefTypes<typeof textFieldSlotPropDefs>;
147
+ type TextFieldSlotOwnProps = GetPropDefTypes<typeof textFieldSlotPropDefs> & TextFieldSlotScrubProps;
143
148
  interface TextFieldSlotProps
144
149
  extends ComponentPropsWithout<'div', RemovedProps>,
145
150
  TextFieldSlotOwnProps {}
146
151
  const TextFieldSlot = React.forwardRef<TextFieldSlotElement, TextFieldSlotProps>(
147
152
  (props, forwardedRef) => {
148
- const { className, color, side, ...slotProps } = extractProps(props, textFieldSlotPropDefs);
153
+ // Extract scrub props first (not part of PropDef system)
154
+ const {
155
+ scrub,
156
+ scrubValue,
157
+ scrubStep = 1,
158
+ scrubSensitivity = 1,
159
+ scrubMin,
160
+ scrubMax,
161
+ scrubShiftMultiplier = 10,
162
+ scrubAltMultiplier = 0.1,
163
+ onScrub,
164
+ ...restProps
165
+ } = props;
166
+
167
+ // Then extract styling props
168
+ const { className, color, side, ...slotProps } = extractProps(restProps, textFieldSlotPropDefs);
169
+
170
+ const slotRef = React.useRef<HTMLDivElement>(null);
171
+ const [isScrubbing, setIsScrubbing] = React.useState(false);
172
+ // Virtual cursor position - X wraps around viewport, Y follows mouse
173
+ const [cursorPosition, setCursorPosition] = React.useState({ x: 0, y: 0 });
174
+
175
+ // Track accumulated sub-step movement for precision
176
+ const accumulatedMovement = React.useRef(0);
177
+ // Track current value for clamping (initialized to scrubValue when scrubbing starts)
178
+ const currentValue = React.useRef(0);
179
+ // Track virtual X position for wrap-around (separate from rendered position)
180
+ const virtualX = React.useRef(0);
181
+
182
+ // Store scrub config in refs so document handlers can access latest values
183
+ const scrubConfigRef = React.useRef({
184
+ scrubValue,
185
+ scrubStep,
186
+ scrubSensitivity,
187
+ scrubMin,
188
+ scrubMax,
189
+ scrubShiftMultiplier,
190
+ scrubAltMultiplier,
191
+ onScrub,
192
+ });
193
+ scrubConfigRef.current = {
194
+ scrubValue,
195
+ scrubStep,
196
+ scrubSensitivity,
197
+ scrubMin,
198
+ scrubMax,
199
+ scrubShiftMultiplier,
200
+ scrubAltMultiplier,
201
+ onScrub,
202
+ };
203
+
204
+ const handlePointerDown = React.useCallback(
205
+ (event: React.PointerEvent) => {
206
+ if (!scrub) return;
207
+
208
+ // Don't start scrubbing if clicking on interactive elements
209
+ const target = event.target as HTMLElement;
210
+ if (target.closest('input, button, a')) return;
211
+
212
+ event.preventDefault();
213
+ accumulatedMovement.current = 0;
214
+ // Initialize to current value so min/max clamping works correctly
215
+ currentValue.current = scrubValue ?? 0;
216
+
217
+ // Initialize virtual cursor at actual mouse position
218
+ virtualX.current = event.clientX;
219
+ setCursorPosition({ x: event.clientX, y: event.clientY });
220
+
221
+ // Request pointer lock for infinite movement (cursor won't hit screen edges)
222
+ const slot = slotRef.current;
223
+ if (slot) {
224
+ slot.requestPointerLock();
225
+ }
226
+ },
227
+ [scrub, scrubValue],
228
+ );
229
+
230
+ // Handle pointer lock state changes
231
+ React.useEffect(() => {
232
+ const handlePointerLockChange = () => {
233
+ const isLocked = document.pointerLockElement === slotRef.current;
234
+ setIsScrubbing(isLocked);
235
+ if (!isLocked) {
236
+ // Fire callback with isChanging = false when scrubbing ends
237
+ scrubConfigRef.current.onScrub?.(0, false);
238
+ accumulatedMovement.current = 0;
239
+ currentValue.current = 0;
240
+ }
241
+ };
242
+
243
+ document.addEventListener('pointerlockchange', handlePointerLockChange);
244
+ return () => {
245
+ document.removeEventListener('pointerlockchange', handlePointerLockChange);
246
+ };
247
+ }, []);
248
+
249
+ // Attach document-level listeners when scrubbing starts
250
+ React.useEffect(() => {
251
+ if (!isScrubbing) return;
252
+
253
+ const handleMouseMove = (event: MouseEvent) => {
254
+ const config = scrubConfigRef.current;
255
+ const movementX = event.movementX;
256
+ const movementY = event.movementY;
257
+ const viewportWidth = window.innerWidth;
258
+ const viewportHeight = window.innerHeight;
259
+
260
+ // Update virtual position with wrap-around at viewport edges
261
+ virtualX.current += movementX;
262
+ if (virtualX.current > viewportWidth) {
263
+ virtualX.current = virtualX.current % viewportWidth;
264
+ } else if (virtualX.current < 0) {
265
+ virtualX.current = viewportWidth + (virtualX.current % viewportWidth);
266
+ }
267
+
268
+ // Also track Y with wrap-around
269
+ setCursorPosition((prev) => {
270
+ let newY = prev.y + movementY;
271
+ if (newY > viewportHeight) {
272
+ newY = newY % viewportHeight;
273
+ } else if (newY < 0) {
274
+ newY = viewportHeight + (newY % viewportHeight);
275
+ }
276
+ return { x: virtualX.current, y: newY };
277
+ });
278
+
279
+ // Accumulate movement for sensitivity calculation
280
+ accumulatedMovement.current += movementX;
281
+
282
+ // Calculate how many steps we've moved
283
+ const stepsFromMovement = accumulatedMovement.current / config.scrubSensitivity;
284
+
285
+ if (Math.abs(stepsFromMovement) >= 1) {
286
+ // Determine modifier multiplier
287
+ let multiplier = 1;
288
+ if (event.shiftKey) {
289
+ multiplier = config.scrubShiftMultiplier;
290
+ } else if (event.altKey) {
291
+ multiplier = config.scrubAltMultiplier;
292
+ }
293
+
294
+ // Calculate delta
295
+ const wholeSteps = Math.trunc(stepsFromMovement);
296
+ const delta = wholeSteps * config.scrubStep * multiplier;
297
+
298
+ // Apply min/max clamping if bounds are set
299
+ let clampedDelta = delta;
300
+ if (config.scrubMin !== undefined || config.scrubMax !== undefined) {
301
+ const newValue = currentValue.current + delta;
302
+ const clampedValue = Math.max(
303
+ config.scrubMin ?? -Infinity,
304
+ Math.min(config.scrubMax ?? Infinity, newValue),
305
+ );
306
+ clampedDelta = clampedValue - currentValue.current;
307
+ currentValue.current = clampedValue;
308
+ } else {
309
+ currentValue.current += delta;
310
+ }
311
+
312
+ // Fire callback with clamped delta (isChanging = true during drag)
313
+ if (clampedDelta !== 0) {
314
+ config.onScrub?.(clampedDelta, true);
315
+ }
316
+
317
+ // Keep the fractional remainder for smooth sub-pixel accumulation
318
+ accumulatedMovement.current = (stepsFromMovement - wholeSteps) * config.scrubSensitivity;
319
+ }
320
+ };
321
+
322
+ const handleMouseUp = () => {
323
+ // Exit pointer lock to end scrubbing
324
+ document.exitPointerLock();
325
+ };
326
+
327
+ // Use mousemove for pointer lock (pointermove doesn't work well with pointer lock)
328
+ document.addEventListener('mousemove', handleMouseMove);
329
+ document.addEventListener('mouseup', handleMouseUp);
330
+
331
+ // Disable text selection during scrubbing
332
+ document.body.style.userSelect = 'none';
333
+
334
+ return () => {
335
+ document.removeEventListener('mousemove', handleMouseMove);
336
+ document.removeEventListener('mouseup', handleMouseUp);
337
+ document.body.style.userSelect = '';
338
+ };
339
+ }, [isScrubbing]);
340
+
341
+ // Render virtual cursor via portal to body so it's not clipped
342
+ const virtualCursor = isScrubbing
343
+ ? ReactDOM.createPortal(
344
+ <div
345
+ className="rt-TextFieldSlotScrubCursor"
346
+ style={{
347
+ position: 'fixed',
348
+ left: cursorPosition.x,
349
+ top: cursorPosition.y,
350
+ transform: 'translate(-50%, -50%)',
351
+ pointerEvents: 'none',
352
+ zIndex: 99999,
353
+ }}
354
+ aria-hidden="true"
355
+ />,
356
+ document.body,
357
+ )
358
+ : null;
359
+
149
360
  return (
150
361
  <div
151
362
  data-accent-color={color}
152
363
  data-side={side}
364
+ data-scrub={scrub || undefined}
365
+ data-scrubbing={isScrubbing || undefined}
153
366
  {...slotProps}
154
- ref={forwardedRef}
367
+ ref={composeRefs(slotRef, forwardedRef)}
155
368
  className={classNames('rt-TextFieldSlot', className)}
156
- />
369
+ onPointerDown={scrub ? handlePointerDown : undefined}
370
+ >
371
+ {slotProps.children}
372
+ {virtualCursor}
373
+ </div>
157
374
  );
158
375
  },
159
376
  );
package/styles.css CHANGED
@@ -14902,12 +14902,68 @@
14902
14902
  font-size: var(--font-size-1);
14903
14903
  line-height: 1;
14904
14904
  }
14905
+ .rt-TextFieldSlot:where([data-scrub]){
14906
+ cursor: ew-resize !important;
14907
+ -webkit-user-select: none;
14908
+ -moz-user-select: none;
14909
+ user-select: none;
14910
+ position: relative;
14911
+ }
14912
+ .rt-TextFieldSlot:where([data-scrub]) *{
14913
+ cursor: ew-resize !important;
14914
+ }
14915
+ .rt-TextFieldSlot:where([data-scrubbing]){
14916
+ cursor: none;
14917
+ background-color: var(--accent-a3);
14918
+ border-radius: calc(var(--text-field-border-radius, var(--radius-2)) - 2px);
14919
+ }
14920
+ .rt-TextFieldSlot:where([data-scrubbing]) *{
14921
+ cursor: none;
14922
+ }
14923
+ .rt-TextFieldSlotScrubCursor{
14924
+ width: 20px;
14925
+ height: 20px;
14926
+ background-color: var(--accent-9);
14927
+ border-radius: 50%;
14928
+ pointer-events: none;
14929
+ box-shadow: 0 0 0 2px var(--color-background), 0 0 8px var(--accent-a8), 0 0 16px var(--accent-a6);
14930
+ }
14931
+ .rt-TextFieldSlotScrubCursor::before,
14932
+ .rt-TextFieldSlotScrubCursor::after{
14933
+ content: '';
14934
+ position: absolute;
14935
+ top: 50%;
14936
+ width: 0;
14937
+ height: 0;
14938
+ border-style: solid;
14939
+ transform: translateY(-50%);
14940
+ }
14941
+ .rt-TextFieldSlotScrubCursor::before{
14942
+ left: -10px;
14943
+ border-width: 5px 6px 5px 0;
14944
+ border-color: transparent var(--accent-9) transparent transparent;
14945
+ }
14946
+ .rt-TextFieldSlotScrubCursor::after{
14947
+ right: -10px;
14948
+ border-width: 5px 0 5px 6px;
14949
+ border-color: transparent transparent transparent var(--accent-9);
14950
+ }
14951
+ @media (prefers-reduced-motion: reduce) {
14952
+ .rt-TextFieldSlotScrubCursor{
14953
+ box-shadow: 0 0 0 2px var(--color-background);
14954
+ }
14955
+ }
14905
14956
  .rt-ComboboxContent{
14906
14957
  padding: 0 !important;
14907
14958
  max-height: var(--radix-popover-content-available-height);
14908
14959
  display: flex;
14909
14960
  flex-direction: column;
14910
14961
  }
14962
+ .rt-ComboboxContent:where([data-state='closed']){
14963
+ visibility: hidden;
14964
+ position: absolute;
14965
+ pointer-events: none;
14966
+ }
14911
14967
  .rt-ComboboxCommand{
14912
14968
  display: flex;
14913
14969
  flex-direction: column;
@@ -14935,6 +14991,8 @@
14935
14991
  .rt-BaseMenuContent :where(.rt-BaseMenuItem.rt-ComboboxItem[data-disabled='']){
14936
14992
  color: inherit !important;
14937
14993
  cursor: var(--cursor-menu-item) !important;
14994
+ opacity: 1 !important;
14995
+ pointer-events: auto !important;
14938
14996
  }
14939
14997
  .rt-ComboboxSearch{
14940
14998
  position: sticky;
@@ -14955,50 +15013,32 @@
14955
15013
  flex: 1;
14956
15014
  min-height: 0;
14957
15015
  }
14958
- .rt-BaseMenuContent:where(.rt-variant-solid) :where(.rt-BaseMenuItem.rt-ComboboxItem[data-selected='true']),
14959
- .rt-BaseMenuContent:where(.rt-variant-solid) :where(.rt-BaseMenuItem.rt-ComboboxItem[aria-selected='true']){
15016
+ .rt-BaseMenuContent:where(.rt-variant-solid) :where(.rt-ComboboxItem[data-selected='true']){
14960
15017
  background-color: var(--accent-9);
14961
15018
  color: var(--accent-contrast);
14962
15019
  }
14963
- .rt-BaseMenuContent:where(.rt-variant-solid) :where(.rt-BaseMenuItem.rt-ComboboxItem[data-selected='true']) :where(.rt-Text), .rt-BaseMenuContent:where(.rt-variant-solid) :where(.rt-BaseMenuItem.rt-ComboboxItem[aria-selected='true']) :where(.rt-Text){
14964
- color: inherit !important;
14965
- }
14966
- .rt-BaseMenuContent:where(.rt-variant-solid) :where(.rt-BaseMenuItem.rt-ComboboxItem[data-selected='true']) :where([data-accent-color='gray']:not(.rt-Badge)), .rt-BaseMenuContent:where(.rt-variant-solid) :where(.rt-BaseMenuItem.rt-ComboboxItem[aria-selected='true']) :where([data-accent-color='gray']:not(.rt-Badge)){
14967
- color: inherit !important;
14968
- }
14969
- .rt-BaseMenuContent:where(.rt-variant-soft) :where(.rt-BaseMenuItem.rt-ComboboxItem[data-selected='true']),
14970
- .rt-BaseMenuContent:where(.rt-variant-soft) :where(.rt-BaseMenuItem.rt-ComboboxItem[aria-selected='true']){
14971
- background-color: var(--accent-4);
14972
- }
14973
- :where([data-panel-background='translucent'], [data-material='translucent']) :is(.rt-BaseMenuContent:where(.rt-variant-soft) :where(.rt-BaseMenuItem.rt-ComboboxItem[data-selected='true'])), :where([data-panel-background='translucent'], [data-material='translucent']) :is(.rt-BaseMenuContent:where(.rt-variant-soft) :where(.rt-BaseMenuItem.rt-ComboboxItem[aria-selected='true'])){
14974
- background-color: var(--accent-a4);
15020
+ .rt-BaseMenuContent:where(.rt-variant-solid) :where(.rt-ComboboxItem[data-selected='true']) *{
15021
+ color: var(--accent-contrast) !important;
14975
15022
  }
14976
- .rt-BaseMenuContent:where(.rt-variant-soft) :where(.rt-BaseMenuItem.rt-ComboboxItem[data-selected='true']):where([data-panel-background='solid'], [data-material='solid']), .rt-BaseMenuContent:where(.rt-variant-soft) :where(.rt-BaseMenuItem.rt-ComboboxItem[aria-selected='true']):where([data-panel-background='solid'], [data-material='solid']){
15023
+ .rt-BaseMenuContent:where(.rt-variant-soft) :where(.rt-ComboboxItem[data-selected='true']){
14977
15024
  background-color: var(--accent-4);
14978
15025
  }
14979
- .rt-BaseMenuContent:where(.rt-variant-soft) :where(.rt-BaseMenuItem.rt-ComboboxItem[data-selected='true']):where([data-panel-background='translucent'], [data-material='translucent']), .rt-BaseMenuContent:where(.rt-variant-soft) :where(.rt-BaseMenuItem.rt-ComboboxItem[aria-selected='true']):where([data-panel-background='translucent'], [data-material='translucent']){
15026
+ :where([data-panel-background='translucent'], [data-material='translucent']) .rt-BaseMenuContent:where(.rt-variant-soft) :where(.rt-ComboboxItem[data-selected='true']){
14980
15027
  background-color: var(--accent-a4);
14981
15028
  }
14982
- .rt-BaseMenuContent:where(.rt-high-contrast) :where(.rt-BaseMenuItem.rt-ComboboxItem[data-selected='true']),
14983
- .rt-BaseMenuContent:where(.rt-high-contrast) :where(.rt-BaseMenuItem.rt-ComboboxItem[aria-selected='true']){
15029
+ .rt-BaseMenuContent:where(.rt-high-contrast) :where(.rt-ComboboxItem[data-selected='true']){
14984
15030
  background-color: var(--accent-12);
14985
15031
  color: var(--accent-1);
14986
15032
  }
14987
- .rt-BaseMenuContent:where(.rt-high-contrast) :where(.rt-BaseMenuItem.rt-ComboboxItem[data-selected='true']) :where(.rt-Text), .rt-BaseMenuContent:where(.rt-high-contrast) :where(.rt-BaseMenuItem.rt-ComboboxItem[aria-selected='true']) :where(.rt-Text){
14988
- color: inherit !important;
14989
- }
14990
- .rt-BaseMenuContent:where(.rt-high-contrast) :where(.rt-BaseMenuItem.rt-ComboboxItem[data-selected='true']) :where([data-accent-color='gray']:not(.rt-Badge)), .rt-BaseMenuContent:where(.rt-high-contrast) :where(.rt-BaseMenuItem.rt-ComboboxItem[aria-selected='true']) :where([data-accent-color='gray']:not(.rt-Badge)){
14991
- color: inherit !important;
15033
+ .rt-BaseMenuContent:where(.rt-high-contrast) :where(.rt-ComboboxItem[data-selected='true']) *{
15034
+ color: var(--accent-1) !important;
14992
15035
  }
14993
- .rt-BaseMenuContent:where(.rt-high-contrast) :where(.rt-BaseMenuItem.rt-ComboboxItem[data-selected='true']):where([data-accent-color]), .rt-BaseMenuContent:where(.rt-high-contrast) :where(.rt-BaseMenuItem.rt-ComboboxItem[aria-selected='true']):where([data-accent-color]){
15036
+ .rt-BaseMenuContent:where(.rt-high-contrast[data-accent-color]) :where(.rt-ComboboxItem[data-selected='true']){
14994
15037
  background-color: var(--accent-9);
14995
15038
  color: var(--accent-contrast);
14996
15039
  }
14997
- .rt-BaseMenuContent:where(.rt-high-contrast) :where(.rt-BaseMenuItem.rt-ComboboxItem[data-selected='true']):where([data-accent-color]) :where(.rt-Text), .rt-BaseMenuContent:where(.rt-high-contrast) :where(.rt-BaseMenuItem.rt-ComboboxItem[aria-selected='true']):where([data-accent-color]) :where(.rt-Text){
14998
- color: inherit !important;
14999
- }
15000
- .rt-BaseMenuContent:where(.rt-high-contrast) :where(.rt-BaseMenuItem.rt-ComboboxItem[data-selected='true']):where([data-accent-color]) :where([data-accent-color='gray']:not(.rt-Badge)), .rt-BaseMenuContent:where(.rt-high-contrast) :where(.rt-BaseMenuItem.rt-ComboboxItem[aria-selected='true']):where([data-accent-color]) :where([data-accent-color='gray']:not(.rt-Badge)){
15001
- color: inherit !important;
15040
+ .rt-BaseMenuContent:where(.rt-high-contrast[data-accent-color]) :where(.rt-ComboboxItem[data-selected='true']) *{
15041
+ color: var(--accent-contrast) !important;
15002
15042
  }
15003
15043
  .rt-Em{
15004
15044
  box-sizing: border-box;