panelui-native 0.7.0 → 0.12.0

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 (161) hide show
  1. package/README.md +5 -3
  2. package/lib/module/components/attachment/index.js +219 -0
  3. package/lib/module/components/attachment/index.js.map +1 -0
  4. package/lib/module/components/bottom-sheet/index.js +53 -3
  5. package/lib/module/components/bottom-sheet/index.js.map +1 -1
  6. package/lib/module/components/button/index.js +19 -1
  7. package/lib/module/components/button/index.js.map +1 -1
  8. package/lib/module/components/dialog/index.js +6 -2
  9. package/lib/module/components/dialog/index.js.map +1 -1
  10. package/lib/module/components/empty-state/index.js +94 -17
  11. package/lib/module/components/empty-state/index.js.map +1 -1
  12. package/lib/module/components/frame/index.js +128 -15
  13. package/lib/module/components/frame/index.js.map +1 -1
  14. package/lib/module/components/input/index.js +107 -15
  15. package/lib/module/components/input/index.js.map +1 -1
  16. package/lib/module/components/line-chart/index.js +1024 -0
  17. package/lib/module/components/line-chart/index.js.map +1 -0
  18. package/lib/module/components/marker/index.js +190 -0
  19. package/lib/module/components/marker/index.js.map +1 -0
  20. package/lib/module/components/message/index.js +24 -8
  21. package/lib/module/components/message/index.js.map +1 -1
  22. package/lib/module/components/message-scroller/index.js +451 -0
  23. package/lib/module/components/message-scroller/index.js.map +1 -0
  24. package/lib/module/components/popover/index.js +511 -0
  25. package/lib/module/components/popover/index.js.map +1 -0
  26. package/lib/module/components/progress/index.js +52 -2
  27. package/lib/module/components/progress/index.js.map +1 -1
  28. package/lib/module/components/radio-group/index.js +132 -17
  29. package/lib/module/components/radio-group/index.js.map +1 -1
  30. package/lib/module/components/section-rail/index.js +355 -0
  31. package/lib/module/components/section-rail/index.js.map +1 -0
  32. package/lib/module/components/select/index.js +245 -56
  33. package/lib/module/components/select/index.js.map +1 -1
  34. package/lib/module/components/separator/index.js +91 -0
  35. package/lib/module/components/separator/index.js.map +1 -0
  36. package/lib/module/components/slider/index.js +355 -0
  37. package/lib/module/components/slider/index.js.map +1 -0
  38. package/lib/module/components/surface/index.js +21 -2
  39. package/lib/module/components/surface/index.js.map +1 -1
  40. package/lib/module/components/switch/index.js +10 -1
  41. package/lib/module/components/switch/index.js.map +1 -1
  42. package/lib/module/components/tabs/index.js +186 -16
  43. package/lib/module/components/tabs/index.js.map +1 -1
  44. package/lib/module/components/toggle-button/index.js +297 -0
  45. package/lib/module/components/toggle-button/index.js.map +1 -0
  46. package/lib/module/hooks/index.js +1 -0
  47. package/lib/module/hooks/index.js.map +1 -1
  48. package/lib/module/hooks/use-keyboard-avoidance.js +57 -8
  49. package/lib/module/hooks/use-keyboard-avoidance.js.map +1 -1
  50. package/lib/module/hooks/use-scroll-sections.js +89 -0
  51. package/lib/module/hooks/use-scroll-sections.js.map +1 -0
  52. package/lib/module/icons/index.js +69 -0
  53. package/lib/module/icons/index.js.map +1 -1
  54. package/lib/module/index.js +11 -2
  55. package/lib/module/index.js.map +1 -1
  56. package/lib/module/native/index.js.map +1 -1
  57. package/lib/module/primitives/keyboard-avoider.js +2 -0
  58. package/lib/module/primitives/keyboard-avoider.js.map +1 -1
  59. package/lib/module/primitives/scrim.js +72 -0
  60. package/lib/module/primitives/scrim.js.map +1 -0
  61. package/lib/module/utils/haptics.js +57 -0
  62. package/lib/module/utils/haptics.js.map +1 -0
  63. package/lib/typescript/src/components/attachment/index.d.ts +93 -0
  64. package/lib/typescript/src/components/attachment/index.d.ts.map +1 -0
  65. package/lib/typescript/src/components/bottom-sheet/index.d.ts +6 -1
  66. package/lib/typescript/src/components/bottom-sheet/index.d.ts.map +1 -1
  67. package/lib/typescript/src/components/button/index.d.ts +9 -4
  68. package/lib/typescript/src/components/button/index.d.ts.map +1 -1
  69. package/lib/typescript/src/components/dialog/index.d.ts +7 -1
  70. package/lib/typescript/src/components/dialog/index.d.ts.map +1 -1
  71. package/lib/typescript/src/components/empty-state/index.d.ts +152 -2
  72. package/lib/typescript/src/components/empty-state/index.d.ts.map +1 -1
  73. package/lib/typescript/src/components/frame/index.d.ts +47 -7
  74. package/lib/typescript/src/components/frame/index.d.ts.map +1 -1
  75. package/lib/typescript/src/components/input/index.d.ts +113 -2
  76. package/lib/typescript/src/components/input/index.d.ts.map +1 -1
  77. package/lib/typescript/src/components/line-chart/index.d.ts +247 -0
  78. package/lib/typescript/src/components/line-chart/index.d.ts.map +1 -0
  79. package/lib/typescript/src/components/marker/index.d.ts +137 -0
  80. package/lib/typescript/src/components/marker/index.d.ts.map +1 -0
  81. package/lib/typescript/src/components/message/index.d.ts +8 -1
  82. package/lib/typescript/src/components/message/index.d.ts.map +1 -1
  83. package/lib/typescript/src/components/message-scroller/index.d.ts +150 -0
  84. package/lib/typescript/src/components/message-scroller/index.d.ts.map +1 -0
  85. package/lib/typescript/src/components/popover/index.d.ts +136 -0
  86. package/lib/typescript/src/components/popover/index.d.ts.map +1 -0
  87. package/lib/typescript/src/components/progress/index.d.ts +33 -0
  88. package/lib/typescript/src/components/progress/index.d.ts.map +1 -1
  89. package/lib/typescript/src/components/radio-group/index.d.ts +39 -0
  90. package/lib/typescript/src/components/radio-group/index.d.ts.map +1 -1
  91. package/lib/typescript/src/components/section-rail/index.d.ts +115 -0
  92. package/lib/typescript/src/components/section-rail/index.d.ts.map +1 -0
  93. package/lib/typescript/src/components/select/index.d.ts +46 -7
  94. package/lib/typescript/src/components/select/index.d.ts.map +1 -1
  95. package/lib/typescript/src/components/separator/index.d.ts +47 -0
  96. package/lib/typescript/src/components/separator/index.d.ts.map +1 -0
  97. package/lib/typescript/src/components/slider/index.d.ts +203 -0
  98. package/lib/typescript/src/components/slider/index.d.ts.map +1 -0
  99. package/lib/typescript/src/components/surface/index.d.ts +51 -2
  100. package/lib/typescript/src/components/surface/index.d.ts.map +1 -1
  101. package/lib/typescript/src/components/switch/index.d.ts.map +1 -1
  102. package/lib/typescript/src/components/tabs/index.d.ts +46 -4
  103. package/lib/typescript/src/components/tabs/index.d.ts.map +1 -1
  104. package/lib/typescript/src/components/toggle-button/index.d.ts +244 -0
  105. package/lib/typescript/src/components/toggle-button/index.d.ts.map +1 -0
  106. package/lib/typescript/src/hooks/index.d.ts +1 -0
  107. package/lib/typescript/src/hooks/index.d.ts.map +1 -1
  108. package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts +10 -1
  109. package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts.map +1 -1
  110. package/lib/typescript/src/hooks/use-scroll-sections.d.ts +31 -0
  111. package/lib/typescript/src/hooks/use-scroll-sections.d.ts.map +1 -0
  112. package/lib/typescript/src/icons/index.d.ts +6 -0
  113. package/lib/typescript/src/icons/index.d.ts.map +1 -1
  114. package/lib/typescript/src/index.d.ts +13 -4
  115. package/lib/typescript/src/index.d.ts.map +1 -1
  116. package/lib/typescript/src/native/index.d.ts +16 -1
  117. package/lib/typescript/src/native/index.d.ts.map +1 -1
  118. package/lib/typescript/src/primitives/keyboard-avoider.d.ts +8 -1
  119. package/lib/typescript/src/primitives/keyboard-avoider.d.ts.map +1 -1
  120. package/lib/typescript/src/primitives/scrim.d.ts +21 -0
  121. package/lib/typescript/src/primitives/scrim.d.ts.map +1 -0
  122. package/lib/typescript/src/utils/haptics.d.ts +12 -0
  123. package/lib/typescript/src/utils/haptics.d.ts.map +1 -0
  124. package/package.json +9 -1
  125. package/src/components/attachment/index.tsx +279 -0
  126. package/src/components/bottom-sheet/index.tsx +58 -2
  127. package/src/components/button/index.tsx +26 -5
  128. package/src/components/dialog/index.tsx +10 -1
  129. package/src/components/empty-state/index.tsx +60 -14
  130. package/src/components/frame/index.tsx +175 -29
  131. package/src/components/input/index.tsx +122 -16
  132. package/src/components/line-chart/index.tsx +1224 -0
  133. package/src/components/marker/index.tsx +194 -0
  134. package/src/components/message/index.tsx +29 -5
  135. package/src/components/message-scroller/index.tsx +574 -0
  136. package/src/components/popover/index.tsx +624 -0
  137. package/src/components/progress/index.tsx +81 -1
  138. package/src/components/radio-group/index.tsx +156 -18
  139. package/src/components/section-rail/index.tsx +459 -0
  140. package/src/components/select/index.tsx +265 -52
  141. package/src/components/separator/index.tsx +97 -0
  142. package/src/components/slider/index.tsx +371 -0
  143. package/src/components/surface/index.tsx +29 -3
  144. package/src/components/switch/index.tsx +8 -1
  145. package/src/components/tabs/index.tsx +208 -28
  146. package/src/components/toggle-button/index.tsx +374 -0
  147. package/src/hooks/index.ts +5 -0
  148. package/src/hooks/use-keyboard-avoidance.ts +73 -7
  149. package/src/hooks/use-scroll-sections.ts +127 -0
  150. package/src/icons/index.tsx +48 -0
  151. package/src/index.ts +97 -6
  152. package/src/native/index.ts +13 -1
  153. package/src/primitives/keyboard-avoider.tsx +9 -1
  154. package/src/primitives/scrim.tsx +95 -0
  155. package/src/utils/haptics.ts +63 -0
  156. package/theme.css +64 -2
  157. package/lib/module/components/inline-select/index.js +0 -284
  158. package/lib/module/components/inline-select/index.js.map +0 -1
  159. package/lib/typescript/src/components/inline-select/index.d.ts +0 -48
  160. package/lib/typescript/src/components/inline-select/index.d.ts.map +0 -1
  161. package/src/components/inline-select/index.tsx +0 -332
