jfs-components 0.0.21 → 0.0.24

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 (50) hide show
  1. package/lib/commonjs/assets/fonts/JioType Var.ttf +0 -0
  2. package/lib/commonjs/components/Carousel/Carousel.js +341 -0
  3. package/lib/commonjs/components/Carousel/Carousel.js.map +1 -0
  4. package/lib/commonjs/components/Carousel/Carousel.mdx +154 -0
  5. package/lib/commonjs/components/Drawer/Drawer.js +9 -2
  6. package/lib/commonjs/components/Drawer/Drawer.js.map +1 -1
  7. package/lib/commonjs/components/RadioButton/RadioButton.js +194 -0
  8. package/lib/commonjs/components/RadioButton/RadioButton.js.map +1 -0
  9. package/lib/commonjs/components/RadioButton/RadioButton.mdx +92 -0
  10. package/lib/commonjs/components/UpiHandle/UpiHandle.js +3 -1
  11. package/lib/commonjs/components/UpiHandle/UpiHandle.js.map +1 -1
  12. package/lib/commonjs/components/index.js +7 -0
  13. package/lib/commonjs/components/index.js.map +1 -1
  14. package/lib/commonjs/design-tokens/figma-variables-resolver.js +9 -3
  15. package/lib/commonjs/icons/registry.js +1 -1
  16. package/lib/module/assets/fonts/JioType Var.ttf +0 -0
  17. package/lib/module/components/Carousel/Carousel.js +333 -0
  18. package/lib/module/components/Carousel/Carousel.js.map +1 -0
  19. package/lib/module/components/Carousel/Carousel.mdx +154 -0
  20. package/lib/module/components/Drawer/Drawer.js +10 -3
  21. package/lib/module/components/Drawer/Drawer.js.map +1 -1
  22. package/lib/module/components/RadioButton/RadioButton.js +188 -0
  23. package/lib/module/components/RadioButton/RadioButton.js.map +1 -0
  24. package/lib/module/components/RadioButton/RadioButton.mdx +92 -0
  25. package/lib/module/components/UpiHandle/UpiHandle.js +3 -1
  26. package/lib/module/components/UpiHandle/UpiHandle.js.map +1 -1
  27. package/lib/module/components/index.js +1 -0
  28. package/lib/module/components/index.js.map +1 -1
  29. package/lib/module/icons/registry.js +1 -1
  30. package/lib/typescript/components/Carousel/Carousel.d.ts +48 -0
  31. package/lib/typescript/components/Carousel/Carousel.d.ts.map +1 -0
  32. package/lib/typescript/components/Drawer/Drawer.d.ts.map +1 -1
  33. package/lib/typescript/components/RadioButton/RadioButton.d.ts +30 -0
  34. package/lib/typescript/components/RadioButton/RadioButton.d.ts.map +1 -0
  35. package/lib/typescript/components/UpiHandle/UpiHandle.d.ts +4 -2
  36. package/lib/typescript/components/UpiHandle/UpiHandle.d.ts.map +1 -1
  37. package/lib/typescript/components/index.d.ts +1 -0
  38. package/lib/typescript/components/index.d.ts.map +1 -1
  39. package/lib/typescript/icons/registry.d.ts +1 -1
  40. package/package.json +3 -3
  41. package/src/assets/fonts/JioType Var.ttf +0 -0
  42. package/src/components/.token-metadata.json +72 -0
  43. package/src/components/Carousel/Carousel.mdx +154 -0
  44. package/src/components/Carousel/Carousel.tsx +472 -0
  45. package/src/components/Drawer/Drawer.tsx +10 -2
  46. package/src/components/RadioButton/RadioButton.mdx +92 -0
  47. package/src/components/RadioButton/RadioButton.tsx +226 -0
  48. package/src/components/UpiHandle/UpiHandle.tsx +5 -2
  49. package/src/components/index.ts +1 -0
  50. package/src/icons/registry.ts +1 -1
