@beyondcorp/beyond-ui-native 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 (83) hide show
  1. package/dist/{chunk-2B6HTSGM.mjs → chunk-RNHEGFYR.mjs} +16 -2
  2. package/dist/chunk-RNHEGFYR.mjs.map +1 -0
  3. package/dist/index.d.mts +2 -145
  4. package/dist/index.d.ts +2 -145
  5. package/dist/index.js +37 -8
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +23 -8
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/preset-BmUHLoAa.d.mts +274 -0
  10. package/dist/preset-BmUHLoAa.d.ts +274 -0
  11. package/dist/preset.d.mts +1 -117
  12. package/dist/preset.d.ts +1 -117
  13. package/dist/preset.js +19 -3
  14. package/dist/preset.js.map +1 -1
  15. package/dist/preset.mjs +5 -3
  16. package/package.json +11 -5
  17. package/src/components/accordion/accordion.tsx +245 -0
  18. package/src/components/accordion/index.ts +1 -0
  19. package/src/components/alert/alert.tsx +118 -0
  20. package/src/components/alert/index.ts +1 -0
  21. package/src/components/avatar/avatar.tsx +125 -0
  22. package/src/components/avatar/index.ts +1 -0
  23. package/src/components/badge/badge.tsx +89 -0
  24. package/src/components/badge/index.ts +1 -0
  25. package/src/components/bottom-sheet/bottom-sheet.tsx +336 -0
  26. package/src/components/bottom-sheet/index.ts +1 -0
  27. package/src/components/button/button.tsx +172 -0
  28. package/src/components/button/index.ts +1 -0
  29. package/src/components/card/card.tsx +121 -0
  30. package/src/components/card/index.ts +1 -0
  31. package/src/components/checkbox/checkbox.tsx +100 -0
  32. package/src/components/checkbox/index.ts +1 -0
  33. package/src/components/data-table/data-table.tsx +277 -0
  34. package/src/components/data-table/index.ts +1 -0
  35. package/src/components/dialog/dialog.tsx +278 -0
  36. package/src/components/dialog/index.ts +1 -0
  37. package/src/components/input/index.ts +1 -0
  38. package/src/components/input/input.tsx +130 -0
  39. package/src/components/radio/index.ts +1 -0
  40. package/src/components/radio/radio.tsx +117 -0
  41. package/src/components/select/index.ts +1 -0
  42. package/src/components/select/select.tsx +375 -0
  43. package/src/components/separator/index.ts +1 -0
  44. package/src/components/separator/separator.tsx +28 -0
  45. package/src/components/skeleton/index.ts +1 -0
  46. package/src/components/skeleton/skeleton.tsx +43 -0
  47. package/src/components/spinner/index.ts +1 -0
  48. package/src/components/spinner/spinner.tsx +46 -0
  49. package/src/components/stats-card/index.ts +1 -0
  50. package/src/components/stats-card/stats-card.tsx +92 -0
  51. package/src/components/switch/index.ts +1 -0
  52. package/src/components/switch/switch.tsx +80 -0
  53. package/src/components/tabs/index.ts +1 -0
  54. package/src/components/tabs/tabs.tsx +172 -0
  55. package/src/components/text/heading.tsx +50 -0
  56. package/src/components/text/index.ts +2 -0
  57. package/src/components/text/text.tsx +62 -0
  58. package/src/components/textarea/index.ts +1 -0
  59. package/src/components/textarea/textarea.tsx +87 -0
  60. package/src/components/toast/index.ts +2 -0
  61. package/src/components/toast/toast.tsx +136 -0
  62. package/src/components/toast/types.ts +32 -0
  63. package/src/index.ts +42 -0
  64. package/src/primitives/box.tsx +25 -0
  65. package/src/primitives/index.ts +2 -0
  66. package/src/primitives/pressable.tsx +49 -0
  67. package/src/providers/BeyondUIProvider.tsx +100 -0
  68. package/src/templates/auth/ForgotPasswordTemplate.tsx +132 -0
  69. package/src/templates/auth/SignInTemplate.tsx +213 -0
  70. package/src/templates/auth/SignUpTemplate.tsx +233 -0
  71. package/src/templates/auth/index.ts +3 -0
  72. package/src/templates/dashboard/DashboardTemplate.tsx +205 -0
  73. package/src/templates/dashboard/index.ts +1 -0
  74. package/src/templates/index.ts +3 -0
  75. package/src/templates/settings/SettingsTemplate.tsx +226 -0
  76. package/src/templates/settings/index.ts +1 -0
  77. package/src/theme/preset.ts +45 -0
  78. package/src/theme/tokens.ts +144 -0
  79. package/src/types/nativewind-env.d.ts +26 -0
  80. package/src/utilities/accessibility.ts +43 -0
  81. package/src/utilities/cn.ts +9 -0
  82. package/src/utilities/index.ts +2 -0
  83. package/dist/chunk-2B6HTSGM.mjs.map +0 -1
