@beyondcorp/beyond-ui-native 0.1.2 → 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 (67) hide show
  1. package/package.json +11 -5
  2. package/src/components/accordion/accordion.tsx +245 -0
  3. package/src/components/accordion/index.ts +1 -0
  4. package/src/components/alert/alert.tsx +118 -0
  5. package/src/components/alert/index.ts +1 -0
  6. package/src/components/avatar/avatar.tsx +125 -0
  7. package/src/components/avatar/index.ts +1 -0
  8. package/src/components/badge/badge.tsx +89 -0
  9. package/src/components/badge/index.ts +1 -0
  10. package/src/components/bottom-sheet/bottom-sheet.tsx +336 -0
  11. package/src/components/bottom-sheet/index.ts +1 -0
  12. package/src/components/button/button.tsx +172 -0
  13. package/src/components/button/index.ts +1 -0
  14. package/src/components/card/card.tsx +121 -0
  15. package/src/components/card/index.ts +1 -0
  16. package/src/components/checkbox/checkbox.tsx +100 -0
  17. package/src/components/checkbox/index.ts +1 -0
  18. package/src/components/data-table/data-table.tsx +277 -0
  19. package/src/components/data-table/index.ts +1 -0
  20. package/src/components/dialog/dialog.tsx +278 -0
  21. package/src/components/dialog/index.ts +1 -0
  22. package/src/components/input/index.ts +1 -0
  23. package/src/components/input/input.tsx +130 -0
  24. package/src/components/radio/index.ts +1 -0
  25. package/src/components/radio/radio.tsx +117 -0
  26. package/src/components/select/index.ts +1 -0
  27. package/src/components/select/select.tsx +375 -0
  28. package/src/components/separator/index.ts +1 -0
  29. package/src/components/separator/separator.tsx +28 -0
  30. package/src/components/skeleton/index.ts +1 -0
  31. package/src/components/skeleton/skeleton.tsx +43 -0
  32. package/src/components/spinner/index.ts +1 -0
  33. package/src/components/spinner/spinner.tsx +46 -0
  34. package/src/components/stats-card/index.ts +1 -0
  35. package/src/components/stats-card/stats-card.tsx +92 -0
  36. package/src/components/switch/index.ts +1 -0
  37. package/src/components/switch/switch.tsx +80 -0
  38. package/src/components/tabs/index.ts +1 -0
  39. package/src/components/tabs/tabs.tsx +172 -0
  40. package/src/components/text/heading.tsx +50 -0
  41. package/src/components/text/index.ts +2 -0
  42. package/src/components/text/text.tsx +62 -0
  43. package/src/components/textarea/index.ts +1 -0
  44. package/src/components/textarea/textarea.tsx +87 -0
  45. package/src/components/toast/index.ts +2 -0
  46. package/src/components/toast/toast.tsx +136 -0
  47. package/src/components/toast/types.ts +32 -0
  48. package/src/index.ts +42 -0
  49. package/src/primitives/box.tsx +25 -0
  50. package/src/primitives/index.ts +2 -0
  51. package/src/primitives/pressable.tsx +49 -0
  52. package/src/providers/BeyondUIProvider.tsx +100 -0
  53. package/src/templates/auth/ForgotPasswordTemplate.tsx +132 -0
  54. package/src/templates/auth/SignInTemplate.tsx +213 -0
  55. package/src/templates/auth/SignUpTemplate.tsx +233 -0
  56. package/src/templates/auth/index.ts +3 -0
  57. package/src/templates/dashboard/DashboardTemplate.tsx +205 -0
  58. package/src/templates/dashboard/index.ts +1 -0
  59. package/src/templates/index.ts +3 -0
  60. package/src/templates/settings/SettingsTemplate.tsx +226 -0
  61. package/src/templates/settings/index.ts +1 -0
  62. package/src/theme/preset.ts +45 -0
  63. package/src/theme/tokens.ts +144 -0
  64. package/src/types/nativewind-env.d.ts +26 -0
  65. package/src/utilities/accessibility.ts +43 -0
  66. package/src/utilities/cn.ts +9 -0
  67. package/src/utilities/index.ts +2 -0