@@ -0,0 +1,472 @@
1
+ import React, {
2
+ createContext,
3
+ useContext,
4
+ useRef,
5
+ useState,
6
+ useEffect,
7
+ useCallback,
8
+ useMemo,
9
+ } from 'react'
10
+ import {
11
+ View,
12
+ ScrollView,
13
+ Animated,
14
+ Pressable,
15
+ type ViewStyle,
16
+ type StyleProp,
17
+ type NativeSyntheticEvent,
18
+ type NativeScrollEvent,
19
+ type LayoutChangeEvent,
20
+ } from 'react-native'
21
+ import { getVariableByName } from '../../design-tokens/figma-variables-resolver'
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Context
25
+ // ---------------------------------------------------------------------------
26
+
27
+ interface CarouselContextValue {
28
+ modes: Record<string, any>
29
+ activeIndex: number
30
+ totalItems: number
31
+ goTo: (index: number) => void
32
+ goNext: () => void
33
+ goPrev: () => void
34
+ }
35
+
36
+ const CarouselContext = createContext<CarouselContextValue>({
37
+ modes: {},
38
+ activeIndex: 0,
39
+ totalItems: 0,
40
+ goTo: () => {},
41
+ goNext: () => {},
42
+ goPrev: () => {},
43
+ })
44
+
45
+ // ---------------------------------------------------------------------------
46
+ // Types
47
+ // ---------------------------------------------------------------------------
48
+
49
+ export interface CarouselProps {
50
+ /** Content items to display (should be Carousel.Item or any React nodes). */
51
+ children?: React.ReactNode
52
+ /** Modes object for design-token resolution. */
53
+ modes?: Record<string, any>
54
+ /** Enable auto-play. Default: false. */
55
+ autoPlay?: boolean
56
+ /** Auto-play interval in ms. Default: 4000. */
57
+ autoPlayInterval?: number
58
+ /** Show pagination dots. Default: true. */
59
+ showPagination?: boolean
60
+ /** Enable looping (jumps back to first after last). Default: true. */
61
+ loop?: boolean
62
+ /** Gap between items in px. Resolved from token `carousel/gap` or defaults to 12. */
63
+ gap?: number
64
+ /** Width of each carousel item. When undefined, items take full container width. */
65
+ itemWidth?: number
66
+ /** Horizontal padding around the carousel track, allowing peek of adjacent items. Defaults to 0. */
67
+ peekOffset?: number
68
+ /** Called when the active index changes. */
69
+ onIndexChange?: (index: number) => void
70
+ /** Style overrides for the outermost container. */
71
+ style?: StyleProp<ViewStyle>
72
+ }
73
+
74
+ // ---------------------------------------------------------------------------
75
+ // Carousel
76
+ // ---------------------------------------------------------------------------
77
+
78
+ export function Carousel({
79
+ children,
80
+ modes = {},
81
+ autoPlay = false,
82
+ autoPlayInterval = 4000,
83
+ showPagination = true,
84
+ loop = true,
85
+ gap: gapProp,
86
+ itemWidth: itemWidthProp,
87
+ peekOffset: peekOffsetProp,
88
+ onIndexChange,
89
+ style,
90
+ }: CarouselProps) {
91
+ // ---- Token resolution ----
92
+ const tokenGap = parseFloat(
93
+ getVariableByName('carousel/gap', modes) || '12',
94
+ )
95
+ const gap = gapProp ?? tokenGap
96
+
97
+ const tokenPeekOffset = parseFloat(
98
+ getVariableByName('carousel/peekOffset', modes) || '0',
99
+ )
100
+ const peekOffset = peekOffsetProp ?? tokenPeekOffset
101
+
102
+ const containerPaddingH = parseFloat(
103
+ getVariableByName('carousel/padding/horizontal', modes) || '0',
104
+ )
105
+ const containerPaddingV = parseFloat(
106
+ getVariableByName('carousel/padding/vertical', modes) || '0',
107
+ )
108
+ const paginationGap = parseFloat(
109
+ getVariableByName('carousel/pagination/gap', modes) || '12',
110
+ )
111
+
112
+ // ---- Refs & state ----
113
+ const scrollRef = useRef<ScrollView>(null)
114
+ const [activeIndex, setActiveIndex] = useState(0)
115
+ const [containerWidth, setContainerWidth] = useState(0)
116
+ const autoPlayTimer = useRef<ReturnType<typeof setInterval> | null>(null)
117
+ const userInteracting = useRef(false)
118
+
119
+ // Flatten children so we can count items
120
+ const items = useMemo(
121
+ () => React.Children.toArray(children).filter(React.isValidElement),
122
+ [children],
123
+ )
124
+
125
+ const totalItems = items.length
126
+
127
+ // Effective item width: provided prop, or full container width minus peek offsets
128
+ const effectiveItemWidth = useMemo(() => {
129
+ if (itemWidthProp != null) return itemWidthProp
130
+ if (containerWidth === 0) return 0
131
+ // Full-width minus peekOffset on each side
132
+ return containerWidth - peekOffset * 2 - containerPaddingH * 2
133
+ }, [itemWidthProp, containerWidth, peekOffset, containerPaddingH])
134
+
135
+ // Snap interval = item width + gap
136
+ const snapInterval = effectiveItemWidth + gap
137
+
138
+ // ---- Navigation helpers ----
139
+ const scrollToIndex = useCallback(
140
+ (index: number, animated = true) => {
141
+ if (totalItems === 0 || snapInterval === 0) return
142
+ let targetIndex = index
143
+ if (loop) {
144
+ targetIndex = ((index % totalItems) + totalItems) % totalItems
145
+ } else {
146
+ targetIndex = Math.max(0, Math.min(index, totalItems - 1))
147
+ }
148
+ scrollRef.current?.scrollTo({
149
+ x: targetIndex * snapInterval,
150
+ animated,
151
+ })
152
+ setActiveIndex(targetIndex)
153
+ onIndexChange?.(targetIndex)
154
+ },
155
+ [totalItems, snapInterval, loop, onIndexChange],
156
+ )
157
+
158
+ const goTo = useCallback(
159
+ (index: number) => scrollToIndex(index),
160
+ [scrollToIndex],
161
+ )
162
+ const goNext = useCallback(
163
+ () => scrollToIndex(activeIndex + 1),
164
+ [scrollToIndex, activeIndex],
165
+ )
166
+ const goPrev = useCallback(
167
+ () => scrollToIndex(activeIndex - 1),
168
+ [scrollToIndex, activeIndex],
169
+ )
170
+
171
+ // ---- Scroll event handler ----
172
+ const handleScroll = useCallback(
173
+ (event: NativeSyntheticEvent<NativeScrollEvent>) => {
174
+ if (snapInterval === 0) return
175
+ const offsetX = event.nativeEvent.contentOffset.x
176
+ const newIndex = Math.round(offsetX / snapInterval)
177
+ const clampedIndex = Math.max(0, Math.min(newIndex, totalItems - 1))
178
+ if (clampedIndex !== activeIndex) {
179
+ setActiveIndex(clampedIndex)
180
+ onIndexChange?.(clampedIndex)
181
+ }
182
+ },
183
+ [snapInterval, totalItems, activeIndex, onIndexChange],
184
+ )
185
+
186
+ // ---- Auto-play ----
187
+ const clearAutoPlay = useCallback(() => {
188
+ if (autoPlayTimer.current != null) {
189
+ clearInterval(autoPlayTimer.current)
190
+ autoPlayTimer.current = null
191
+ }
192
+ }, [])
193
+
194
+ const startAutoPlay = useCallback(() => {
195
+ if (!autoPlay || totalItems <= 1) return
196
+ clearAutoPlay()
197
+ autoPlayTimer.current = setInterval(() => {
198
+ if (!userInteracting.current) {
199
+ setActiveIndex((prev) => {
200
+ const next = loop
201
+ ? (prev + 1) % totalItems
202
+ : Math.min(prev + 1, totalItems - 1)
203
+ scrollRef.current?.scrollTo({
204
+ x: next * snapInterval,
205
+ animated: true,
206
+ })
207
+ onIndexChange?.(next)
208
+ return next
209
+ })
210
+ }
211
+ }, autoPlayInterval)
212
+ }, [
213
+ autoPlay,
214
+ totalItems,
215
+ loop,
216
+ snapInterval,
217
+ autoPlayInterval,
218
+ clearAutoPlay,
219
+ onIndexChange,
220
+ ])
221
+
222
+ useEffect(() => {
223
+ startAutoPlay()
224
+ return clearAutoPlay
225
+ }, [startAutoPlay, clearAutoPlay])
226
+
227
+ const handleScrollBeginDrag = useCallback(() => {
228
+ userInteracting.current = true
229
+ }, [])
230
+
231
+ const handleScrollEndDrag = useCallback(() => {
232
+ userInteracting.current = false
233
+ // Reset autoplay timer after interaction
234
+ if (autoPlay) startAutoPlay()
235
+ }, [autoPlay, startAutoPlay])
236
+
237
+ // ---- Layout ----
238
+ const handleLayout = useCallback((e: LayoutChangeEvent) => {
239
+ setContainerWidth(e.nativeEvent.layout.width)
240
+ }, [])
241
+
242
+ // ---- Context value ----
243
+ const contextValue = useMemo<CarouselContextValue>(
244
+ () => ({
245
+ modes,
246
+ activeIndex,
247
+ totalItems,
248
+ goTo,
249
+ goNext,
250
+ goPrev,
251
+ }),
252
+ [modes, activeIndex, totalItems, goTo, goNext, goPrev],
253
+ )
254
+
255
+ // ---- Render ----
256
+ const outerStyle: ViewStyle = {
257
+ paddingVertical: containerPaddingV,
258
+ }
259
+
260
+ const contentContainerStyle: ViewStyle = {
261
+ paddingHorizontal: peekOffset + containerPaddingH,
262
+ gap,
263
+ // Align items to the start so snap works correctly
264
+ alignItems: 'flex-start',
265
+ }
266
+
267
+ return (
268
+ <CarouselContext.Provider value={contextValue}>
269
+ <View style={[outerStyle, style]} onLayout={handleLayout}>
270
+ <ScrollView
271
+ ref={scrollRef}
272
+ horizontal
273
+ pagingEnabled={false}
274
+ showsHorizontalScrollIndicator={false}
275
+ decelerationRate="fast"
276
+ snapToInterval={snapInterval > 0 ? snapInterval : undefined}
277
+ snapToAlignment="start"
278
+ contentContainerStyle={contentContainerStyle}
279
+ onScroll={handleScroll}
280
+ scrollEventThrottle={16}
281
+ onScrollBeginDrag={handleScrollBeginDrag}
282
+ onScrollEndDrag={handleScrollEndDrag}
283
+
284
+ >
285
+ {items.map((child, index) => {
286
+ const itemStyle: ViewStyle = {
287
+ width: effectiveItemWidth > 0 ? effectiveItemWidth : undefined,
288
+ }
289
+
290
+ // Pass modes down to children
291
+ const childWithModes = React.isValidElement(child)
292
+ ? React.cloneElement(child as React.ReactElement<any>, {
293
+ modes: {
294
+ ...((child.props as any)?.modes || {}),
295
+ ...modes,
296
+ },
297
+ style: [itemStyle, (child.props as any)?.style],
298
+ })
299
+ : child
300
+
301
+ return (
302
+ <View key={index} style={itemStyle}>
303
+ {childWithModes}
304
+ </View>
305
+ )
306
+ })}
307
+ </ScrollView>
308
+
309
+ {showPagination && totalItems > 1 && (
310
+ <Pagination
311
+ modes={modes}
312
+ style={{ marginTop: paginationGap }}
313
+ />
314
+ )}
315
+ </View>
316
+ </CarouselContext.Provider>
317
+ )
318
+ }
319
+
320
+ // ---------------------------------------------------------------------------
321
+ // Carousel.Item
322
+ // ---------------------------------------------------------------------------
323
+
324
+ export interface CarouselItemProps {
325
+ children?: React.ReactNode
326
+ modes?: Record<string, any>
327
+ style?: StyleProp<ViewStyle>
328
+ }
329
+
330
+ /**
331
+ * Optional wrapper for carousel items. Not strictly required — any
332
+ * React node works as a direct child of `<Carousel>`.
333
+ */
334
+ export function Item({ children, modes: _modes, style }: CarouselItemProps) {
335
+ return <View style={style}>{children}</View>
336
+ }
337
+
338
+ // ---------------------------------------------------------------------------
339
+ // Carousel.Pagination
340
+ // ---------------------------------------------------------------------------
341
+
342
+ export interface PaginationProps {
343
+ modes?: Record<string, any>
344
+ style?: StyleProp<ViewStyle>
345
+ }
346
+
347
+ export function Pagination({ modes: propModes, style }: PaginationProps) {
348
+ const { modes: ctxModes, activeIndex, totalItems, goTo } =
349
+ useContext(CarouselContext)
350
+ const modes = propModes || ctxModes || {}
351
+
352
+ // Token resolution for dots
353
+ const dotSize = parseFloat(
354
+ getVariableByName('carousel/pagination/dotSize', modes) || '8',
355
+ )
356
+ const dotActiveWidth = parseFloat(
357
+ getVariableByName('carousel/pagination/dotActiveWidth', modes) || '24',
358
+ )
359
+ const dotGap = parseFloat(
360
+ getVariableByName('carousel/pagination/dotGap', modes) || '8',
361
+ )
362
+ const dotColor =
363
+ (getVariableByName('carousel/pagination/dotColor', modes) as string) ||
364
+ 'rgba(255,255,255,0.35)'
365
+ const dotActiveColor =
366
+ (getVariableByName(
367
+ 'carousel/pagination/dotActiveColor',
368
+ modes,
369
+ ) as string) || '#ffffff'
370
+ const dotRadius = parseFloat(
371
+ getVariableByName('carousel/pagination/dotRadius', modes) || '4',
372
+ )
373
+
374
+ const containerStyle: ViewStyle = {
375
+ flexDirection: 'row',
376
+ justifyContent: 'center',
377
+ alignItems: 'center',
378
+ gap: dotGap,
379
+ }
380
+
381
+ return (
382
+ <View
383
+ style={[containerStyle, style]}
384
+ accessibilityRole="tablist"
385
+ accessibilityLabel="Carousel pagination"
386
+ >
387
+ {Array.from({ length: totalItems }).map((_, i) => {
388
+ const isActive = i === activeIndex
389
+ return (
390
+ <Pressable
391
+ key={i}
392
+ onPress={() => goTo(i)}
393
+ accessibilityRole="tab"
394
+ accessibilityState={{ selected: isActive }}
395
+ accessibilityLabel={`Go to slide ${i + 1}`}
396
+ >
397
+ <AnimatedDot
398
+ isActive={isActive}
399
+ size={dotSize}
400
+ activeWidth={dotActiveWidth}
401
+ radius={dotRadius}
402
+ color={dotColor}
403
+ activeColor={dotActiveColor}
404
+ />
405
+ </Pressable>
406
+ )
407
+ })}
408
+ </View>
409
+ )
410
+ }
411
+
412
+ // ---------------------------------------------------------------------------
413
+ // AnimatedDot (internal)
414
+ // ---------------------------------------------------------------------------
415
+
416
+ interface AnimatedDotProps {
417
+ isActive: boolean
418
+ size: number
419
+ activeWidth: number
420
+ radius: number
421
+ color: string
422
+ activeColor: string
423
+ }
424
+
425
+ function AnimatedDot({
426
+ isActive,
427
+ size,
428
+ activeWidth,
429
+ radius,
430
+ color,
431
+ activeColor,
432
+ }: AnimatedDotProps) {
433
+ const animValue = useRef(new Animated.Value(isActive ? 1 : 0)).current
434
+
435
+ useEffect(() => {
436
+ Animated.timing(animValue, {
437
+ toValue: isActive ? 1 : 0,
438
+ duration: 250,
439
+ useNativeDriver: false,
440
+ }).start()
441
+ }, [isActive, animValue])
442
+
443
+ const width = animValue.interpolate({
444
+ inputRange: [0, 1],
445
+ outputRange: [size, activeWidth],
446
+ })
447
+
448
+ const backgroundColor = animValue.interpolate({
449
+ inputRange: [0, 1],
450
+ outputRange: [color, activeColor],
451
+ })
452
+
453
+ return (
454
+ <Animated.View
455
+ style={{
456
+ width,
457
+ height: size,
458
+ borderRadius: radius,
459
+ backgroundColor,
460
+ }}
461
+ />
462
+ )
463
+ }
464
+
465
+ // ---------------------------------------------------------------------------
466
+ // Attach sub-components
467
+ // ---------------------------------------------------------------------------
468
+
469
+ Carousel.Item = Item
470
+ Carousel.Pagination = Pagination
471
+
472
+ export default Carousel
@@ -8,6 +8,7 @@ import {
8
8
  } from 'react-native-gesture-handler'
