@metacells/mcellui-mcp-server 0.1.0 → 0.1.2
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.
- package/dist/index.js +70 -7
- package/package.json +7 -5
- package/registry/registry.json +717 -0
- package/registry/ui/accordion.tsx +416 -0
- package/registry/ui/action-sheet.tsx +396 -0
- package/registry/ui/alert-dialog.tsx +355 -0
- package/registry/ui/avatar-stack.tsx +278 -0
- package/registry/ui/avatar.tsx +116 -0
- package/registry/ui/badge.tsx +125 -0
- package/registry/ui/button.tsx +240 -0
- package/registry/ui/card.tsx +675 -0
- package/registry/ui/carousel.tsx +431 -0
- package/registry/ui/checkbox.tsx +252 -0
- package/registry/ui/chip.tsx +271 -0
- package/registry/ui/column.tsx +133 -0
- package/registry/ui/datetime-picker.tsx +578 -0
- package/registry/ui/dialog.tsx +292 -0
- package/registry/ui/fab.tsx +225 -0
- package/registry/ui/form.tsx +323 -0
- package/registry/ui/horizontal-list.tsx +200 -0
- package/registry/ui/icon-button.tsx +244 -0
- package/registry/ui/image-gallery.tsx +455 -0
- package/registry/ui/image.tsx +283 -0
- package/registry/ui/input.tsx +242 -0
- package/registry/ui/label.tsx +99 -0
- package/registry/ui/list.tsx +519 -0
- package/registry/ui/progress.tsx +168 -0
- package/registry/ui/pull-to-refresh.tsx +231 -0
- package/registry/ui/radio-group.tsx +294 -0
- package/registry/ui/rating.tsx +311 -0
- package/registry/ui/row.tsx +136 -0
- package/registry/ui/screen.tsx +153 -0
- package/registry/ui/search-input.tsx +281 -0
- package/registry/ui/section-header.tsx +258 -0
- package/registry/ui/segmented-control.tsx +229 -0
- package/registry/ui/select.tsx +311 -0
- package/registry/ui/separator.tsx +74 -0
- package/registry/ui/sheet.tsx +362 -0
- package/registry/ui/skeleton.tsx +156 -0
- package/registry/ui/slider.tsx +307 -0
- package/registry/ui/spinner.tsx +100 -0
- package/registry/ui/stepper.tsx +314 -0
- package/registry/ui/stories.tsx +463 -0
- package/registry/ui/swipeable-row.tsx +362 -0
- package/registry/ui/switch.tsx +246 -0
- package/registry/ui/tabs.tsx +348 -0
- package/registry/ui/textarea.tsx +265 -0
- package/registry/ui/toast.tsx +316 -0
- package/registry/ui/tooltip.tsx +369 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pull to Refresh
|
|
3
|
+
*
|
|
4
|
+
* A pull-to-refresh wrapper component with custom animated indicator.
|
|
5
|
+
* Works with ScrollView and FlatList.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* const [refreshing, setRefreshing] = useState(false);
|
|
10
|
+
*
|
|
11
|
+
* const onRefresh = async () => {
|
|
12
|
+
* setRefreshing(true);
|
|
13
|
+
* await fetchData();
|
|
14
|
+
* setRefreshing(false);
|
|
15
|
+
* };
|
|
16
|
+
*
|
|
17
|
+
* <PullToRefresh refreshing={refreshing} onRefresh={onRefresh}>
|
|
18
|
+
* <ScrollView>
|
|
19
|
+
* {content}
|
|
20
|
+
* </ScrollView>
|
|
21
|
+
* </PullToRefresh>
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import React, { useCallback } from 'react';
|
|
26
|
+
import {
|
|
27
|
+
View,
|
|
28
|
+
RefreshControl,
|
|
29
|
+
StyleSheet,
|
|
30
|
+
ViewStyle,
|
|
31
|
+
Platform,
|
|
32
|
+
} from 'react-native';
|
|
33
|
+
import Animated, {
|
|
34
|
+
useSharedValue,
|
|
35
|
+
useAnimatedStyle,
|
|
36
|
+
withRepeat,
|
|
37
|
+
withTiming,
|
|
38
|
+
Easing,
|
|
39
|
+
cancelAnimation,
|
|
40
|
+
} from 'react-native-reanimated';
|
|
41
|
+
import { useTheme } from '@nativeui/core';
|
|
42
|
+
|
|
43
|
+
export interface PullToRefreshProps {
|
|
44
|
+
/** Whether currently refreshing */
|
|
45
|
+
refreshing: boolean;
|
|
46
|
+
/** Callback when refresh is triggered */
|
|
47
|
+
onRefresh: () => void;
|
|
48
|
+
/** Children (ScrollView, FlatList, etc.) */
|
|
49
|
+
children: React.ReactElement;
|
|
50
|
+
/** Custom refresh indicator color */
|
|
51
|
+
indicatorColor?: string;
|
|
52
|
+
/** Custom background color for iOS */
|
|
53
|
+
backgroundColor?: string;
|
|
54
|
+
/** Progress view offset for Android */
|
|
55
|
+
progressViewOffset?: number;
|
|
56
|
+
/** Container style */
|
|
57
|
+
style?: ViewStyle;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function PullToRefresh({
|
|
61
|
+
refreshing,
|
|
62
|
+
onRefresh,
|
|
63
|
+
children,
|
|
64
|
+
indicatorColor,
|
|
65
|
+
backgroundColor,
|
|
66
|
+
progressViewOffset = 0,
|
|
67
|
+
style,
|
|
68
|
+
}: PullToRefreshProps) {
|
|
69
|
+
const { colors } = useTheme();
|
|
70
|
+
|
|
71
|
+
const tintColor = indicatorColor ?? colors.primary;
|
|
72
|
+
const bgColor = backgroundColor ?? colors.backgroundSubtle;
|
|
73
|
+
|
|
74
|
+
// Clone child with RefreshControl
|
|
75
|
+
const childWithRefreshControl = React.cloneElement(
|
|
76
|
+
children as React.ReactElement<{ refreshControl?: React.ReactElement }>,
|
|
77
|
+
{
|
|
78
|
+
refreshControl: (
|
|
79
|
+
<RefreshControl
|
|
80
|
+
refreshing={refreshing}
|
|
81
|
+
onRefresh={onRefresh}
|
|
82
|
+
tintColor={tintColor}
|
|
83
|
+
colors={[tintColor]} // Android
|
|
84
|
+
progressBackgroundColor={bgColor} // Android
|
|
85
|
+
progressViewOffset={progressViewOffset}
|
|
86
|
+
style={Platform.OS === 'ios' ? { backgroundColor: bgColor } : undefined}
|
|
87
|
+
/>
|
|
88
|
+
),
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<View style={[styles.container, style]}>
|
|
94
|
+
{childWithRefreshControl}
|
|
95
|
+
</View>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Custom Refresh Indicator
|
|
101
|
+
*
|
|
102
|
+
* A custom animated spinner for use with pull-to-refresh.
|
|
103
|
+
* Can be used standalone or with custom refresh implementations.
|
|
104
|
+
*/
|
|
105
|
+
export interface RefreshIndicatorProps {
|
|
106
|
+
/** Whether animating */
|
|
107
|
+
animating?: boolean;
|
|
108
|
+
/** Size of the indicator */
|
|
109
|
+
size?: number;
|
|
110
|
+
/** Color of the indicator */
|
|
111
|
+
color?: string;
|
|
112
|
+
/** Container style */
|
|
113
|
+
style?: ViewStyle;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function RefreshIndicator({
|
|
117
|
+
animating = true,
|
|
118
|
+
size = 24,
|
|
119
|
+
color,
|
|
120
|
+
style,
|
|
121
|
+
}: RefreshIndicatorProps) {
|
|
122
|
+
const { colors } = useTheme();
|
|
123
|
+
const rotation = useSharedValue(0);
|
|
124
|
+
|
|
125
|
+
const indicatorColor = color ?? colors.primary;
|
|
126
|
+
|
|
127
|
+
React.useEffect(() => {
|
|
128
|
+
if (animating) {
|
|
129
|
+
rotation.value = withRepeat(
|
|
130
|
+
withTiming(360, { duration: 1000, easing: Easing.linear }),
|
|
131
|
+
-1,
|
|
132
|
+
false
|
|
133
|
+
);
|
|
134
|
+
} else {
|
|
135
|
+
cancelAnimation(rotation);
|
|
136
|
+
rotation.value = 0;
|
|
137
|
+
}
|
|
138
|
+
}, [animating]);
|
|
139
|
+
|
|
140
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
141
|
+
transform: [{ rotate: `${rotation.value}deg` }],
|
|
142
|
+
}));
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<View style={[styles.indicatorContainer, { width: size, height: size }, style]}>
|
|
146
|
+
<Animated.View style={[styles.indicator, animatedStyle]}>
|
|
147
|
+
<View
|
|
148
|
+
style={[
|
|
149
|
+
styles.indicatorArc,
|
|
150
|
+
{
|
|
151
|
+
width: size,
|
|
152
|
+
height: size,
|
|
153
|
+
borderRadius: size / 2,
|
|
154
|
+
borderWidth: size / 8,
|
|
155
|
+
borderColor: indicatorColor,
|
|
156
|
+
borderTopColor: 'transparent',
|
|
157
|
+
borderRightColor: 'transparent',
|
|
158
|
+
},
|
|
159
|
+
]}
|
|
160
|
+
/>
|
|
161
|
+
</Animated.View>
|
|
162
|
+
</View>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* RefreshContainer
|
|
168
|
+
*
|
|
169
|
+
* A container component that shows a custom refresh indicator
|
|
170
|
+
* at the top when pulling down. For more control than PullToRefresh.
|
|
171
|
+
*/
|
|
172
|
+
export interface RefreshContainerProps {
|
|
173
|
+
/** Whether currently refreshing */
|
|
174
|
+
refreshing: boolean;
|
|
175
|
+
/** Callback when refresh is triggered */
|
|
176
|
+
onRefresh: () => void;
|
|
177
|
+
/** Pull threshold to trigger refresh */
|
|
178
|
+
threshold?: number;
|
|
179
|
+
/** Children */
|
|
180
|
+
children: React.ReactNode;
|
|
181
|
+
/** Container style */
|
|
182
|
+
style?: ViewStyle;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function RefreshContainer({
|
|
186
|
+
refreshing,
|
|
187
|
+
onRefresh,
|
|
188
|
+
threshold = 80,
|
|
189
|
+
children,
|
|
190
|
+
style,
|
|
191
|
+
}: RefreshContainerProps) {
|
|
192
|
+
const { colors, spacing } = useTheme();
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<View style={[styles.refreshContainer, style]}>
|
|
196
|
+
{refreshing && (
|
|
197
|
+
<View
|
|
198
|
+
style={[
|
|
199
|
+
styles.refreshHeader,
|
|
200
|
+
{
|
|
201
|
+
backgroundColor: colors.backgroundSubtle,
|
|
202
|
+
paddingVertical: spacing[4],
|
|
203
|
+
},
|
|
204
|
+
]}
|
|
205
|
+
>
|
|
206
|
+
<RefreshIndicator animating={refreshing} />
|
|
207
|
+
</View>
|
|
208
|
+
)}
|
|
209
|
+
{children}
|
|
210
|
+
</View>
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const styles = StyleSheet.create({
|
|
215
|
+
container: {
|
|
216
|
+
flex: 1,
|
|
217
|
+
},
|
|
218
|
+
indicatorContainer: {
|
|
219
|
+
alignItems: 'center',
|
|
220
|
+
justifyContent: 'center',
|
|
221
|
+
},
|
|
222
|
+
indicator: {},
|
|
223
|
+
indicatorArc: {},
|
|
224
|
+
refreshContainer: {
|
|
225
|
+
flex: 1,
|
|
226
|
+
},
|
|
227
|
+
refreshHeader: {
|
|
228
|
+
alignItems: 'center',
|
|
229
|
+
justifyContent: 'center',
|
|
230
|
+
},
|
|
231
|
+
});
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Radio Group
|
|
3
|
+
*
|
|
4
|
+
* A set of radio buttons where only one can be selected.
|
|
5
|
+
* Features animated selection indicator, haptic feedback,
|
|
6
|
+
* dark mode support, and accessibility.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* const [value, setValue] = useState('option1');
|
|
11
|
+
* <RadioGroup value={value} onValueChange={setValue}>
|
|
12
|
+
* <RadioGroupItem value="option1" label="Option 1" />
|
|
13
|
+
* <RadioGroupItem value="option2" label="Option 2" />
|
|
14
|
+
* <RadioGroupItem value="option3" label="Option 3" />
|
|
15
|
+
* </RadioGroup>
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import React, { createContext, useContext, useEffect, useCallback } from 'react';
|
|
20
|
+
import {
|
|
21
|
+
Pressable,
|
|
22
|
+
View,
|
|
23
|
+
Text,
|
|
24
|
+
StyleSheet,
|
|
25
|
+
ViewStyle,
|
|
26
|
+
AccessibilityInfo,
|
|
27
|
+
} from 'react-native';
|
|
28
|
+
import Animated, {
|
|
29
|
+
useSharedValue,
|
|
30
|
+
useAnimatedStyle,
|
|
31
|
+
withSpring,
|
|
32
|
+
interpolate,
|
|
33
|
+
interpolateColor,
|
|
34
|
+
Extrapolation,
|
|
35
|
+
} from 'react-native-reanimated';
|
|
36
|
+
import { useTheme, ThemeColors, springs as themeSpringPresets } from '@nativeui/core';
|
|
37
|
+
import { haptic } from '@nativeui/core';
|
|
38
|
+
|
|
39
|
+
// Context for sharing state between RadioGroup and RadioGroupItem
|
|
40
|
+
interface RadioGroupContextValue {
|
|
41
|
+
value: string;
|
|
42
|
+
onValueChange: (value: string) => void;
|
|
43
|
+
disabled: boolean;
|
|
44
|
+
size: 'sm' | 'md' | 'lg';
|
|
45
|
+
colors: ThemeColors;
|
|
46
|
+
springs: typeof themeSpringPresets;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const RadioGroupContext = createContext<RadioGroupContextValue | null>(null);
|
|
50
|
+
|
|
51
|
+
function useRadioGroup() {
|
|
52
|
+
const context = useContext(RadioGroupContext);
|
|
53
|
+
if (!context) {
|
|
54
|
+
throw new Error('RadioGroupItem must be used within a RadioGroup');
|
|
55
|
+
}
|
|
56
|
+
return context;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface RadioGroupProps {
|
|
60
|
+
/** Currently selected value */
|
|
61
|
+
value: string;
|
|
62
|
+
/** Callback when selection changes */
|
|
63
|
+
onValueChange: (value: string) => void;
|
|
64
|
+
/** Disable all items */
|
|
65
|
+
disabled?: boolean;
|
|
66
|
+
/** Size variant for all items */
|
|
67
|
+
size?: 'sm' | 'md' | 'lg';
|
|
68
|
+
/** Radio items */
|
|
69
|
+
children: React.ReactNode;
|
|
70
|
+
/** Additional container styles */
|
|
71
|
+
style?: ViewStyle;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function RadioGroup({
|
|
75
|
+
value,
|
|
76
|
+
onValueChange,
|
|
77
|
+
disabled = false,
|
|
78
|
+
size = 'md',
|
|
79
|
+
children,
|
|
80
|
+
style,
|
|
81
|
+
}: RadioGroupProps) {
|
|
82
|
+
const { colors, springs } = useTheme();
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<RadioGroupContext.Provider
|
|
86
|
+
value={{ value, onValueChange, disabled, size, colors, springs }}
|
|
87
|
+
>
|
|
88
|
+
<View
|
|
89
|
+
style={[styles.group, style]}
|
|
90
|
+
accessibilityRole="radiogroup"
|
|
91
|
+
>
|
|
92
|
+
{children}
|
|
93
|
+
</View>
|
|
94
|
+
</RadioGroupContext.Provider>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface RadioGroupItemProps {
|
|
99
|
+
/** Value for this radio option */
|
|
100
|
+
value: string;
|
|
101
|
+
/** Label text */
|
|
102
|
+
label: string;
|
|
103
|
+
/** Description text (optional) */
|
|
104
|
+
description?: string;
|
|
105
|
+
/** Disable this specific item */
|
|
106
|
+
disabled?: boolean;
|
|
107
|
+
/** Additional accessibility label */
|
|
108
|
+
accessibilityLabel?: string;
|
|
109
|
+
/** Additional container styles */
|
|
110
|
+
style?: ViewStyle;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function RadioGroupItem({
|
|
114
|
+
value,
|
|
115
|
+
label,
|
|
116
|
+
description,
|
|
117
|
+
disabled: itemDisabled = false,
|
|
118
|
+
accessibilityLabel,
|
|
119
|
+
style,
|
|
120
|
+
}: RadioGroupItemProps) {
|
|
121
|
+
const context = useRadioGroup();
|
|
122
|
+
const isSelected = context.value === value;
|
|
123
|
+
const disabled = context.disabled || itemDisabled;
|
|
124
|
+
const { colors, springs } = context;
|
|
125
|
+
|
|
126
|
+
const progress = useSharedValue(isSelected ? 1 : 0);
|
|
127
|
+
const [reduceMotion, setReduceMotion] = React.useState(false);
|
|
128
|
+
|
|
129
|
+
// Check for reduce motion preference
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
AccessibilityInfo.isReduceMotionEnabled().then(setReduceMotion);
|
|
132
|
+
const subscription = AccessibilityInfo.addEventListener(
|
|
133
|
+
'reduceMotionChanged',
|
|
134
|
+
setReduceMotion
|
|
135
|
+
);
|
|
136
|
+
return () => subscription.remove();
|
|
137
|
+
}, []);
|
|
138
|
+
|
|
139
|
+
// Animate on selection change
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
const target = isSelected ? 1 : 0;
|
|
142
|
+
if (reduceMotion) {
|
|
143
|
+
progress.value = target;
|
|
144
|
+
} else {
|
|
145
|
+
progress.value = withSpring(target, springs.snappy);
|
|
146
|
+
}
|
|
147
|
+
}, [isSelected, reduceMotion, springs.snappy]);
|
|
148
|
+
|
|
149
|
+
const handlePress = useCallback(() => {
|
|
150
|
+
if (disabled) return;
|
|
151
|
+
haptic('selection');
|
|
152
|
+
context.onValueChange(value);
|
|
153
|
+
}, [disabled, context.onValueChange, value]);
|
|
154
|
+
|
|
155
|
+
const sizeStyles = sizes[context.size];
|
|
156
|
+
|
|
157
|
+
const outerAnimatedStyle = useAnimatedStyle(() => ({
|
|
158
|
+
borderColor: interpolateColor(
|
|
159
|
+
progress.value,
|
|
160
|
+
[0, 1],
|
|
161
|
+
[colors.border, colors.primary]
|
|
162
|
+
),
|
|
163
|
+
}));
|
|
164
|
+
|
|
165
|
+
const innerAnimatedStyle = useAnimatedStyle(() => ({
|
|
166
|
+
opacity: progress.value,
|
|
167
|
+
transform: [
|
|
168
|
+
{
|
|
169
|
+
scale: interpolate(
|
|
170
|
+
progress.value,
|
|
171
|
+
[0, 1],
|
|
172
|
+
[0, 1],
|
|
173
|
+
Extrapolation.CLAMP
|
|
174
|
+
),
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
}));
|
|
178
|
+
|
|
179
|
+
return (
|
|
180
|
+
<Pressable
|
|
181
|
+
onPress={handlePress}
|
|
182
|
+
disabled={disabled}
|
|
183
|
+
style={({ pressed }) => [
|
|
184
|
+
styles.item,
|
|
185
|
+
pressed && !disabled && styles.pressed,
|
|
186
|
+
style,
|
|
187
|
+
]}
|
|
188
|
+
accessible
|
|
189
|
+
accessibilityRole="radio"
|
|
190
|
+
accessibilityLabel={accessibilityLabel ?? label}
|
|
191
|
+
accessibilityState={{
|
|
192
|
+
checked: isSelected,
|
|
193
|
+
disabled,
|
|
194
|
+
}}
|
|
195
|
+
>
|
|
196
|
+
<Animated.View
|
|
197
|
+
style={[
|
|
198
|
+
styles.outer,
|
|
199
|
+
sizeStyles.outer,
|
|
200
|
+
outerAnimatedStyle,
|
|
201
|
+
disabled && styles.disabled,
|
|
202
|
+
]}
|
|
203
|
+
>
|
|
204
|
+
<Animated.View
|
|
205
|
+
style={[
|
|
206
|
+
styles.inner,
|
|
207
|
+
sizeStyles.inner,
|
|
208
|
+
{ backgroundColor: colors.primary },
|
|
209
|
+
innerAnimatedStyle,
|
|
210
|
+
]}
|
|
211
|
+
/>
|
|
212
|
+
</Animated.View>
|
|
213
|
+
|
|
214
|
+
<View style={styles.textContainer}>
|
|
215
|
+
<Text
|
|
216
|
+
style={[
|
|
217
|
+
styles.label,
|
|
218
|
+
sizeStyles.label,
|
|
219
|
+
{ color: disabled ? colors.foregroundMuted : colors.foreground },
|
|
220
|
+
]}
|
|
221
|
+
>
|
|
222
|
+
{label}
|
|
223
|
+
</Text>
|
|
224
|
+
{description && (
|
|
225
|
+
<Text
|
|
226
|
+
style={[
|
|
227
|
+
styles.description,
|
|
228
|
+
sizeStyles.description,
|
|
229
|
+
{ color: disabled ? colors.foregroundMuted : colors.foregroundMuted },
|
|
230
|
+
]}
|
|
231
|
+
>
|
|
232
|
+
{description}
|
|
233
|
+
</Text>
|
|
234
|
+
)}
|
|
235
|
+
</View>
|
|
236
|
+
</Pressable>
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Size-specific styles using StyleSheet
|
|
241
|
+
const sizes = {
|
|
242
|
+
sm: StyleSheet.create({
|
|
243
|
+
outer: { width: 16, height: 16, borderRadius: 8 },
|
|
244
|
+
inner: { width: 8, height: 8, borderRadius: 4 },
|
|
245
|
+
label: { fontSize: 14 },
|
|
246
|
+
description: { fontSize: 12 },
|
|
247
|
+
}),
|
|
248
|
+
md: StyleSheet.create({
|
|
249
|
+
outer: { width: 20, height: 20, borderRadius: 10 },
|
|
250
|
+
inner: { width: 10, height: 10, borderRadius: 5 },
|
|
251
|
+
label: { fontSize: 16 },
|
|
252
|
+
description: { fontSize: 14 },
|
|
253
|
+
}),
|
|
254
|
+
lg: StyleSheet.create({
|
|
255
|
+
outer: { width: 24, height: 24, borderRadius: 12 },
|
|
256
|
+
inner: { width: 12, height: 12, borderRadius: 6 },
|
|
257
|
+
label: { fontSize: 18 },
|
|
258
|
+
description: { fontSize: 16 },
|
|
259
|
+
}),
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const styles = StyleSheet.create({
|
|
263
|
+
group: {
|
|
264
|
+
gap: 12,
|
|
265
|
+
},
|
|
266
|
+
item: {
|
|
267
|
+
flexDirection: 'row',
|
|
268
|
+
alignItems: 'flex-start',
|
|
269
|
+
gap: 10,
|
|
270
|
+
},
|
|
271
|
+
pressed: {
|
|
272
|
+
opacity: 0.7,
|
|
273
|
+
},
|
|
274
|
+
outer: {
|
|
275
|
+
borderWidth: 2,
|
|
276
|
+
alignItems: 'center',
|
|
277
|
+
justifyContent: 'center',
|
|
278
|
+
marginTop: 2,
|
|
279
|
+
},
|
|
280
|
+
inner: {},
|
|
281
|
+
disabled: {
|
|
282
|
+
opacity: 0.5,
|
|
283
|
+
},
|
|
284
|
+
textContainer: {
|
|
285
|
+
flex: 1,
|
|
286
|
+
gap: 2,
|
|
287
|
+
},
|
|
288
|
+
label: {
|
|
289
|
+
fontWeight: '500',
|
|
290
|
+
},
|
|
291
|
+
description: {
|
|
292
|
+
fontWeight: '400',
|
|
293
|
+
},
|
|
294
|
+
});
|