@metacells/mcellui-mcp-server 0.1.1 → 0.1.3

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 +14 -3
  2. package/package.json +5 -3
  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,271 @@
1
+ /**
2
+ * Chip
3
+ *
4
+ * Selectable filter pills for filtering content or making selections.
5
+ * Supports single and multi-select modes with optional icons.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * // Single chip
10
+ * <Chip selected={isSelected} onPress={() => setSelected(!isSelected)}>
11
+ * Electronics
12
+ * </Chip>
13
+ *
14
+ * // With icon
15
+ * <Chip icon={<TagIcon />} selected>
16
+ * Sale
17
+ * </Chip>
18
+ *
19
+ * // Chip group
20
+ * <ChipGroup>
21
+ * {categories.map(cat => (
22
+ * <Chip
23
+ * key={cat.id}
24
+ * selected={selectedIds.includes(cat.id)}
25
+ * onPress={() => toggleSelection(cat.id)}
26
+ * >
27
+ * {cat.name}
28
+ * </Chip>
29
+ * ))}
30
+ * </ChipGroup>
31
+ * ```
32
+ */
33
+
34
+ import React from 'react';
35
+ import {
36
+ View,
37
+ Text,
38
+ Pressable,
39
+ StyleSheet,
40
+ ViewStyle,
41
+ TextStyle,
42
+ } from 'react-native';
43
+ import Animated, {
44
+ useAnimatedStyle,
45
+ useSharedValue,
46
+ withSpring,
47
+ interpolateColor,
48
+ } from 'react-native-reanimated';
49
+ import { useTheme } from '@nativeui/core';
50
+
51
+ const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
52
+
53
+ // ─────────────────────────────────────────────────────────────────────────────
54
+ // Types
55
+ // ─────────────────────────────────────────────────────────────────────────────
56
+
57
+ export type ChipVariant = 'outline' | 'filled';
58
+ export type ChipSize = 'sm' | 'md' | 'lg';
59
+
60
+ export interface ChipProps {
61
+ /** Chip label */
62
+ children: string;
63
+ /** Whether chip is selected */
64
+ selected?: boolean;
65
+ /** Visual variant */
66
+ variant?: ChipVariant;
67
+ /** Size preset */
68
+ size?: ChipSize;
69
+ /** Icon element (left side) */
70
+ icon?: React.ReactNode;
71
+ /** Whether chip is disabled */
72
+ disabled?: boolean;
73
+ /** Press handler */
74
+ onPress?: () => void;
75
+ /** Container style */
76
+ style?: ViewStyle;
77
+ /** Label style */
78
+ labelStyle?: TextStyle;
79
+ }
80
+
81
+ export interface ChipGroupProps {
82
+ /** Chip elements */
83
+ children: React.ReactNode;
84
+ /** Gap between chips */
85
+ spacing?: number;
86
+ /** Container style */
87
+ style?: ViewStyle;
88
+ }
89
+
90
+ // ─────────────────────────────────────────────────────────────────────────────
91
+ // Size configs
92
+ // ─────────────────────────────────────────────────────────────────────────────
93
+
94
+ const SIZE_CONFIG = {
95
+ sm: {
96
+ paddingHorizontal: 10,
97
+ paddingVertical: 4,
98
+ fontSize: 12,
99
+ iconSize: 14,
100
+ radiusKey: 'md' as const,
101
+ },
102
+ md: {
103
+ paddingHorizontal: 14,
104
+ paddingVertical: 6,
105
+ fontSize: 14,
106
+ iconSize: 16,
107
+ radiusKey: 'lg' as const,
108
+ },
109
+ lg: {
110
+ paddingHorizontal: 18,
111
+ paddingVertical: 8,
112
+ fontSize: 16,
113
+ iconSize: 18,
114
+ radiusKey: 'xl' as const,
115
+ },
116
+ };
117
+
118
+ // ─────────────────────────────────────────────────────────────────────────────
119
+ // Chip Component
120
+ // ─────────────────────────────────────────────────────────────────────────────
121
+
122
+ export function Chip({
123
+ children,
124
+ selected = false,
125
+ variant = 'outline',
126
+ size = 'md',
127
+ icon,
128
+ disabled = false,
129
+ onPress,
130
+ style,
131
+ labelStyle,
132
+ }: ChipProps) {
133
+ const { colors, fontWeight, radius } = useTheme();
134
+ const config = SIZE_CONFIG[size];
135
+
136
+ const scale = useSharedValue(1);
137
+ const selectedAnim = useSharedValue(selected ? 1 : 0);
138
+
139
+ React.useEffect(() => {
140
+ selectedAnim.value = withSpring(selected ? 1 : 0, {
141
+ damping: 20,
142
+ stiffness: 300,
143
+ });
144
+ }, [selected, selectedAnim]);
145
+
146
+ const animatedStyle = useAnimatedStyle(() => {
147
+ const backgroundColor =
148
+ variant === 'filled'
149
+ ? interpolateColor(
150
+ selectedAnim.value,
151
+ [0, 1],
152
+ [colors.secondary, colors.primary]
153
+ )
154
+ : interpolateColor(
155
+ selectedAnim.value,
156
+ [0, 1],
157
+ ['transparent', colors.primary + '15']
158
+ );
159
+
160
+ const borderColor = interpolateColor(
161
+ selectedAnim.value,
162
+ [0, 1],
163
+ [colors.border, colors.primary]
164
+ );
165
+
166
+ return {
167
+ transform: [{ scale: scale.value }],
168
+ backgroundColor,
169
+ borderColor,
170
+ };
171
+ });
172
+
173
+ const textColor =
174
+ variant === 'filled'
175
+ ? selected
176
+ ? colors.primaryForeground
177
+ : colors.secondaryForeground
178
+ : selected
179
+ ? colors.primary
180
+ : colors.foreground;
181
+
182
+ const handlePressIn = () => {
183
+ scale.value = withSpring(0.95, { damping: 20, stiffness: 400 });
184
+ };
185
+
186
+ const handlePressOut = () => {
187
+ scale.value = withSpring(1, { damping: 20, stiffness: 400 });
188
+ };
189
+
190
+ return (
191
+ <AnimatedPressable
192
+ onPress={onPress}
193
+ onPressIn={handlePressIn}
194
+ onPressOut={handlePressOut}
195
+ disabled={disabled}
196
+ style={[
197
+ styles.chip,
198
+ {
199
+ paddingHorizontal: config.paddingHorizontal,
200
+ paddingVertical: config.paddingVertical,
201
+ borderRadius: radius[config.radiusKey],
202
+ opacity: disabled ? 0.5 : 1,
203
+ },
204
+ animatedStyle,
205
+ style,
206
+ ]}
207
+ accessibilityRole="button"
208
+ accessibilityState={{ selected, disabled }}
209
+ >
210
+ {icon && (
211
+ <View style={{ marginRight: 6 }}>
212
+ {React.isValidElement(icon)
213
+ ? React.cloneElement(icon as React.ReactElement<{ width?: number; height?: number; color?: string }>, {
214
+ width: config.iconSize,
215
+ height: config.iconSize,
216
+ color: textColor,
217
+ })
218
+ : icon}
219
+ </View>
220
+ )}
221
+ <Text
222
+ style={[
223
+ styles.label,
224
+ {
225
+ fontSize: config.fontSize,
226
+ fontWeight: fontWeight.medium,
227
+ color: textColor,
228
+ },
229
+ labelStyle,
230
+ ]}
231
+ >
232
+ {children}
233
+ </Text>
234
+ </AnimatedPressable>
235
+ );
236
+ }
237
+
238
+ // ─────────────────────────────────────────────────────────────────────────────
239
+ // ChipGroup Component
240
+ // ─────────────────────────────────────────────────────────────────────────────
241
+
242
+ export function ChipGroup({ children, spacing, style }: ChipGroupProps) {
243
+ const { spacing: themeSpacing } = useTheme();
244
+ const gap = spacing ?? themeSpacing[2];
245
+
246
+ return (
247
+ <View style={[styles.group, { gap }, style]}>
248
+ {children}
249
+ </View>
250
+ );
251
+ }
252
+
253
+ // ─────────────────────────────────────────────────────────────────────────────
254
+ // Styles
255
+ // ─────────────────────────────────────────────────────────────────────────────
256
+
257
+ const styles = StyleSheet.create({
258
+ chip: {
259
+ flexDirection: 'row',
260
+ alignItems: 'center',
261
+ justifyContent: 'center',
262
+ borderWidth: 1,
263
+ },
264
+ label: {
265
+ textAlign: 'center',
266
+ },
267
+ group: {
268
+ flexDirection: 'row',
269
+ flexWrap: 'wrap',
270
+ },
271
+ });
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Column
3
+ *
4
+ * Vertical flex container with gap, alignment, and padding props.
5
+ * Uses design tokens for consistent spacing.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * <Column gap="md" align="center">
10
+ * <Text>Top</Text>
11
+ * <Text>Bottom</Text>
12
+ * </Column>
13
+ *
14
+ * <Column gap={4} flex={1} justify="between">
15
+ * <Header />
16
+ * <Content />
17
+ * <Footer />
18
+ * </Column>
19
+ * ```
20
+ */
21
+
22
+ import React, { forwardRef } from 'react';
23
+ import { View, ViewProps, ViewStyle } from 'react-native';
24
+ import { useTheme } from '@nativeui/core';
25
+
26
+ // Semantic gap values
27
+ type GapSemantic = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
28
+
29
+ // Gap can be either semantic string or numeric spacing key
30
+ export type GapValue = GapSemantic | number;
31
+
32
+ // Semantic → Spacing Key Mapping
33
+ const semanticGapMap: Record<GapSemantic, number> = {
34
+ 'none': 0,
35
+ 'xs': 2,
36
+ 'sm': 3,
37
+ 'md': 4,
38
+ 'lg': 6,
39
+ 'xl': 8,
40
+ '2xl': 12,
41
+ };
42
+
43
+ // Alignment value mappings
44
+ const alignMap = {
45
+ 'start': 'flex-start',
46
+ 'center': 'center',
47
+ 'end': 'flex-end',
48
+ 'stretch': 'stretch',
49
+ } as const;
50
+
51
+ const justifyMap = {
52
+ 'start': 'flex-start',
53
+ 'center': 'center',
54
+ 'end': 'flex-end',
55
+ 'between': 'space-between',
56
+ 'around': 'space-around',
57
+ 'evenly': 'space-evenly',
58
+ } as const;
59
+
60
+ export interface ColumnProps extends ViewProps {
61
+ /** Gap between children (semantic or spacing key) */
62
+ gap?: GapValue;
63
+ /** Horizontal alignment of children */
64
+ align?: 'start' | 'center' | 'end' | 'stretch';
65
+ /** Vertical distribution of children */
66
+ justify?: 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly';
67
+ /** Flex value for the container */
68
+ flex?: number;
69
+ /** Padding (all sides) */
70
+ p?: GapValue;
71
+ /** Horizontal padding */
72
+ px?: GapValue;
73
+ /** Vertical padding */
74
+ py?: GapValue;
75
+ /** Additional styles */
76
+ style?: ViewStyle;
77
+ /** Children */
78
+ children?: React.ReactNode;
79
+ }
80
+
81
+ function resolveGap(
82
+ value: GapValue | undefined,
83
+ spacing: ReturnType<typeof useTheme>['spacing']
84
+ ): number | undefined {
85
+ if (value === undefined) return undefined;
86
+
87
+ if (typeof value === 'string') {
88
+ const key = semanticGapMap[value as GapSemantic];
89
+ return (spacing as Record<number, number>)[key];
90
+ }
91
+
92
+ return (spacing as Record<number, number>)[value];
93
+ }
94
+
95
+ export const Column = forwardRef<View, ColumnProps>(function Column(
96
+ {
97
+ gap,
98
+ align,
99
+ justify,
100
+ flex,
101
+ p,
102
+ px,
103
+ py,
104
+ style,
105
+ children,
106
+ ...props
107
+ },
108
+ ref
109
+ ) {
110
+ const { spacing } = useTheme();
111
+
112
+ const resolvedGap = resolveGap(gap, spacing);
113
+ const resolvedP = resolveGap(p, spacing);
114
+ const resolvedPx = resolveGap(px, spacing);
115
+ const resolvedPy = resolveGap(py, spacing);
116
+
117
+ const containerStyle: ViewStyle = {
118
+ flexDirection: 'column',
119
+ ...(resolvedGap !== undefined && { gap: resolvedGap }),
120
+ ...(align && { alignItems: alignMap[align] }),
121
+ ...(justify && { justifyContent: justifyMap[justify] }),
122
+ ...(flex !== undefined && { flex }),
123
+ ...(resolvedP !== undefined && { padding: resolvedP }),
124
+ ...(resolvedPx !== undefined && { paddingHorizontal: resolvedPx }),
125
+ ...(resolvedPy !== undefined && { paddingVertical: resolvedPy }),
126
+ };
127
+
128
+ return (
129
+ <View ref={ref} style={[containerStyle, style]} {...props}>
130
+ {children}
131
+ </View>
132
+ );
133
+ });