@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.
Files changed (49) hide show
  1. package/dist/index.js +70 -7
  2. package/package.json +7 -5
  3. package/registry/registry.json +717 -0
  4. package/registry/ui/accordion.tsx +416 -0
  5. package/registry/ui/action-sheet.tsx +396 -0
  6. package/registry/ui/alert-dialog.tsx +355 -0
  7. package/registry/ui/avatar-stack.tsx +278 -0
  8. package/registry/ui/avatar.tsx +116 -0
  9. package/registry/ui/badge.tsx +125 -0
  10. package/registry/ui/button.tsx +240 -0
  11. package/registry/ui/card.tsx +675 -0
  12. package/registry/ui/carousel.tsx +431 -0
  13. package/registry/ui/checkbox.tsx +252 -0
  14. package/registry/ui/chip.tsx +271 -0
  15. package/registry/ui/column.tsx +133 -0
  16. package/registry/ui/datetime-picker.tsx +578 -0
  17. package/registry/ui/dialog.tsx +292 -0
  18. package/registry/ui/fab.tsx +225 -0
  19. package/registry/ui/form.tsx +323 -0
  20. package/registry/ui/horizontal-list.tsx +200 -0
  21. package/registry/ui/icon-button.tsx +244 -0
  22. package/registry/ui/image-gallery.tsx +455 -0
  23. package/registry/ui/image.tsx +283 -0
  24. package/registry/ui/input.tsx +242 -0
  25. package/registry/ui/label.tsx +99 -0
  26. package/registry/ui/list.tsx +519 -0
  27. package/registry/ui/progress.tsx +168 -0
  28. package/registry/ui/pull-to-refresh.tsx +231 -0
  29. package/registry/ui/radio-group.tsx +294 -0
  30. package/registry/ui/rating.tsx +311 -0
  31. package/registry/ui/row.tsx +136 -0
  32. package/registry/ui/screen.tsx +153 -0
  33. package/registry/ui/search-input.tsx +281 -0
  34. package/registry/ui/section-header.tsx +258 -0
  35. package/registry/ui/segmented-control.tsx +229 -0
  36. package/registry/ui/select.tsx +311 -0
  37. package/registry/ui/separator.tsx +74 -0
  38. package/registry/ui/sheet.tsx +362 -0
  39. package/registry/ui/skeleton.tsx +156 -0
  40. package/registry/ui/slider.tsx +307 -0
  41. package/registry/ui/spinner.tsx +100 -0
  42. package/registry/ui/stepper.tsx +314 -0
  43. package/registry/ui/stories.tsx +463 -0
  44. package/registry/ui/swipeable-row.tsx +362 -0
  45. package/registry/ui/switch.tsx +246 -0
  46. package/registry/ui/tabs.tsx +348 -0
  47. package/registry/ui/textarea.tsx +265 -0
  48. package/registry/ui/toast.tsx +316 -0
  49. package/registry/ui/tooltip.tsx +369 -0
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Avatar
3
+ *
4
+ * User profile picture with fallback initials.
5
+ * Uses design tokens for consistent styling.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * <Avatar source={{ uri: 'https://example.com/avatar.jpg' }} fallback="JD" />
10
+ * <Avatar fallback="AB" size="lg" />
11
+ * <Avatar fallback="XY" size="xs" />
12
+ * ```
13
+ */
14
+
15
+ import React, { useState } from 'react';
16
+ import {
17
+ View,
18
+ Text,
19
+ Image,
20
+ ImageSourcePropType,
21
+ StyleSheet,
22
+ ViewStyle,
23
+ } from 'react-native';
24
+ import { useTheme } from '@nativeui/core';
25
+
26
+ export type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
27
+
28
+ export interface AvatarProps {
29
+ /** Image source */
30
+ source?: ImageSourcePropType;
31
+ /** Fallback text (usually initials) */
32
+ fallback?: string;
33
+ /** Size preset */
34
+ size?: AvatarSize;
35
+ /** Additional container styles */
36
+ style?: ViewStyle;
37
+ }
38
+
39
+ export function Avatar({
40
+ source,
41
+ fallback = '?',
42
+ size = 'md',
43
+ style,
44
+ }: AvatarProps) {
45
+ const { colors, components, platformShadow } = useTheme();
46
+ const tokens = components.avatar[size];
47
+ const [imageError, setImageError] = useState(false);
48
+ const showFallback = !source || imageError;
49
+
50
+ return (
51
+ <View
52
+ style={[
53
+ styles.container,
54
+ {
55
+ width: tokens.size,
56
+ height: tokens.size,
57
+ borderRadius: tokens.borderRadius,
58
+ backgroundColor: colors.backgroundMuted,
59
+ },
60
+ platformShadow('sm'),
61
+ style,
62
+ ]}
63
+ accessibilityRole="image"
64
+ accessibilityLabel={fallback ? `Avatar: ${fallback}` : 'Avatar'}
65
+ >
66
+ {showFallback ? (
67
+ <View
68
+ style={[
69
+ styles.fallback,
70
+ {
71
+ borderRadius: tokens.borderRadius,
72
+ backgroundColor: colors.primary,
73
+ },
74
+ ]}
75
+ >
76
+ <Text
77
+ style={[
78
+ styles.fallbackText,
79
+ {
80
+ fontSize: tokens.fontSize,
81
+ fontWeight: tokens.fontWeight,
82
+ color: colors.primaryForeground,
83
+ },
84
+ ]}
85
+ >
86
+ {fallback.slice(0, 2).toUpperCase()}
87
+ </Text>
88
+ </View>
89
+ ) : (
90
+ <Image
91
+ source={source}
92
+ style={[styles.image, { borderRadius: tokens.borderRadius }]}
93
+ onError={() => setImageError(true)}
94
+ />
95
+ )}
96
+ </View>
97
+ );
98
+ }
99
+
100
+ const styles = StyleSheet.create({
101
+ container: {
102
+ overflow: 'hidden',
103
+ },
104
+ image: {
105
+ width: '100%',
106
+ height: '100%',
107
+ },
108
+ fallback: {
109
+ flex: 1,
110
+ alignItems: 'center',
111
+ justifyContent: 'center',
112
+ },
113
+ fallbackText: {
114
+ // Dynamic styles applied inline
115
+ },
116
+ });
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Badge
3
+ *
4
+ * Small status indicator for labels and counts.
5
+ * Uses design tokens for consistent styling.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * <Badge>New</Badge>
10
+ * <Badge variant="secondary">12</Badge>
11
+ * <Badge variant="destructive" size="lg">Error</Badge>
12
+ * <Badge variant="outline">Draft</Badge>
13
+ * ```
14
+ */
15
+
16
+ import React from 'react';
17
+ import { View, Text, StyleSheet, ViewStyle, TextStyle } from 'react-native';
18
+ import { useTheme, ThemeColors } from '@nativeui/core';
19
+
20
+ export type BadgeVariant = 'default' | 'secondary' | 'destructive' | 'outline';
21
+ export type BadgeSize = 'sm' | 'md' | 'lg';
22
+
23
+ export interface BadgeProps {
24
+ /** Badge content */
25
+ children: React.ReactNode;
26
+ /** Visual style variant */
27
+ variant?: BadgeVariant;
28
+ /** Size variant */
29
+ size?: BadgeSize;
30
+ /** Additional container styles */
31
+ style?: ViewStyle;
32
+ /** Additional text styles */
33
+ textStyle?: TextStyle;
34
+ }
35
+
36
+ export function Badge({
37
+ children,
38
+ variant = 'default',
39
+ size = 'md',
40
+ style,
41
+ textStyle,
42
+ }: BadgeProps) {
43
+ const { colors, components, platformShadow } = useTheme();
44
+ const tokens = components.badge[size];
45
+ const variantStyles = getVariantStyles(variant, colors);
46
+
47
+ // Add subtle shadow for solid badges
48
+ const shadowStyle = variant !== 'outline' ? platformShadow('sm') : {};
49
+
50
+ return (
51
+ <View
52
+ style={[
53
+ styles.base,
54
+ {
55
+ paddingHorizontal: tokens.paddingHorizontal,
56
+ paddingVertical: tokens.paddingVertical,
57
+ borderRadius: tokens.borderRadius,
58
+ },
59
+ variantStyles.container,
60
+ shadowStyle,
61
+ style,
62
+ ]}
63
+ >
64
+ <Text
65
+ style={[
66
+ styles.text,
67
+ {
68
+ fontSize: tokens.fontSize,
69
+ fontWeight: tokens.fontWeight,
70
+ },
71
+ variantStyles.text,
72
+ textStyle,
73
+ ]}
74
+ >
75
+ {children}
76
+ </Text>
77
+ </View>
78
+ );
79
+ }
80
+
81
+ function getVariantStyles(
82
+ variant: BadgeVariant,
83
+ colors: ThemeColors
84
+ ) {
85
+ switch (variant) {
86
+ case 'default':
87
+ return {
88
+ container: { backgroundColor: colors.primary } as ViewStyle,
89
+ text: { color: colors.primaryForeground } as TextStyle,
90
+ };
91
+ case 'secondary':
92
+ return {
93
+ container: { backgroundColor: colors.secondary } as ViewStyle,
94
+ text: { color: colors.secondaryForeground } as TextStyle,
95
+ };
96
+ case 'destructive':
97
+ return {
98
+ container: { backgroundColor: colors.destructive } as ViewStyle,
99
+ text: { color: colors.destructiveForeground } as TextStyle,
100
+ };
101
+ case 'outline':
102
+ return {
103
+ container: {
104
+ backgroundColor: 'transparent',
105
+ borderWidth: 1,
106
+ borderColor: colors.border,
107
+ } as ViewStyle,
108
+ text: { color: colors.foreground } as TextStyle,
109
+ };
110
+ default:
111
+ return {
112
+ container: { backgroundColor: colors.primary } as ViewStyle,
113
+ text: { color: colors.primaryForeground } as TextStyle,
114
+ };
115
+ }
116
+ }
117
+
118
+ const styles = StyleSheet.create({
119
+ base: {
120
+ alignSelf: 'flex-start',
121
+ },
122
+ text: {
123
+ textAlign: 'center',
124
+ },
125
+ });
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Button
3
+ *
4
+ * A pressable button component with multiple variants and sizes.
5
+ * Uses design tokens for consistent styling across the app.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * <Button onPress={() => {}}>Click me</Button>
10
+ * <Button variant="secondary" size="sm">Small</Button>
11
+ * <Button variant="destructive" disabled>Disabled</Button>
12
+ * <Button variant="outline" icon={<Icon name="plus" />}>With Icon</Button>
13
+ * ```
14
+ */
15
+
16
+ import React, { useCallback, forwardRef } from 'react';
17
+ import {
18
+ Text,
19
+ View,
20
+ StyleSheet,
21
+ ViewStyle,
22
+ TextStyle,
23
+ ActivityIndicator,
24
+ PressableProps,
25
+ Pressable,
26
+ } from 'react-native';
27
+ import Animated, {
28
+ useSharedValue,
29
+ useAnimatedStyle,
30
+ withSpring,
31
+ } from 'react-native-reanimated';
32
+ import { useTheme, BUTTON_CONSTANTS } from '@nativeui/core';
33
+ import { haptic } from '@nativeui/core';
34
+
35
+ const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
36
+
37
+ export type ButtonVariant = 'default' | 'secondary' | 'outline' | 'ghost' | 'destructive';
38
+ export type ButtonSize = 'sm' | 'md' | 'lg';
39
+
40
+ export interface ButtonProps extends Omit<PressableProps, 'style'> {
41
+ /** Button content */
42
+ children: React.ReactNode;
43
+ /** Visual style variant */
44
+ variant?: ButtonVariant;
45
+ /** Size preset */
46
+ size?: ButtonSize;
47
+ /** Show loading spinner */
48
+ loading?: boolean;
49
+ /** Icon element (left side) */
50
+ icon?: React.ReactNode;
51
+ /** Icon element (right side) */
52
+ iconRight?: React.ReactNode;
53
+ /** Full width button */
54
+ fullWidth?: boolean;
55
+ /** Additional container styles */
56
+ style?: ViewStyle;
57
+ /** Additional text styles */
58
+ textStyle?: TextStyle;
59
+ }
60
+
61
+ export const Button = forwardRef(function Button(
62
+ {
63
+ children,
64
+ variant = 'default',
65
+ size = 'md',
66
+ loading = false,
67
+ icon,
68
+ iconRight,
69
+ fullWidth = false,
70
+ disabled,
71
+ style,
72
+ textStyle,
73
+ onPressIn,
74
+ onPressOut,
75
+ onPress,
76
+ ...props
77
+ }: ButtonProps,
78
+ ref: React.ForwardedRef<View>
79
+ ) {
80
+ const { colors, components, platformShadow, springs } = useTheme();
81
+ const tokens = components.button[size];
82
+ const isDisabled = disabled || loading;
83
+ const scale = useSharedValue(1);
84
+
85
+ const handlePressIn = useCallback(
86
+ (e: any) => {
87
+ scale.value = withSpring(BUTTON_CONSTANTS.pressScale, springs.snappy);
88
+ onPressIn?.(e);
89
+ },
90
+ [onPressIn, springs.snappy]
91
+ );
92
+
93
+ const handlePressOut = useCallback(
94
+ (e: any) => {
95
+ scale.value = withSpring(1, springs.snappy);
96
+ onPressOut?.(e);
97
+ },
98
+ [onPressOut, springs.snappy]
99
+ );
100
+
101
+ const handlePress = useCallback(
102
+ (e: any) => {
103
+ haptic('light');
104
+ onPress?.(e);
105
+ },
106
+ [onPress]
107
+ );
108
+
109
+ const animatedStyle = useAnimatedStyle(() => ({
110
+ transform: [{ scale: scale.value }],
111
+ }));
112
+
113
+ // Get variant-specific styles
114
+ const variantStyles = getVariantStyles(variant, colors);
115
+
116
+ // Add shadow for solid buttons
117
+ const shadowStyle =
118
+ variant !== 'ghost' && variant !== 'outline' && !isDisabled
119
+ ? platformShadow('sm')
120
+ : {};
121
+
122
+ return (
123
+ <AnimatedPressable
124
+ ref={ref}
125
+ style={[
126
+ styles.base,
127
+ {
128
+ minHeight: tokens.height,
129
+ paddingHorizontal: tokens.paddingHorizontal,
130
+ paddingVertical: tokens.paddingVertical,
131
+ borderRadius: tokens.borderRadius,
132
+ gap: tokens.gap,
133
+ },
134
+ variantStyles.container,
135
+ shadowStyle,
136
+ isDisabled && styles.disabled,
137
+ fullWidth && styles.fullWidth,
138
+ animatedStyle,
139
+ style,
140
+ ]}
141
+ disabled={isDisabled}
142
+ onPressIn={handlePressIn}
143
+ onPressOut={handlePressOut}
144
+ onPress={handlePress}
145
+ accessibilityRole="button"
146
+ accessibilityState={{ disabled: isDisabled }}
147
+ {...props}
148
+ >
149
+ {loading ? (
150
+ <ActivityIndicator size="small" color={variantStyles.spinnerColor} />
151
+ ) : (
152
+ <>
153
+ {icon && <View style={styles.icon}>{icon}</View>}
154
+ <Text
155
+ style={[
156
+ styles.text,
157
+ {
158
+ fontSize: tokens.fontSize,
159
+ fontWeight: tokens.fontWeight,
160
+ },
161
+ variantStyles.text,
162
+ textStyle,
163
+ ]}
164
+ >
165
+ {children}
166
+ </Text>
167
+ {iconRight && <View style={styles.icon}>{iconRight}</View>}
168
+ </>
169
+ )}
170
+ </AnimatedPressable>
171
+ );
172
+ });
173
+
174
+ function getVariantStyles(
175
+ variant: ButtonVariant,
176
+ colors: ReturnType<typeof useTheme>['colors']
177
+ ) {
178
+ switch (variant) {
179
+ case 'default':
180
+ return {
181
+ container: { backgroundColor: colors.primary } as ViewStyle,
182
+ text: { color: colors.primaryForeground } as TextStyle,
183
+ spinnerColor: colors.primaryForeground,
184
+ };
185
+ case 'secondary':
186
+ return {
187
+ container: { backgroundColor: colors.secondary } as ViewStyle,
188
+ text: { color: colors.secondaryForeground } as TextStyle,
189
+ spinnerColor: colors.secondaryForeground,
190
+ };
191
+ case 'outline':
192
+ return {
193
+ container: {
194
+ backgroundColor: 'transparent',
195
+ borderWidth: 1,
196
+ borderColor: colors.border,
197
+ } as ViewStyle,
198
+ text: { color: colors.foreground } as TextStyle,
199
+ spinnerColor: colors.foreground,
200
+ };
201
+ case 'ghost':
202
+ return {
203
+ container: { backgroundColor: 'transparent' } as ViewStyle,
204
+ text: { color: colors.foreground } as TextStyle,
205
+ spinnerColor: colors.foreground,
206
+ };
207
+ case 'destructive':
208
+ return {
209
+ container: { backgroundColor: colors.destructive } as ViewStyle,
210
+ text: { color: colors.destructiveForeground } as TextStyle,
211
+ spinnerColor: colors.destructiveForeground,
212
+ };
213
+ default:
214
+ return {
215
+ container: { backgroundColor: colors.primary } as ViewStyle,
216
+ text: { color: colors.primaryForeground } as TextStyle,
217
+ spinnerColor: colors.primaryForeground,
218
+ };
219
+ }
220
+ }
221
+
222
+ const styles = StyleSheet.create({
223
+ base: {
224
+ flexDirection: 'row',
225
+ alignItems: 'center',
226
+ justifyContent: 'center',
227
+ },
228
+ disabled: {
229
+ opacity: BUTTON_CONSTANTS.disabledOpacity,
230
+ },
231
+ fullWidth: {
232
+ width: '100%',
233
+ },
234
+ text: {
235
+ textAlign: 'center',
236
+ },
237
+ icon: {
238
+ flexShrink: 0,
239
+ },
240
+ });