@@ -0,0 +1,336 @@
1
+ import * as React from "react";
2
+ import {
3
+ Modal,
4
+ View,
5
+ Pressable,
6
+ Animated,
7
+ PanResponder,
8
+ Dimensions,
9
+ type ViewProps,
10
+ type PressableProps,
11
+ } from "react-native";
12
+ import { cn } from "../../utilities/cn";
13
+ import { Text } from "../text/text";
14
+ import { Heading } from "../text/heading";
15
+
16
+ interface BottomSheetContextValue {
17
+ open: boolean;
18
+ setOpen: (open: boolean) => void;
19
+ closeSheet: () => void;
20
+ }
21
+
22
+ const BottomSheetContext = React.createContext<BottomSheetContextValue | null>(null);
23
+
24
+ function useBottomSheetContext() {
25
+ const context = React.useContext(BottomSheetContext);
26
+ if (!context) {
27
+ throw new Error("BottomSheet components must be used within a BottomSheet");
28
+ }
29
+ return context;
30
+ }
31
+
32
+ export interface BottomSheetProps {
33
+ open?: boolean;
34
+ defaultOpen?: boolean;
35
+ onOpenChange?: (open: boolean) => void;
36
+ children: React.ReactNode;
37
+ }
38
+
39
+ export const BottomSheet: React.FC<BottomSheetProps> = ({
40
+ open: controlledOpen,
41
+ defaultOpen = false,
42
+ onOpenChange,
43
+ children,
44
+ }) => {
45
+ const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);
46
+ const isControlled = controlledOpen !== undefined;
47
+ const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
48
+
49
+ const setOpen = React.useCallback(
50
+ (nextOpen: boolean) => {
51
+ if (!isControlled) {
52
+ setUncontrolledOpen(nextOpen);
53
+ }
54
+ onOpenChange?.(nextOpen);
55
+ },
56
+ [isControlled, onOpenChange]
57
+ );
58
+
59
+ const closeSheet = React.useCallback(() => {
60
+ setOpen(false);
61
+ }, [setOpen]);
62
+
63
+ return (
64
+ <BottomSheetContext.Provider value={{ open: isOpen, setOpen, closeSheet }}>
65
+ {children}
66
+ </BottomSheetContext.Provider>
67
+ );
68
+ };
69
+
70
+ // --- BottomSheetTrigger ---
71
+
72
+ export interface BottomSheetTriggerProps extends PressableProps {
73
+ asChild?: boolean;
74
+ className?: string;
75
+ children: React.ReactNode;
76
+ }
77
+
78
+ export const BottomSheetTrigger = React.forwardRef<View, BottomSheetTriggerProps>(
79
+ ({ asChild, children, onPress, ...props }, ref) => {
80
+ const { setOpen } = useBottomSheetContext();
81
+
82
+ const handlePress = (e: any) => {
83
+ setOpen(true);
84
+ onPress?.(e);
85
+ };
86
+
87
+ if (asChild && React.isValidElement(children)) {
88
+ return React.cloneElement(children as React.ReactElement<any>, {
89
+ ref,
90
+ onPress: handlePress,
91
+ });
92
+ }
93
+
94
+ return (
95
+ <Pressable ref={ref} onPress={handlePress} {...props}>
96
+ {children}
97
+ </Pressable>
98
+ );
99
+ }
100
+ );
101
+ BottomSheetTrigger.displayName = "BottomSheetTrigger";
102
+
103
+ // --- BottomSheetContent ---
104
+
105
+ export interface BottomSheetContentProps extends ViewProps {
106
+ className?: string;
107
+ children: React.ReactNode;
108
+ }
109
+
110
+ export const BottomSheetContent = React.forwardRef<View, BottomSheetContentProps>(
111
+ ({ className, children, ...props }, ref) => {
112
+ const { open, closeSheet } = useBottomSheetContext();
113
+ const screenHeight = Dimensions.get("window").height;
114
+
115
+ const translateY = React.useRef(new Animated.Value(screenHeight)).current;
116
+ const backdropOpacity = React.useRef(new Animated.Value(0)).current;
117
+
118
+ React.useEffect(() => {
119
+ if (open) {
120
+ Animated.parallel([
121
+ Animated.spring(translateY, {
122
+ toValue: 0,
123
+ useNativeDriver: true,
124
+ bounciness: 4,
125
+ }),
126
+ Animated.timing(backdropOpacity, {
127
+ toValue: 1,
128
+ duration: 250,
129
+ useNativeDriver: true,
130
+ }),
131
+ ]).start();
132
+ } else {
133
+ Animated.parallel([
134
+ Animated.timing(translateY, {
135
+ toValue: screenHeight,
136
+ duration: 200,
137
+ useNativeDriver: true,
138
+ }),
139
+ Animated.timing(backdropOpacity, {
140
+ toValue: 0,
141
+ duration: 200,
142
+ useNativeDriver: true,
143
+ }),
144
+ ]).start();
145
+ }
146
+ }, [open, translateY, backdropOpacity, screenHeight]);
147
+
148
+ // PanResponder for drag down to dismiss
149
+ const panResponder = React.useRef(
150
+ PanResponder.create({
151
+ onStartShouldSetPanResponder: () => true,
152
+ onMoveShouldSetPanResponder: (_, gestureState) => gestureState.dy > 5,
153
+ onPanResponderMove: (_, gestureState) => {
154
+ if (gestureState.dy > 0) {
155
+ translateY.setValue(gestureState.dy);
156
+ }
157
+ },
158
+ onPanResponderRelease: (_, gestureState) => {
159
+ if (gestureState.dy > 120 || gestureState.vy > 0.8) {
160
+ closeSheet();
161
+ } else {
162
+ Animated.spring(translateY, {
163
+ toValue: 0,
164
+ useNativeDriver: true,
165
+ bounciness: 4,
166
+ }).start();
167
+ }
168
+ },
169
+ })
170
+ ).current;
171
+
172
+ if (!open) return null;
173
+
174
+ return (
175
+ <Modal
176
+ transparent
177
+ visible={open}
178
+ animationType="none"
179
+ onRequestClose={closeSheet}
180
+ statusBarTranslucent
181
+ >
182
+ <View className="flex-1 justify-end">
183
+ {/* Backdrop */}
184
+ <Animated.View
185
+ style={{ opacity: backdropOpacity }}
186
+ className="absolute inset-0 bg-black/60"
187
+ >
188
+ <Pressable className="flex-1" onPress={closeSheet} />
189
+ </Animated.View>
190
+
191
+ {/* Sheet Container */}
192
+ <Animated.View
193
+ ref={ref}
194
+ style={{ transform: [{ translateY }] }}
195
+ className={cn(
196
+ "w-full bg-card rounded-t-3xl border-t border-border shadow-2xl pt-2 pb-8 px-6 max-h-[85%]",
197
+ className
198
+ )}
199
+ {...props}
200
+ >
201
+ {/* Drag Handle Bar */}
202
+ <View {...panResponder.panHandlers} className="w-full py-2 items-center">
203
+ <View className="w-12 h-1.5 rounded-full bg-muted/40" />
204
+ </View>
205
+
206
+ {children}
207
+ </Animated.View>
208
+ </View>
209
+ </Modal>
210
+ );
211
+ }
212
+ );
213
+ BottomSheetContent.displayName = "BottomSheetContent";
214
+
215
+ // --- BottomSheetHeader ---
216
+
217
+ export interface BottomSheetHeaderProps extends ViewProps {
218
+ className?: string;
219
+ children: React.ReactNode;
220
+ }
221
+
222
+ export const BottomSheetHeader = React.forwardRef<View, BottomSheetHeaderProps>(
223
+ ({ className, children, ...props }, ref) => (
224
+ <View ref={ref} className={cn("mb-4 gap-1", className)} {...props}>
225
+ {children}
226
+ </View>
227
+ )
228
+ );
229
+ BottomSheetHeader.displayName = "BottomSheetHeader";
230
+
231
+ // --- BottomSheetTitle ---
232
+
233
+ export interface BottomSheetTitleProps {
234
+ className?: string;
235
+ children: React.ReactNode;
236
+ }
237
+
238
+ export const BottomSheetTitle: React.FC<BottomSheetTitleProps> = ({
239
+ className,
240
+ children,
241
+ }) => {
242
+ return (
243
+ <Heading level={4} className={cn("text-xl font-bold text-foreground", className)}>
244
+ {children}
245
+ </Heading>
246
+ );
247
+ };
248
+ BottomSheetTitle.displayName = "BottomSheetTitle";
249
+
250
+ // --- BottomSheetDescription ---
251
+
252
+ export interface BottomSheetDescriptionProps {
253
+ className?: string;
254
+ children: React.ReactNode;
255
+ }
256
+
257
+ export const BottomSheetDescription: React.FC<BottomSheetDescriptionProps> = ({
258
+ className,
259
+ children,
260
+ }) => {
261
+ return (
262
+ <Text className={cn("text-sm text-muted", className)}>
263
+ {children}
264
+ </Text>
265
+ );
266
+ };
267
+ BottomSheetDescription.displayName = "BottomSheetDescription";
268
+
269
+ // --- BottomSheetBody ---
270
+
271
+ export interface BottomSheetBodyProps extends ViewProps {
272
+ className?: string;
273
+ children: React.ReactNode;
274
+ }
275
+
276
+ export const BottomSheetBody = React.forwardRef<View, BottomSheetBodyProps>(
277
+ ({ className, children, ...props }, ref) => (
278
+ <View ref={ref} className={cn("py-2", className)} {...props}>
279
+ {children}
280
+ </View>
281
+ )
282
+ );
283
+ BottomSheetBody.displayName = "BottomSheetBody";
284
+
285
+ // --- BottomSheetFooter ---
286
+
287
+ export interface BottomSheetFooterProps extends ViewProps {
288
+ className?: string;
289
+ children: React.ReactNode;
290
+ }
291
+
292
+ export const BottomSheetFooter = React.forwardRef<View, BottomSheetFooterProps>(
293
+ ({ className, children, ...props }, ref) => (
294
+ <View
295
+ ref={ref}
296
+ className={cn("mt-6 flex-row items-center justify-end gap-3", className)}
297
+ {...props}
298
+ >
299
+ {children}
300
+ </View>
301
+ )
302
+ );
303
+ BottomSheetFooter.displayName = "BottomSheetFooter";
304
+
305
+ // --- BottomSheetClose ---
306
+
307
+ export interface BottomSheetCloseProps extends PressableProps {
308
+ asChild?: boolean;
309
+ className?: string;
310
+ children: React.ReactNode;
311
+ }
312
+
313
+ export const BottomSheetClose = React.forwardRef<View, BottomSheetCloseProps>(
314
+ ({ asChild, children, onPress, ...props }, ref) => {
315
+ const { closeSheet } = useBottomSheetContext();
316
+
317
+ const handlePress = (e: any) => {
318
+ closeSheet();
319
+ onPress?.(e);
320
+ };
321
+
322
+ if (asChild && React.isValidElement(children)) {
323
+ return React.cloneElement(children as React.ReactElement<any>, {
324
+ ref,
325
+ onPress: handlePress,
326
+ });
327
+ }
328
+
329
+ return (
330
+ <Pressable ref={ref} onPress={handlePress} {...props}>
331
+ {children}
332
+ </Pressable>
333
+ );
334
+ }
335
+ );
336
+ BottomSheetClose.displayName = "BottomSheetClose";
@@ -0,0 +1 @@
1
+ export * from "./bottom-sheet";
@@ -0,0 +1,172 @@
1
+ import * as React from "react";
2
+ import {
3
+ ActivityIndicator,
4
+ Pressable,
5
+ Text,
6
+ View,
7
+ type PressableProps,
8
+ type TextProps,
9
+ } from "react-native";
10
+ import { cva, type VariantProps } from "class-variance-authority";
11
+ import { cn } from "../../utilities/cn";
12
+
13
+ export const buttonVariants = cva(
14
+ "flex-row items-center justify-center rounded-xl transition-colors",
15
+ {
16
+ variants: {
17
+ variant: {
18
+ primary: "bg-primary-600 active:bg-primary-700 dark:bg-primary-600 dark:active:bg-primary-700",
19
+ secondary: "bg-secondary-600 active:bg-secondary-700 dark:bg-secondary-600 dark:active:bg-secondary-700",
20
+ danger: "bg-danger-600 active:bg-danger-700 dark:bg-danger-600 dark:active:bg-danger-700",
21
+ destructive: "bg-danger-600 active:bg-danger-700 dark:bg-danger-600 dark:active:bg-danger-700",
22
+ success: "bg-success-600 active:bg-success-700 dark:bg-success-600 dark:active:bg-success-700",
23
+ warning: "bg-warning-600 active:bg-warning-700 dark:bg-warning-600 dark:active:bg-warning-700",
24
+ outline: "border border-neutral-300 dark:border-neutral-700 bg-transparent active:bg-neutral-100 dark:active:bg-neutral-800",
25
+ ghost: "bg-transparent active:bg-neutral-100 dark:active:bg-neutral-800",
26
+ link: "bg-transparent underline",
27
+ },
28
+ size: {
29
+ sm: "min-h-8 px-3 py-1.5 rounded-lg",
30
+ md: "min-h-10 px-4 py-2 rounded-xl",
31
+ lg: "min-h-12 px-6 py-2.5 rounded-xl",
32
+ xl: "min-h-14 px-8 py-3 rounded-2xl",
33
+ icon: "min-h-10 min-w-10 p-0 rounded-xl",
34
+ },
35
+ },
36
+ defaultVariants: {
37
+ variant: "primary",
38
+ size: "md",
39
+ },
40
+ }
41
+ );
42
+
43
+ export const buttonTextVariants = cva("font-semibold text-center select-none", {
44
+ variants: {
45
+ variant: {
46
+ primary: "text-white",
47
+ secondary: "text-white",
48
+ danger: "text-white",
49
+ destructive: "text-white",
50
+ success: "text-white",
51
+ warning: "text-white",
52
+ outline: "text-neutral-800 dark:text-neutral-100",
53
+ ghost: "text-neutral-800 dark:text-neutral-100",
54
+ link: "text-primary-600 dark:text-primary-400 underline",
55
+ },
56
+ size: {
57
+ sm: "text-xs",
58
+ md: "text-sm",
59
+ lg: "text-base font-semibold",
60
+ xl: "text-lg font-bold",
61
+ icon: "text-sm",
62
+ },
63
+ },
64
+ defaultVariants: {
65
+ variant: "primary",
66
+ size: "md",
67
+ },
68
+ });
69
+
70
+ type ButtonVariantProps = VariantProps<typeof buttonVariants>;
71
+
72
+ export interface ButtonProps
73
+ extends Omit<PressableProps, "children">,
74
+ ButtonVariantProps {
75
+ children?: React.ReactNode;
76
+ loading?: boolean;
77
+ disabled?: boolean;
78
+ leftIcon?: React.ReactNode;
79
+ rightIcon?: React.ReactNode;
80
+ className?: string;
81
+ textClassName?: string;
82
+ }
83
+
84
+ interface ButtonContextValue {
85
+ variant: ButtonVariantProps["variant"];
86
+ size: ButtonVariantProps["size"];
87
+ }
88
+
89
+ const ButtonContext = React.createContext<ButtonContextValue>({
90
+ variant: "primary",
91
+ size: "md",
92
+ });
93
+
94
+ export const Button = React.forwardRef<View, ButtonProps>(function Button(
95
+ {
96
+ children,
97
+ variant = "primary",
98
+ size = "md",
99
+ loading = false,
100
+ disabled = false,
101
+ leftIcon,
102
+ rightIcon,
103
+ className,
104
+ textClassName,
105
+ ...props
106
+ },
107
+ ref
108
+ ) {
109
+ const isDisabled = disabled || loading;
110
+ const isLightText = variant === "outline" || variant === "ghost" || variant === "link";
111
+ const spinnerColor = isLightText ? "#2563eb" : "#ffffff";
112
+
113
+ return (
114
+ <ButtonContext.Provider value={{ variant, size }}>
115
+ <Pressable
116
+ ref={ref}
117
+ accessibilityRole="button"
118
+ accessibilityState={{ disabled: !!isDisabled, busy: loading }}
119
+ disabled={isDisabled}
120
+ className={cn(
121
+ buttonVariants({ variant, size }),
122
+ isDisabled && "opacity-50",
123
+ className
124
+ )}
125
+ {...props}
126
+ >
127
+ {loading ? (
128
+ <ActivityIndicator color={spinnerColor} className="mr-2" size="small" />
129
+ ) : leftIcon ? (
130
+ <View className="mr-2">{leftIcon}</View>
131
+ ) : null}
132
+
133
+ {typeof children === "string" || typeof children === "number" ? (
134
+ <Text
135
+ className={cn(
136
+ buttonTextVariants({ variant, size }),
137
+ textClassName
138
+ )}
139
+ >
140
+ {children}
141
+ </Text>
142
+ ) : (
143
+ children
144
+ )}
145
+
146
+ {rightIcon && !loading ? (
147
+ <View className="ml-2">{rightIcon}</View>
148
+ ) : null}
149
+ </Pressable>
150
+ </ButtonContext.Provider>
151
+ );
152
+ });
153
+
154
+ Button.displayName = "Button";
155
+
156
+ export function ButtonText({
157
+ children,
158
+ className,
159
+ ...props
160
+ }: TextProps & { className?: string }) {
161
+ const { variant, size } = React.useContext(ButtonContext);
162
+ return (
163
+ <Text
164
+ className={cn(buttonTextVariants({ variant, size }), className)}
165
+ {...props}
166
+ >
167
+ {children}
168
+ </Text>
169
+ );
170
+ }
171
+
172
+ ButtonText.displayName = "Button.Text";
@@ -0,0 +1 @@
1
+ export * from "./button";
@@ -0,0 +1,121 @@
1
+ import * as React from "react";
2
+ import { View, Text, type ViewProps, type TextProps } from "react-native";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+ import { cn } from "../../utilities/cn";
5
+
6
+ export const cardVariants = cva(
7
+ "w-full rounded-2xl border bg-white dark:bg-neutral-900 overflow-hidden",
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default: "border-neutral-200 dark:border-neutral-800 shadow-sm",
12
+ elevated: "border-neutral-200/80 dark:border-neutral-800 shadow-md",
13
+ outlined: "border-2 border-primary-200 dark:border-primary-800",
14
+ ghost: "border-transparent bg-transparent shadow-none",
15
+ },
16
+ padding: {
17
+ none: "p-0",
18
+ sm: "p-3",
19
+ md: "p-4",
20
+ lg: "p-6",
21
+ },
22
+ },
23
+ defaultVariants: {
24
+ variant: "default",
25
+ padding: "none",
26
+ },
27
+ }
28
+ );
29
+
30
+ export interface CardProps
31
+ extends ViewProps,
32
+ VariantProps<typeof cardVariants> {
33
+ className?: string;
34
+ }
35
+
36
+ export const Card = React.forwardRef<View, CardProps>(function Card(
37
+ { className, variant, padding, ...props },
38
+ ref
39
+ ) {
40
+ return (
41
+ <View
42
+ ref={ref}
43
+ className={cn(cardVariants({ variant, padding }), className)}
44
+ {...props}
45
+ />
46
+ );
47
+ });
48
+ Card.displayName = "Card";
49
+
50
+ export const CardHeader = React.forwardRef<
51
+ View,
52
+ ViewProps & { className?: string }
53
+ >(function CardHeader({ className, ...props }, ref) {
54
+ return (
55
+ <View
56
+ ref={ref}
57
+ className={cn("flex-col space-y-1.5 p-4 pb-2", className)}
58
+ {...props}
59
+ />
60
+ );
61
+ });
62
+ CardHeader.displayName = "Card.Header";
63
+
64
+ export const CardTitle = React.forwardRef<
65
+ Text,
66
+ TextProps & { className?: string }
67
+ >(function CardTitle({ className, ...props }, ref) {
68
+ return (
69
+ <Text
70
+ ref={ref}
71
+ className={cn(
72
+ "text-lg font-bold tracking-tight text-neutral-900 dark:text-neutral-50",
73
+ className
74
+ )}
75
+ {...props}
76
+ />
77
+ );
78
+ });
79
+ CardTitle.displayName = "Card.Title";
80
+
81
+ export const CardDescription = React.forwardRef<
82
+ Text,
83
+ TextProps & { className?: string }
84
+ >(function CardDescription({ className, ...props }, ref) {
85
+ return (
86
+ <Text
87
+ ref={ref}
88
+ className={cn("text-sm text-neutral-500 dark:text-neutral-400", className)}
89
+ {...props}
90
+ />
91
+ );
92
+ });
93
+ CardDescription.displayName = "Card.Description";
94
+
95
+ export const CardContent = React.forwardRef<
96
+ View,
97
+ ViewProps & { className?: string }
98
+ >(function CardContent({ className, ...props }, ref) {
99
+ return (
100
+ <View
101
+ ref={ref}
102
+ className={cn("p-4 pt-1", className)}
103
+ {...props}
104
+ />
105
+ );
106
+ });
107
+ CardContent.displayName = "Card.Content";
108
+
109
+ export const CardFooter = React.forwardRef<
110
+ View,
111
+ ViewProps & { className?: string }
112
+ >(function CardFooter({ className, ...props }, ref) {
113
+ return (
114
+ <View
115
+ ref={ref}
116
+ className={cn("flex-row items-center p-4 pt-0", className)}
117
+ {...props}
118
+ />
119
+ );
120
+ });
121
+ CardFooter.displayName = "Card.Footer";
@@ -0,0 +1 @@
1
+ export * from "./card";