9
9
  import Animated, {
10
10
  runOnJS,
11
+ useAnimatedProps,
11
12
  useAnimatedScrollHandler,
12
13
  useAnimatedStyle,
13
14
  useSharedValue,
@@ -116,6 +117,13 @@ function Drawer({
116
117
  const scrollY = useSharedValue(0)
117
118
  const scrollRef = useRef(null)
118
119
 
120
+ // Dynamically disable top bounce so a downward swipe at the top of
121
+ // the content drags the whole drawer instead of rubber-banding the
122
+ // scroll view. Bottom bounce is preserved when the user has scrolled.
123
+ const animatedScrollProps = useAnimatedProps(() => ({
124
+ bounces: scrollY.value > 1,
125
+ }))
126
+
119
127
  // We need to know if we are currently dragging the drawer or scrolling the content
120
128
  // to prevent conflict.
121
129
  const isDrawerActive = useSharedValue(false)
@@ -330,8 +338,8 @@ function Drawer({
330
338
  style={[styles.content, contentStyle]}
331
339
  contentContainerStyle={[{ paddingBottom: paddingBottom + bottomInset, gap: drawerGap, flexDirection: 'column', alignItems: 'stretch' }, contentContainerStyle]}
332
340
  showsVerticalScrollIndicator={showsVerticalScrollIndicator}
333
- bounces={true}
334
- alwaysBounceVertical={true}
341
+ animatedProps={animatedScrollProps}
342
+ alwaysBounceVertical={false}
335
343
  overScrollMode="always"
336
344
  onScroll={useAnimatedScrollHandler((event) => {
337
345
  scrollY.value = event.contentOffset.y
@@ -0,0 +1,92 @@
1
+ import { Canvas, Meta, Controls } from '@storybook/blocks';
2
+ import * as RadioButtonStories from './RadioButton.stories';
3
+ import { RadioButton } from './RadioButton';
4
+
5
+ <Meta of={RadioButtonStories} />
6
+
7
+ ## Available Collections and Modes
8
+
9
+ This component uses the following design token collections. Each collection supports multiple modes that can be configured via the `modes` prop.
10
+
11
+ ### Color Mode
12
+ - **Modes:** Light | Dark
13
+ - **Default:** Light
14
+
15
+ ### Colors Router
16
+ - **Modes:** POC | Old
17
+ - **Default:** POC
18
+
19
+ ## Usage
20
+
21
+ # RadioButton
22
+
23
+ A standard RadioButton component. This component is used to select a single option from a set of options.
24
+
25
+ ## Default
26
+
27
+ <Canvas of={RadioButtonStories.Default} />
28
+
29
+ <Controls of={RadioButtonStories.Default} />
30
+
31
+ ## States
32
+
33
+ <Canvas of={RadioButtonStories.AllStates} />
34
+
35
+
36
+ ```tsx
37
+ import React, { useState } from 'react';
38
+ import { RadioButton } from 'jfs-components';
39
+ import { View, Text } from 'react-native';
40
+
41
+ export default function App() {
42
+ const [selected, setSelected] = useState(false);
43
+
44
+ return (
45
+ <RadioButton
46
+ selected={selected}
47
+ onPress={() => setSelected(!selected)}
48
+ />
49
+ );
50
+ }
51
+ ```
52
+
53
+
54
+ ## Design Tokens
55
+
56
+ This component uses the following design tokens, resolved through `getVariableByName`:
57
+
58
+ - **`radio/background/color`**
59
+ - **`radio/disabled/background/color`**
60
+ - **`radio/disabled/border/color`**
61
+ - **`radio/disabled/radio/disabled/border/size`**
62
+ - **`radio/disabledSelected/background`**
63
+ - **`radio/disabledSelected/border/color`**
64
+ - **`radio/disabledSelected/selector/background/color`**
65
+ - **`radio/focus/background/color`**
66
+ - **`radio/focus/border/color`**
67
+ - **`radio/focus/border/size`**
68
+ - **`radio/focus/boxShadow/size`**
69
+ - **`radio/focus/shadow/color`**
70
+ - **`radio/focusSelected/background/color`**
71
+ - **`radio/focusSelected/border/size`**
72
+ - **`radio/focusSelected/selector/background/color`**
73
+ - **`radio/height`**
74
+ - **`radio/hover/background/color`**
75
+ - **`radio/hover/border/color`**
76
+ - **`radio/hover/boxShadow/size`**
77
+ - **`radio/hover/shadow/color`**
78
+ - **`radio/hoverSelected/background/color`**
79
+ - **`radio/hoverSelected/border/color`**
80
+ - **`radio/hoverSelected/boxShadow/size`**
81
+ - **`radio/hoverSelected/selector/background/color`**
82
+ - **`radio/hoverSelected/shadow/color`**
83
+ - **`radio/idle/background/color`**
84
+ - **`radio/idle/border/color`**
85
+ - **`radio/selected/background/color`**
86
+ - **`radio/selected/border/color`**
87
+ - **`radio/selected/selector/background/color`**
88
+ - **`radio/selector/size`**
89
+ - **`radio/width`**
90
+
91
+ All tokens support mode-based theming through the `modes` prop.
92
+