@@ -0,0 +1,172 @@
1
+ import * as React from "react";
2
+ import {
3
+ View,
4
+ Text,
5
+ Pressable,
6
+ type ViewProps,
7
+ type PressableProps,
8
+ type GestureResponderEvent,
9
+ } from "react-native";
10
+ import { cn } from "../../utilities/cn";
11
+
12
+ export interface TabsContextValue {
13
+ value: string;
14
+ onValueChange: (value: string) => void;
15
+ }
16
+
17
+ export const TabsContext = React.createContext<TabsContextValue | null>(null);
18
+
19
+ export function useTabsContext(): TabsContextValue {
20
+ const context = React.useContext(TabsContext);
21
+ if (!context) {
22
+ throw new Error("Tabs compound components must be rendered inside a Tabs component");
23
+ }
24
+ return context;
25
+ }
26
+
27
+ export interface TabsProps extends ViewProps {
28
+ value?: string;
29
+ defaultValue?: string;
30
+ onValueChange?: (value: string) => void;
31
+ className?: string;
32
+ }
33
+
34
+ export const Tabs = React.forwardRef<View, TabsProps>(function Tabs(
35
+ { value: controlledValue, defaultValue = "", onValueChange, className, children, ...props },
36
+ ref
37
+ ) {
38
+ const [internalValue, setInternalValue] = React.useState(defaultValue);
39
+ const isControlled = controlledValue !== undefined;
40
+ const currentValue = isControlled ? controlledValue : internalValue;
41
+
42
+ const handleValueChange = React.useCallback(
43
+ (val: string) => {
44
+ if (!isControlled) {
45
+ setInternalValue(val);
46
+ }
47
+ onValueChange?.(val);
48
+ },
49
+ [isControlled, onValueChange]
50
+ );
51
+
52
+ return (
53
+ <TabsContext.Provider value={{ value: currentValue, onValueChange: handleValueChange }}>
54
+ <View ref={ref} className={className} {...props}>
55
+ {children}
56
+ </View>
57
+ </TabsContext.Provider>
58
+ );
59
+ });
60
+ Tabs.displayName = "Tabs";
61
+
62
+ export interface TabsListProps extends ViewProps {
63
+ className?: string;
64
+ }
65
+
66
+ export const TabsList = React.forwardRef<View, TabsListProps>(function TabsList(
67
+ { className, ...props },
68
+ ref
69
+ ) {
70
+ return (
71
+ <View
72
+ ref={ref}
73
+ role="tablist"
74
+ className={cn(
75
+ "flex-row items-center justify-center rounded-xl bg-neutral-100 dark:bg-neutral-800 p-1",
76
+ className
77
+ )}
78
+ {...props}
79
+ />
80
+ );
81
+ });
82
+ TabsList.displayName = "TabsList";
83
+
84
+ export interface TabsTriggerProps extends Omit<PressableProps, "onPress"> {
85
+ value: string;
86
+ className?: string;
87
+ textClassName?: string;
88
+ children?: React.ReactNode;
89
+ onPress?: (e: GestureResponderEvent) => void;
90
+ }
91
+
92
+ export const TabsTrigger = React.forwardRef<
93
+ React.ElementRef<typeof Pressable>,
94
+ TabsTriggerProps
95
+ >(function TabsTrigger({ value, className, textClassName, children, onPress, disabled, ...props }, ref) {
96
+ const { value: selectedValue, onValueChange } = useTabsContext();
97
+ const isSelected = selectedValue === value;
98
+
99
+ const handlePress = (e: GestureResponderEvent) => {
100
+ if (disabled) return;
101
+ onValueChange(value);
102
+ onPress?.(e);
103
+ };
104
+
105
+ return (
106
+ <Pressable
107
+ ref={ref}
108
+ role="tab"
109
+ accessibilityRole="tab"
110
+ accessibilityState={{ selected: isSelected, disabled: !!disabled }}
111
+ disabled={disabled}
112
+ onPress={handlePress}
113
+ className={cn(
114
+ "flex-1 items-center justify-center rounded-lg py-2 px-3 transition-all",
115
+ isSelected
116
+ ? "bg-white dark:bg-neutral-900 shadow-sm"
117
+ : "bg-transparent opacity-70",
118
+ disabled && "opacity-40",
119
+ className
120
+ )}
121
+ {...props}
122
+ >
123
+ {typeof children === "string" ? (
124
+ <Text
125
+ className={cn(
126
+ "text-sm font-semibold",
127
+ isSelected
128
+ ? "text-neutral-900 dark:text-neutral-50"
129
+ : "text-neutral-600 dark:text-neutral-400",
130
+ textClassName
131
+ )}
132
+ >
133
+ {children}
134
+ </Text>
135
+ ) : (
136
+ children
137
+ )}
138
+ </Pressable>
139
+ );
140
+ });
141
+ TabsTrigger.displayName = "TabsTrigger";
142
+
143
+ export interface TabsContentProps extends ViewProps {
144
+ value: string;
145
+ className?: string;
146
+ forceMount?: boolean;
147
+ }
148
+
149
+ export const TabsContent = React.forwardRef<View, TabsContentProps>(function TabsContent(
150
+ { value, className, forceMount, children, ...props },
151
+ ref
152
+ ) {
153
+ const { value: selectedValue } = useTabsContext();
154
+ const isSelected = selectedValue === value;
155
+
156
+ if (!isSelected && !forceMount) {
157
+ return null;
158
+ }
159
+
160
+ return (
161
+ <View
162
+ ref={ref}
163
+ role="tabpanel"
164
+ accessibilityElementsHidden={!isSelected}
165
+ className={cn("mt-3", className)}
166
+ {...props}
167
+ >
168
+ {children}
169
+ </View>
170
+ );
171
+ });
172
+ TabsContent.displayName = "TabsContent";
@@ -0,0 +1,50 @@
1
+ import * as React from "react";
2
+ import { Text as NativeText, type TextProps as NativeTextProps } from "react-native";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+ import { cn } from "../../utilities/cn";
5
+
6
+ export const headingVariants = cva("font-bold text-neutral-900 dark:text-neutral-50 tracking-tight", {
7
+ variants: {
8
+ level: {
9
+ h1: "text-3xl font-extrabold",
10
+ h2: "text-2xl font-bold",
11
+ h3: "text-xl font-bold",
12
+ h4: "text-lg font-semibold",
13
+ h5: "text-base font-semibold",
14
+ h6: "text-sm font-semibold uppercase tracking-wider",
15
+ },
16
+ },
17
+ defaultVariants: {
18
+ level: "h2",
19
+ },
20
+ });
21
+
22
+ export type HeadingLevel = "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | 1 | 2 | 3 | 4 | 5 | 6;
23
+
24
+ export interface HeadingProps
25
+ extends NativeTextProps,
26
+ Omit<VariantProps<typeof headingVariants>, "level"> {
27
+ level?: HeadingLevel;
28
+ className?: string;
29
+ }
30
+
31
+ export const Heading = React.forwardRef<NativeText, HeadingProps>(function Heading(
32
+ { className, level = "h2", ...props },
33
+ ref
34
+ ) {
35
+ const normalizedLevel =
36
+ typeof level === "number"
37
+ ? (`h${level}` as "h1" | "h2" | "h3" | "h4" | "h5" | "h6")
38
+ : level;
39
+
40
+ return (
41
+ <NativeText
42
+ ref={ref}
43
+ accessibilityRole="header"
44
+ className={cn(headingVariants({ level: normalizedLevel }), className)}
45
+ {...props}
46
+ />
47
+ );
48
+ });
49
+
50
+ Heading.displayName = "Heading";
@@ -0,0 +1,2 @@
1
+ export * from "./text";
2
+ export * from "./heading";
@@ -0,0 +1,62 @@
1
+ import * as React from "react";
2
+ import { Text as NativeText, type TextProps as NativeTextProps } from "react-native";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+ import { cn } from "../../utilities/cn";
5
+
6
+ export const textVariants = cva("text-neutral-900 dark:text-neutral-100", {
7
+ variants: {
8
+ variant: {
9
+ body: "text-base font-normal",
10
+ caption: "text-xs font-normal text-neutral-500 dark:text-neutral-400",
11
+ label: "text-sm font-medium text-neutral-700 dark:text-neutral-300",
12
+ muted: "text-sm font-normal text-neutral-500 dark:text-neutral-400",
13
+ lead: "text-lg font-normal text-neutral-600 dark:text-neutral-300",
14
+ },
15
+ color: {
16
+ default: "text-neutral-900 dark:text-neutral-100",
17
+ muted: "text-neutral-500 dark:text-neutral-400",
18
+ primary: "text-primary-600 dark:text-primary-400",
19
+ secondary: "text-secondary-600 dark:text-secondary-400",
20
+ danger: "text-danger-600 dark:text-danger-400",
21
+ success: "text-success-600 dark:text-success-400",
22
+ warning: "text-warning-600 dark:text-warning-400",
23
+ },
24
+ size: {
25
+ xs: "text-xs",
26
+ sm: "text-sm",
27
+ base: "text-base",
28
+ lg: "text-lg",
29
+ xl: "text-xl",
30
+ },
31
+ weight: {
32
+ normal: "font-normal",
33
+ medium: "font-medium",
34
+ semibold: "font-semibold",
35
+ bold: "font-bold",
36
+ },
37
+ },
38
+ defaultVariants: {
39
+ variant: "body",
40
+ },
41
+ });
42
+
43
+ export interface TextProps
44
+ extends NativeTextProps,
45
+ VariantProps<typeof textVariants> {
46
+ className?: string;
47
+ }
48
+
49
+ export const Text = React.forwardRef<NativeText, TextProps>(function Text(
50
+ { className, variant, color, size, weight, ...props },
51
+ ref
52
+ ) {
53
+ return (
54
+ <NativeText
55
+ ref={ref}
56
+ className={cn(textVariants({ variant, color, size, weight }), className)}
57
+ {...props}
58
+ />
59
+ );
60
+ });
61
+
62
+ Text.displayName = "Text";
@@ -0,0 +1 @@
1
+ export * from "./textarea";
@@ -0,0 +1,87 @@
1
+ import * as React from "react";
2
+ import {
3
+ Text,
4
+ TextInput,
5
+ View,
6
+ type TextInputProps,
7
+ } from "react-native";
8
+ import { cn } from "../../utilities/cn";
9
+
10
+ export interface TextareaProps
11
+ extends Omit<TextInputProps, "multiline"> {
12
+ label?: string;
13
+ error?: string;
14
+ helperText?: string;
15
+ disabled?: boolean;
16
+ rows?: number;
17
+ containerClassName?: string;
18
+ className?: string;
19
+ labelClassName?: string;
20
+ }
21
+
22
+ export const Textarea = React.forwardRef<TextInput, TextareaProps>(function Textarea(
23
+ {
24
+ label,
25
+ error,
26
+ helperText,
27
+ disabled = false,
28
+ rows = 4,
29
+ containerClassName,
30
+ className,
31
+ labelClassName,
32
+ placeholderTextColor,
33
+ accessibilityLabel,
34
+ ...props
35
+ },
36
+ ref
37
+ ) {
38
+ const minHeight = Math.max(80, rows * 22);
39
+
40
+ return (
41
+ <View className={cn("w-full gap-1.5", containerClassName)}>
42
+ {label ? (
43
+ <Text
44
+ className={cn(
45
+ "text-sm font-medium text-neutral-800 dark:text-neutral-200",
46
+ labelClassName
47
+ )}
48
+ >
49
+ {label}
50
+ </Text>
51
+ ) : null}
52
+
53
+ <TextInput
54
+ ref={ref}
55
+ multiline
56
+ textAlignVertical="top"
57
+ editable={!disabled}
58
+ accessibilityLabel={accessibilityLabel ?? label}
59
+ accessibilityHint={error}
60
+ aria-invalid={!!error}
61
+ placeholderTextColor={placeholderTextColor ?? "#9ca3af"}
62
+ style={{ minHeight }}
63
+ className={cn(
64
+ "w-full rounded-xl border bg-white dark:bg-neutral-900 text-neutral-900 dark:text-neutral-100 p-3.5 text-base",
65
+ error
66
+ ? "border-danger-500 dark:border-danger-500"
67
+ : "border-neutral-300 dark:border-neutral-700 focus:border-primary-500",
68
+ disabled && "opacity-50 bg-neutral-100 dark:bg-neutral-800",
69
+ className
70
+ )}
71
+ {...props}
72
+ />
73
+
74
+ {error ? (
75
+ <Text accessibilityRole="alert" className="text-xs font-medium text-danger-600 dark:text-danger-400">
76
+ {error}
77
+ </Text>
78
+ ) : helperText ? (
79
+ <Text className="text-xs text-neutral-500 dark:text-neutral-400">
80
+ {helperText}
81
+ </Text>
82
+ ) : null}
83
+ </View>
84
+ );
85
+ });
86
+
87
+ Textarea.displayName = "Textarea";
@@ -0,0 +1,2 @@
1
+ export * from "./toast";
2
+ export * from "./types";
@@ -0,0 +1,136 @@
1
+ import * as React from "react";
2
+ import { View, Text, Pressable, Animated } from "react-native";
3
+ import { cva } from "class-variance-authority";
4
+ import { cn } from "../../utilities/cn";
5
+ import { ToastItem, ToastVariant } from "./types";
6
+
7
+ const toastVariants = cva(
8
+ "w-full max-w-sm rounded-xl p-4 shadow-lg border flex-row items-center justify-between mb-2",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: "bg-white border-neutral-200 dark:bg-neutral-900 dark:border-neutral-800",
13
+ success: "bg-success-50 border-success-200 dark:bg-success-950/80 dark:border-success-800",
14
+ danger: "bg-danger-50 border-danger-200 dark:bg-danger-950/80 dark:border-danger-800",
15
+ warning: "bg-warning-50 border-warning-200 dark:bg-warning-950/80 dark:border-warning-800",
16
+ info: "bg-primary-50 border-primary-200 dark:bg-primary-950/80 dark:border-primary-800",
17
+ },
18
+ },
19
+ defaultVariants: {
20
+ variant: "default",
21
+ },
22
+ }
23
+ );
24
+
25
+ const toastTitleVariants = cva("text-sm font-semibold", {
26
+ variants: {
27
+ variant: {
28
+ default: "text-neutral-900 dark:text-white",
29
+ success: "text-success-700 dark:text-success-300",
30
+ danger: "text-danger-700 dark:text-danger-300",
31
+ warning: "text-warning-800 dark:text-warning-300",
32
+ info: "text-primary-700 dark:text-primary-300",
33
+ },
34
+ },
35
+ defaultVariants: {
36
+ variant: "default",
37
+ },
38
+ });
39
+
40
+ interface ToastBannerProps {
41
+ toast: ToastItem;
42
+ onDismiss: (id: string) => void;
43
+ }
44
+
45
+ export function ToastBanner({ toast, onDismiss }: ToastBannerProps) {
46
+ const opacity = React.useRef(new Animated.Value(0)).current;
47
+ const translateY = React.useRef(new Animated.Value(-16)).current;
48
+
49
+ React.useEffect(() => {
50
+ Animated.parallel([
51
+ Animated.timing(opacity, {
52
+ toValue: 1,
53
+ duration: 200,
54
+ useNativeDriver: true,
55
+ }),
56
+ Animated.timing(translateY, {
57
+ toValue: 0,
58
+ duration: 200,
59
+ useNativeDriver: true,
60
+ }),
61
+ ]).start();
62
+
63
+ const timer = setTimeout(() => {
64
+ handleDismiss();
65
+ }, toast.duration || 4000);
66
+
67
+ return () => clearTimeout(timer);
68
+ }, []);
69
+
70
+ const handleDismiss = () => {
71
+ Animated.parallel([
72
+ Animated.timing(opacity, {
73
+ toValue: 0,
74
+ duration: 200,
75
+ useNativeDriver: true,
76
+ }),
77
+ Animated.timing(translateY, {
78
+ toValue: -16,
79
+ duration: 200,
80
+ useNativeDriver: true,
81
+ }),
82
+ ]).start(() => {
83
+ onDismiss(toast.id);
84
+ });
85
+ };
86
+
87
+ const variant: ToastVariant = toast.variant || "default";
88
+
89
+ return (
90
+ <Animated.View
91
+ style={{
92
+ opacity,
93
+ transform: [{ translateY }],
94
+ }}
95
+ className="w-full items-center px-4"
96
+ >
97
+ <Pressable
98
+ onPress={handleDismiss}
99
+ className={cn(toastVariants({ variant }))}
100
+ >
101
+ <View className="flex-1 pr-2">
102
+ <Text className={cn(toastTitleVariants({ variant }))}>
103
+ {toast.title}
104
+ </Text>
105
+ {toast.description ? (
106
+ <Text className="text-xs text-neutral-600 dark:text-neutral-400 mt-0.5">
107
+ {toast.description}
108
+ </Text>
109
+ ) : null}
110
+ </View>
111
+ <Text className="text-xs text-neutral-400">✕</Text>
112
+ </Pressable>
113
+ </Animated.View>
114
+ );
115
+ }
116
+
117
+ export function ToastContainer({
118
+ toasts,
119
+ onDismiss,
120
+ }: {
121
+ toasts: ToastItem[];
122
+ onDismiss: (id: string) => void;
123
+ }) {
124
+ if (toasts.length === 0) return null;
125
+
126
+ return (
127
+ <View
128
+ pointerEvents="box-none"
129
+ className="absolute top-12 left-0 right-0 z-50 items-center"
130
+ >
131
+ {toasts.map((toast) => (
132
+ <ToastBanner key={toast.id} toast={toast} onDismiss={onDismiss} />
133
+ ))}
134
+ </View>
135
+ );
136
+ }
@@ -0,0 +1,32 @@
1
+ import * as React from "react";
2
+
3
+ export type ToastVariant = "default" | "success" | "danger" | "warning" | "info";
4
+
5
+ export interface ToastItem {
6
+ id: string;
7
+ title: string;
8
+ description?: string;
9
+ variant?: ToastVariant;
10
+ duration?: number;
11
+ }
12
+
13
+ export interface ToastContextValue {
14
+ toasts: ToastItem[];
15
+ show: (toast: Omit<ToastItem, "id">) => string;
16
+ dismiss: (id: string) => void;
17
+ success: (title: string, description?: string) => string;
18
+ danger: (title: string, description?: string) => string;
19
+ error: (title: string, description?: string) => string;
20
+ warning: (title: string, description?: string) => string;
21
+ info: (title: string, description?: string) => string;
22
+ }
23
+
24
+ export const ToastContext = React.createContext<ToastContextValue | null>(null);
25
+
26
+ export function useToast(): ToastContextValue {
27
+ const context = React.useContext(ToastContext);
28
+ if (!context) {
29
+ throw new Error("useToast must be used within a BeyondUIProvider");
30
+ }
31
+ return context;
32
+ }
package/src/index.ts ADDED
@@ -0,0 +1,42 @@
1
+ /// <reference path="./types/nativewind-env.d.ts" />
2
+
3
+ // Primitives
4
+ export * from "./primitives";
5
+
6
+ // Components
7
+ export * from "./components/button";
8
+ export * from "./components/text";
9
+ export * from "./components/input";
10
+ export * from "./components/textarea";
11
+ export * from "./components/card";
12
+ export * from "./components/badge";
13
+ export * from "./components/avatar";
14
+ export * from "./components/switch";
15
+ export * from "./components/checkbox";
16
+ export * from "./components/radio";
17
+ export * from "./components/spinner";
18
+ export * from "./components/skeleton";
19
+ export * from "./components/alert";
20
+ export * from "./components/separator";
21
+ export * from "./components/dialog";
22
+ export * from "./components/tabs";
23
+ export * from "./components/toast";
24
+ export * from "./components/stats-card";
25
+ export * from "./components/accordion";
26
+ export * from "./components/bottom-sheet";
27
+ export * from "./components/select";
28
+ export * from "./components/data-table";
29
+
30
+ // Screen Templates
31
+ export * from "./templates";
32
+
33
+ // Providers & Context
34
+ export * from "./providers/BeyondUIProvider";
35
+
36
+ // Theme & Tokens
37
+ export * from "./theme/tokens";
38
+ export { default as beyondUIPreset } from "./theme/preset";
39
+
40
+ // Utilities
41
+ export * from "./utilities/cn";
42
+ export * from "./utilities/accessibility";
@@ -0,0 +1,25 @@
1
+ import * as React from "react";
2
+ import { View, type ViewProps } from "react-native";
3
+ import { cn } from "../utilities/cn";
4
+
5
+ export interface BoxProps extends ViewProps {
6
+ className?: string;
7
+ children?: React.ReactNode;
8
+ }
9
+
10
+ export const Box = React.forwardRef<View, BoxProps>(
11
+ ({ className, style, children, ...props }, ref) => {
12
+ return (
13
+ <View
14
+ ref={ref}
15
+ className={cn(className)}
16
+ style={style}
17
+ {...props}
18
+ >
19
+ {children}
20
+ </View>
21
+ );
22
+ }
23
+ );
24
+
25
+ Box.displayName = "Box";
@@ -0,0 +1,2 @@
1
+ export * from "./box";
2
+ export * from "./pressable";
@@ -0,0 +1,49 @@
1
+ import * as React from "react";
2
+ import {
3
+ Pressable as RNPressable,
4
+ type PressableProps as RNPressableProps,
5
+ type View,
6
+ type GestureResponderEvent,
7
+ } from "react-native";
8
+ import { cn } from "../utilities/cn";
9
+
10
+ export interface PressableProps extends Omit<RNPressableProps, "children"> {
11
+ className?: string;
12
+ children?: React.ReactNode | ((state: { pressed: boolean }) => React.ReactNode);
13
+ feedback?: "opacity" | "scale" | "none";
14
+ }
15
+
16
+ export const Pressable = React.forwardRef<View, PressableProps>(
17
+ (
18
+ {
19
+ className,
20
+ style,
21
+ disabled,
22
+ feedback = "opacity",
23
+ children,
24
+ ...props
25
+ },
26
+ ref
27
+ ) => {
28
+ return (
29
+ <RNPressable
30
+ ref={ref}
31
+ disabled={disabled}
32
+ accessibilityRole="button"
33
+ accessibilityState={{ disabled: !!disabled }}
34
+ className={cn(
35
+ feedback === "opacity" && "active:opacity-70",
36
+ feedback === "scale" && "active:scale-[0.98]",
37
+ disabled && "opacity-50",
38
+ className
39
+ )}
40
+ style={style}
41
+ {...props}
42
+ >
43
+ {typeof children === "function" ? children : children}
44
+ </RNPressable>
45
+ );
46
+ }
47
+ );
48
+
49
+ Pressable.displayName = "Pressable";