@@ -11,6 +11,8 @@ import Animated, {
11
11
  withTiming,
12
12
  } from 'react-native-reanimated';
13
13
  import { tv, type VariantProps } from 'tailwind-variants';
14
+ import { Text } from '../../primitives/text';
15
+ import { cn } from '../../utils/cn';
14
16
 
15
17
  const SPRING = { damping: 20, stiffness: 180, mass: 0.6 } as const;
16
18
  /** Fraction of the track covered by the sliding bar in indeterminate mode. */
@@ -18,6 +20,8 @@ const INDETERMINATE_WIDTH = 0.4;
18
20
 
19
21
  const progressVariants = tv({
20
22
  slots: {
23
+ root: 'w-full gap-2',
24
+ header: 'flex-row items-center justify-between',
21
25
  track: 'w-full overflow-hidden rounded-full',
22
26
  indicator: 'h-full rounded-full',
23
27
  },
@@ -53,6 +57,30 @@ export interface ProgressProps
53
57
  indeterminate?: boolean;
54
58
  /** Extra classes for the moving indicator. */
55
59
  indicatorClassName?: string;
60
+ /**
61
+ * Caption drawn above the track, on the left. Supplying it (or
62
+ * `showValueLabel`) wraps the bar in a header row; the track alone renders
63
+ * otherwise.
64
+ */
65
+ label?: string;
66
+ /**
67
+ * Draw the percentage above the track, on the right. Hidden while
68
+ * `indeterminate` — there is nothing meaningful to show.
69
+ */
70
+ showValueLabel?: boolean;
71
+ /**
72
+ * Text for the value label. Overrides the formatted percentage — use it for
73
+ * a byte count, a step tally, anything that is not a bare percent.
74
+ */
75
+ valueLabel?: string;
76
+ /**
77
+ * Format the value label as a fraction of the whole with `Intl.NumberFormat`
78
+ * — e.g. `{ style: 'currency', currency: 'USD' }`. Falls back to a rounded
79
+ * percent when omitted.
80
+ */
81
+ formatOptions?: Intl.NumberFormatOptions;
82
+ /** Extra classes for the label + value-label row. */
83
+ headerClassName?: string;
56
84
  }
57
85
 
58
86
  function clamp(value: number) {
@@ -62,18 +90,43 @@ function clamp(value: number) {
62
90
  return value;
63
91
  }
64
92
 
93
+ /** The right-hand caption: an explicit override, an Intl fraction, or a percent. */
94
+ function formatValue(
95
+ value: number,
96
+ valueLabel?: string,
97
+ formatOptions?: Intl.NumberFormatOptions
98
+ ) {
99
+ if (valueLabel != null) return valueLabel;
100
+ if (formatOptions) {
101
+ try {
102
+ return new Intl.NumberFormat(undefined, formatOptions).format(value / 100);
103
+ } catch {
104
+ // Some engines ship a partial Intl; fall through to the plain percent.
105
+ }
106
+ }
107
+ return `${Math.round(value)}%`;
108
+ }
109
+
65
110
  /**
66
111
  * Determinate or indeterminate progress bar. The fill width (determinate) and
67
112
  * the sliding bar (indeterminate) are both driven on the UI thread, so updates
68
113
  * never re-render past the value change itself.
114
+ *
115
+ * Pass `label` or `showValueLabel` to caption the bar with a header row; the
116
+ * bare track renders when neither is set, so existing call sites are untouched.
69
117
  */
70
118
  export const Progress = forwardRef<View, ProgressProps>(
71
119
  (
72
120
  {
73
121
  className,
74
122
  indicatorClassName,
123
+ headerClassName,
75
124
  value = 0,
76
125
  indeterminate = false,
126
+ label,
127
+ showValueLabel = false,
128
+ valueLabel,
129
+ formatOptions,
77
130
  color,
78
131
  size,
79
132
  ...props
@@ -124,10 +177,15 @@ export const Progress = forwardRef<View, ProgressProps>(
124
177
  };
125
178
  });
126
179
 
127
- return (
180
+ // The value label is meaningless while looping, so it is dropped there.
181
+ const showValue = showValueLabel && !indeterminate;
182
+ const hasHeader = label != null || showValue;
183
+
184
+ const track = (
128
185
  <View
129
186
  ref={ref}
130
187
  accessibilityRole="progressbar"
188
+ accessibilityLabel={label}
131
189
  accessibilityValue={
132
190
  indeterminate ? undefined : { min: 0, max: 100, now: clamp(value) }
133
191
  }
@@ -141,6 +199,28 @@ export const Progress = forwardRef<View, ProgressProps>(
141
199
  />
142
200
  </View>
143
201
  );
202
+
203
+ if (!hasHeader) return track;
204
+
205
+ return (
206
+ <View className={slots.root()}>
207
+ <View className={slots.header({ className: headerClassName })}>
208
+ {label != null ? (
209
+ <Text size="sm" weight="medium" numberOfLines={1}>
210
+ {label}
211
+ </Text>
212
+ ) : (
213
+ <View />
214
+ )}
215
+ {showValue ? (
216
+ <Text size="sm" muted className={cn(label == null && 'ml-auto')}>
217
+ {formatValue(clamp(value), valueLabel, formatOptions)}
218
+ </Text>
219
+ ) : null}
220
+ </View>
221
+ {track}
222
+ </View>
223
+ );
144
224
  }
145
225
  );
146
226
 
@@ -1,3 +1,23 @@
1
+ /**
2
+ * RadioGroup — one choice from a set.
3
+ *
4
+ * The group owns the value and hands each item its selected state through
5
+ * context, so an item is a thin pressable that reports its own value up and
6
+ * reads selection back down.
7
+ *
8
+ * Two shapes, chosen on the group and inherited by every item: `dot` is the
9
+ * classic label-beside-a-disc row; `card` turns the whole surface into the
10
+ * target — for pickable options where the disc is a confirmation rather than
11
+ * the thing you aim at. The card is the same treatment `Checkbox` offers, so a
12
+ * form mixing single- and multi-select choices reads as one family.
13
+ *
14
+ * ```tsx
15
+ * <RadioGroup value={plan} onValueChange={setPlan} variant="card">
16
+ * <RadioGroup.Item value="pro" label="Pro" description="For growing teams" />
17
+ * <RadioGroup.Item value="max" label="Max" description="Everything, uncapped" />
18
+ * </RadioGroup>
19
+ * ```
20
+ */
1
21
  import {
2
22
  createContext,
3
23
  forwardRef,
@@ -13,13 +33,66 @@ import Animated, {
13
33
  withSpring,
14
34
  withTiming,
15
35
  } from 'react-native-reanimated';
36
+ import { tv, type VariantProps } from 'tailwind-variants';
16
37
  import { cn } from '../../utils/cn';
17
38
  import { Text } from '../../primitives/text';
18
39
 
40
+ type RadioVariant = 'dot' | 'card';
41
+ type RadioOrientation = 'vertical' | 'horizontal';
42
+
43
+ const itemVariants = tv({
44
+ slots: {
45
+ // `self-start` matters: the group is a column, so without it Yoga stretches
46
+ // the row to the full width and the dead space to the right of the label
47
+ // becomes part of the target. Tapping nothing would select the option.
48
+ row: 'flex-row items-center gap-2.5 self-start',
49
+ indicator:
50
+ 'h-5 w-5 items-center justify-center rounded-full border border-input bg-background',
51
+ label: 'text-sm text-foreground',
52
+ description: 'text-xs text-muted-foreground',
53
+ },
54
+ variants: {
55
+ variant: {
56
+ dot: {},
57
+ card: {
58
+ // The whole surface is the target; the disc moves to the trailing edge
59
+ // as a confirmation of the row, not the affordance for it. Here the
60
+ // full width is deliberate, so it takes `self-stretch` back.
61
+ row: 'w-full self-stretch items-start justify-between gap-3 rounded-xl border border-border bg-card p-4',
62
+ label: 'text-base font-medium',
63
+ },
64
+ },
65
+ selected: {
66
+ true: {},
67
+ },
68
+ disabled: {
69
+ true: { row: 'opacity-50' },
70
+ },
71
+ /**
72
+ * A card in a row shares the width rather than filling it, so two or three
73
+ * options sit side by side instead of each taking the whole line.
74
+ */
75
+ horizontal: {
76
+ true: {},
77
+ },
78
+ },
79
+ compoundVariants: [
80
+ { variant: 'card', selected: true, class: { row: 'border-primary bg-accent' } },
81
+ // Share the row instead of filling it, keeping the disc on the trailing
82
+ // edge of each narrower card.
83
+ { variant: 'card', horizontal: true, class: { row: 'w-auto flex-1' } },
84
+ ],
85
+ defaultVariants: {
86
+ variant: 'dot',
87
+ },
88
+ });
89
+
19
90
  interface RadioGroupContextValue {
20
91
  value: string | undefined;
21
92
  onValueChange: (value: string) => void;
22
93
  disabled?: boolean;
94
+ variant: RadioVariant;
95
+ orientation: RadioOrientation;
23
96
  }
24
97
 
25
98
  const RadioGroupContext = createContext<RadioGroupContextValue | null>(null);
@@ -29,14 +102,38 @@ export interface RadioGroupProps extends ViewProps {
29
102
  value?: string;
30
103
  onValueChange: (value: string) => void;
31
104
  disabled?: boolean;
105
+ /**
106
+ * `dot` is the label-beside-a-disc row. `card` makes the whole surface the
107
+ * target and highlights the selected option — for a plan picker or a
108
+ * settings choice where each option carries a description.
109
+ */
110
+ variant?: RadioVariant;
111
+ /**
112
+ * `horizontal` lays the options out along a row that wraps — for two or
113
+ * three short choices, where a stacked list wastes the width and reads as
114
+ * longer than it is.
115
+ */
116
+ orientation?: RadioOrientation;
32
117
  children: ReactNode;
33
118
  }
34
119
 
35
120
  const RadioGroupRoot = forwardRef<View, RadioGroupProps>(
36
- ({ className, value, onValueChange, disabled, children, ...props }, ref) => {
121
+ (
122
+ {
123
+ className,
124
+ value,
125
+ onValueChange,
126
+ disabled,
127
+ variant = 'dot',
128
+ orientation = 'vertical',
129
+ children,
130
+ ...props
131
+ },
132
+ ref
133
+ ) => {
37
134
  const context = useMemo(
38
- () => ({ value, onValueChange, disabled }),
39
- [value, onValueChange, disabled]
135
+ () => ({ value, onValueChange, disabled, variant, orientation }),
136
+ [value, onValueChange, disabled, variant, orientation]
40
137
  );
41
138
 
42
139
  return (
@@ -44,7 +141,15 @@ const RadioGroupRoot = forwardRef<View, RadioGroupProps>(
44
141
  <View
45
142
  ref={ref}
46
143
  accessibilityRole="radiogroup"
47
- className={cn('gap-3', className)}
144
+ className={cn(
145
+ orientation === 'horizontal'
146
+ ? // Wrapping, not scrolling: a choice that runs off the edge is
147
+ // a choice nobody knows is there. The cross-axis gap is
148
+ // smaller because wrapped rows already read as separate.
149
+ 'flex-row flex-wrap items-stretch gap-x-5 gap-y-3'
150
+ : 'gap-3',
151
+ className
152
+ )}
48
153
  {...props}
49
154
  >
50
155
  {children}
@@ -59,12 +164,19 @@ export interface RadioGroupItemProps {
59
164
  className?: string;
60
165
  value: string;
61
166
  label?: string;
167
+ /** Secondary line under the label. Most at home in the `card` variant. */
168
+ description?: string;
62
169
  disabled?: boolean;
170
+ /** Hide the disc entirely — for a card whose selected fill is enough. */
171
+ hideIndicator?: boolean;
63
172
  children?: ReactNode;
64
173
  }
65
174
 
66
175
  const RadioGroupItem = forwardRef<View, RadioGroupItemProps>(
67
- ({ className, value, label, disabled: itemDisabled, children }, ref) => {
176
+ (
177
+ { className, value, label, description, disabled: itemDisabled, hideIndicator, children },
178
+ ref
179
+ ) => {
68
180
  const context = useContext(RadioGroupContext);
69
181
  if (!context) {
70
182
  throw new Error('RadioGroup.Item must be used within a <RadioGroup>');
@@ -72,6 +184,7 @@ const RadioGroupItem = forwardRef<View, RadioGroupItemProps>(
72
184
 
73
185
  const selected = context.value === value;
74
186
  const disabled = itemDisabled || context.disabled;
187
+ const variant = context.variant;
75
188
  const progress = useSharedValue(selected ? 1 : 0);
76
189
 
77
190
  useEffect(() => {
@@ -85,6 +198,39 @@ const RadioGroupItem = forwardRef<View, RadioGroupItemProps>(
85
198
  transform: [{ scale: progress.value }],
86
199
  }));
87
200
 
201
+ const slots = itemVariants({
202
+ variant,
203
+ selected,
204
+ disabled: !!disabled,
205
+ horizontal: context.orientation === 'horizontal',
206
+ });
207
+
208
+ const indicator = hideIndicator ? null : (
209
+ <View className={slots.indicator()}>
210
+ <Animated.View style={dotStyle} className="h-2.5 w-2.5 rounded-full bg-primary" />
211
+ </View>
212
+ );
213
+
214
+ // The card lays its text out first so the disc sits at the trailing edge;
215
+ // the dot row keeps the classic disc-then-label order.
216
+ const body =
217
+ variant === 'card' ? (
218
+ <>
219
+ <View className="flex-1 gap-1">
220
+ {label ? <Text className={slots.label()}>{label}</Text> : children}
221
+ {description ? (
222
+ <Text className={slots.description()}>{description}</Text>
223
+ ) : null}
224
+ </View>
225
+ {indicator}
226
+ </>
227
+ ) : (
228
+ <>
229
+ {indicator}
230
+ {label ? <Text className={slots.label()}>{label}</Text> : children}
231
+ </>
232
+ );
233
+
88
234
  return (
89
235
  <Pressable
90
236
  ref={ref}
@@ -93,20 +239,10 @@ const RadioGroupItem = forwardRef<View, RadioGroupItemProps>(
93
239
  accessibilityLabel={label}
94
240
  disabled={disabled}
95
241
  onPress={() => context.onValueChange(value)}
96
- hitSlop={8}
97
- className={cn(
98
- 'flex-row items-center gap-2.5',
99
- disabled && 'opacity-50',
100
- className
101
- )}
242
+ hitSlop={variant === 'card' ? undefined : 8}
243
+ className={slots.row({ className })}
102
244
  >
103
- <View className="h-5 w-5 items-center justify-center rounded-full border border-input bg-background">
104
- <Animated.View
105
- style={dotStyle}
106
- className="h-2.5 w-2.5 rounded-full bg-primary"
107
- />
108
- </View>
109
- {label ? <Text className="text-sm text-foreground">{label}</Text> : children}
245
+ {body}
110
246
  </Pressable>
111
247
  );
112
248
  }
@@ -116,3 +252,5 @@ RadioGroupItem.displayName = 'RadioGroup.Item';
116
252
  export const RadioGroup = Object.assign(RadioGroupRoot, {
117
253
  Item: RadioGroupItem,
118
254
  });
255
+
256
+ export type { RadioVariant };