@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,278 @@
1
+ import * as React from "react";
2
+ import {
3
+ Modal,
4
+ View,
5
+ Text,
6
+ Pressable,
7
+ StyleSheet,
8
+ type ViewProps,
9
+ type TextProps,
10
+ type PressableProps,
11
+ type GestureResponderEvent,
12
+ } from "react-native";
13
+ import { cn } from "../../utilities/cn";
14
+
15
+ export interface DialogContextValue {
16
+ open: boolean;
17
+ onOpenChange: (open: boolean) => void;
18
+ }
19
+
20
+ export const DialogContext = React.createContext<DialogContextValue | null>(null);
21
+
22
+ export function useDialogContext(): DialogContextValue {
23
+ const context = React.useContext(DialogContext);
24
+ if (!context) {
25
+ throw new Error("Dialog compound components must be used within a Dialog component");
26
+ }
27
+ return context;
28
+ }
29
+
30
+ export interface DialogProps {
31
+ open?: boolean;
32
+ defaultOpen?: boolean;
33
+ onOpenChange?: (open: boolean) => void;
34
+ children: React.ReactNode;
35
+ }
36
+
37
+ export function Dialog({
38
+ open: controlledOpen,
39
+ defaultOpen = false,
40
+ onOpenChange,
41
+ children,
42
+ }: DialogProps) {
43
+ const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);
44
+ const isControlled = controlledOpen !== undefined;
45
+ const open = isControlled ? controlledOpen : uncontrolledOpen;
46
+
47
+ const handleOpenChange = React.useCallback(
48
+ (nextOpen: boolean) => {
49
+ if (!isControlled) {
50
+ setUncontrolledOpen(nextOpen);
51
+ }
52
+ onOpenChange?.(nextOpen);
53
+ },
54
+ [isControlled, onOpenChange]
55
+ );
56
+
57
+ return (
58
+ <DialogContext.Provider value={{ open, onOpenChange: handleOpenChange }}>
59
+ {children}
60
+ </DialogContext.Provider>
61
+ );
62
+ }
63
+ Dialog.displayName = "Dialog";
64
+
65
+ export interface DialogTriggerProps extends PressableProps {
66
+ asChild?: boolean;
67
+ className?: string;
68
+ children: React.ReactNode;
69
+ }
70
+
71
+ export const DialogTrigger = React.forwardRef<View, DialogTriggerProps>(
72
+ function DialogTrigger({ asChild, children, onPress, ...props }, ref) {
73
+ const { open, onOpenChange } = useDialogContext();
74
+
75
+ const handlePress = (e: GestureResponderEvent) => {
76
+ onOpenChange(!open);
77
+ onPress?.(e);
78
+ };
79
+
80
+ if (asChild && React.isValidElement(children)) {
81
+ return React.cloneElement(children as React.ReactElement<any>, {
82
+ ref,
83
+ onPress: (e: GestureResponderEvent) => {
84
+ (children.props as any)?.onPress?.(e);
85
+ handlePress(e);
86
+ },
87
+ });
88
+ }
89
+
90
+ return (
91
+ <Pressable ref={ref} onPress={handlePress} role="button" {...props}>
92
+ {children}
93
+ </Pressable>
94
+ );
95
+ }
96
+ );
97
+ DialogTrigger.displayName = "DialogTrigger";
98
+
99
+ export interface DialogPortalProps {
100
+ children: React.ReactNode;
101
+ forceMount?: boolean;
102
+ }
103
+
104
+ export function DialogPortal({ children, forceMount }: DialogPortalProps) {
105
+ const { open, onOpenChange } = useDialogContext();
106
+
107
+ if (!open && !forceMount) {
108
+ return null;
109
+ }
110
+
111
+ return (
112
+ <Modal
113
+ transparent
114
+ visible={open}
115
+ animationType="fade"
116
+ onRequestClose={() => onOpenChange(false)}
117
+ statusBarTranslucent
118
+ >
119
+ {children}
120
+ </Modal>
121
+ );
122
+ }
123
+ DialogPortal.displayName = "DialogPortal";
124
+
125
+ export interface DialogOverlayProps extends ViewProps {
126
+ className?: string;
127
+ closeOnPress?: boolean;
128
+ }
129
+
130
+ export const DialogOverlay = React.forwardRef<View, DialogOverlayProps>(
131
+ function DialogOverlay({ className, closeOnPress = true, ...props }, ref) {
132
+ const { onOpenChange } = useDialogContext();
133
+
134
+ return (
135
+ <Pressable
136
+ ref={ref}
137
+ style={StyleSheet.absoluteFill}
138
+ className={cn("z-50 bg-black/60", className)}
139
+ onPress={() => {
140
+ if (closeOnPress) {
141
+ onOpenChange(false);
142
+ }
143
+ }}
144
+ {...props}
145
+ />
146
+ );
147
+ }
148
+ );
149
+ DialogOverlay.displayName = "DialogOverlay";
150
+
151
+ export interface DialogContentProps extends ViewProps {
152
+ className?: string;
153
+ overlayClassName?: string;
154
+ children: React.ReactNode;
155
+ }
156
+
157
+ export const DialogContent = React.forwardRef<View, DialogContentProps>(
158
+ function DialogContent({ className, overlayClassName, children, ...props }, ref) {
159
+ return (
160
+ <DialogPortal>
161
+ <View
162
+ pointerEvents="box-none"
163
+ style={StyleSheet.absoluteFill}
164
+ className="z-50 items-center justify-center p-4"
165
+ >
166
+ <DialogOverlay className={overlayClassName} />
167
+ <View
168
+ ref={ref}
169
+ role="dialog"
170
+ aria-modal={true}
171
+ className={cn(
172
+ "z-50 w-full max-w-lg rounded-2xl border border-neutral-200 dark:border-neutral-800 bg-white dark:bg-neutral-900 p-6 shadow-2xl",
173
+ className
174
+ )}
175
+ {...props}
176
+ >
177
+ {children}
178
+ </View>
179
+ </View>
180
+ </DialogPortal>
181
+ );
182
+ }
183
+ );
184
+ DialogContent.displayName = "DialogContent";
185
+
186
+ export function DialogHeader({
187
+ className,
188
+ ...props
189
+ }: ViewProps & { className?: string }) {
190
+ return (
191
+ <View
192
+ className={cn("flex-col space-y-2 text-center sm:text-left", className)}
193
+ {...props}
194
+ />
195
+ );
196
+ }
197
+ DialogHeader.displayName = "DialogHeader";
198
+
199
+ export const DialogTitle = React.forwardRef<Text, TextProps & { className?: string }>(
200
+ function DialogTitle({ className, ...props }, ref) {
201
+ return (
202
+ <Text
203
+ ref={ref}
204
+ role="heading"
205
+ aria-level={2}
206
+ className={cn(
207
+ "text-xl font-bold tracking-tight text-neutral-900 dark:text-neutral-50",
208
+ className
209
+ )}
210
+ {...props}
211
+ />
212
+ );
213
+ }
214
+ );
215
+ DialogTitle.displayName = "DialogTitle";
216
+
217
+ export const DialogDescription = React.forwardRef<Text, TextProps & { className?: string }>(
218
+ function DialogDescription({ className, ...props }, ref) {
219
+ return (
220
+ <Text
221
+ ref={ref}
222
+ className={cn(
223
+ "text-sm text-neutral-500 dark:text-neutral-400 mt-1",
224
+ className
225
+ )}
226
+ {...props}
227
+ />
228
+ );
229
+ }
230
+ );
231
+ DialogDescription.displayName = "DialogDescription";
232
+
233
+ export function DialogFooter({
234
+ className,
235
+ ...props
236
+ }: ViewProps & { className?: string }) {
237
+ return (
238
+ <View
239
+ className={cn("flex-row justify-end space-x-2 mt-6", className)}
240
+ {...props}
241
+ />
242
+ );
243
+ }
244
+ DialogFooter.displayName = "DialogFooter";
245
+
246
+ export interface DialogCloseProps extends PressableProps {
247
+ asChild?: boolean;
248
+ className?: string;
249
+ children: React.ReactNode;
250
+ }
251
+
252
+ export const DialogClose = React.forwardRef<View, DialogCloseProps>(
253
+ function DialogClose({ asChild, children, onPress, ...props }, ref) {
254
+ const { onOpenChange } = useDialogContext();
255
+
256
+ const handlePress = (e: GestureResponderEvent) => {
257
+ onOpenChange(false);
258
+ onPress?.(e);
259
+ };
260
+
261
+ if (asChild && React.isValidElement(children)) {
262
+ return React.cloneElement(children as React.ReactElement<any>, {
263
+ ref,
264
+ onPress: (e: GestureResponderEvent) => {
265
+ (children.props as any)?.onPress?.(e);
266
+ handlePress(e);
267
+ },
268
+ });
269
+ }
270
+
271
+ return (
272
+ <Pressable ref={ref} onPress={handlePress} role="button" {...props}>
273
+ {children}
274
+ </Pressable>
275
+ );
276
+ }
277
+ );
278
+ DialogClose.displayName = "DialogClose";
@@ -0,0 +1 @@
1
+ export * from "./dialog";
@@ -0,0 +1 @@
1
+ export * from "./input";
@@ -0,0 +1,130 @@
1
+ import * as React from "react";
2
+ import {
3
+ Text,
4
+ TextInput,
5
+ View,
6
+ type TextInputProps,
7
+ } from "react-native";
8
+ import { cva, type VariantProps } from "class-variance-authority";
9
+ import { cn } from "../../utilities/cn";
10
+
11
+ export const inputVariants = cva(
12
+ "w-full rounded-xl border bg-white dark:bg-neutral-900 text-neutral-900 dark:text-neutral-100 px-3.5 flex-row items-center",
13
+ {
14
+ variants: {
15
+ inputSize: {
16
+ sm: "min-h-9 py-1 text-sm",
17
+ md: "min-h-11 py-2 text-base",
18
+ lg: "min-h-14 py-3 text-lg",
19
+ },
20
+ status: {
21
+ default: "border-neutral-300 dark:border-neutral-700 focus:border-primary-500",
22
+ error: "border-danger-500 dark:border-danger-500",
23
+ success: "border-success-500 dark:border-success-500",
24
+ },
25
+ disabled: {
26
+ true: "opacity-50 bg-neutral-100 dark:bg-neutral-800",
27
+ false: "",
28
+ },
29
+ },
30
+ defaultVariants: {
31
+ inputSize: "md",
32
+ status: "default",
33
+ disabled: false,
34
+ },
35
+ }
36
+ );
37
+
38
+ export interface InputProps
39
+ extends Omit<TextInputProps, "editable">,
40
+ VariantProps<typeof inputVariants> {
41
+ label?: string;
42
+ error?: string;
43
+ helperText?: string;
44
+ leftIcon?: React.ReactNode;
45
+ rightIcon?: React.ReactNode;
46
+ leftElement?: React.ReactNode;
47
+ rightElement?: React.ReactNode;
48
+ disabled?: boolean;
49
+ containerClassName?: string;
50
+ className?: string;
51
+ labelClassName?: string;
52
+ }
53
+
54
+ export const Input = React.forwardRef<TextInput, InputProps>(function Input(
55
+ {
56
+ label,
57
+ error,
58
+ helperText,
59
+ leftIcon,
60
+ rightIcon,
61
+ leftElement,
62
+ rightElement,
63
+ disabled = false,
64
+ inputSize = "md",
65
+ containerClassName,
66
+ className,
67
+ labelClassName,
68
+ placeholderTextColor,
69
+ accessibilityLabel,
70
+ ...props
71
+ },
72
+ ref
73
+ ) {
74
+ const status = error ? "error" : "default";
75
+
76
+ return (
77
+ <View className={cn("w-full gap-1.5", containerClassName)}>
78
+ {label ? (
79
+ <Text
80
+ className={cn(
81
+ "text-sm font-medium text-neutral-800 dark:text-neutral-200",
82
+ labelClassName
83
+ )}
84
+ >
85
+ {label}
86
+ </Text>
87
+ ) : null}
88
+
89
+ <View
90
+ className={cn(
91
+ inputVariants({ inputSize, status, disabled }),
92
+ className
93
+ )}
94
+ >
95
+ {leftIcon || leftElement ? (
96
+ <View className="mr-2">{leftIcon ?? leftElement}</View>
97
+ ) : null}
98
+
99
+ <TextInput
100
+ ref={ref}
101
+ editable={!disabled}
102
+ accessibilityLabel={accessibilityLabel ?? label}
103
+ accessibilityHint={error}
104
+ aria-invalid={!!error}
105
+ placeholderTextColor={
106
+ placeholderTextColor ?? "#9ca3af" // neutral-400
107
+ }
108
+ className="flex-1 py-1 text-neutral-900 dark:text-neutral-100"
109
+ {...props}
110
+ />
111
+
112
+ {rightIcon || rightElement ? (
113
+ <View className="ml-2">{rightIcon ?? rightElement}</View>
114
+ ) : null}
115
+ </View>
116
+
117
+ {error ? (
118
+ <Text accessibilityRole="alert" className="text-xs font-medium text-danger-600 dark:text-danger-400">
119
+ {error}
120
+ </Text>
121
+ ) : helperText ? (
122
+ <Text className="text-xs text-neutral-500 dark:text-neutral-400">
123
+ {helperText}
124
+ </Text>
125
+ ) : null}
126
+ </View>
127
+ );
128
+ });
129
+
130
+ Input.displayName = "Input";
@@ -0,0 +1 @@
1
+ export * from "./radio";
@@ -0,0 +1,117 @@
1
+ import * as React from "react";
2
+ import { View, Text, Pressable, type ViewProps } from "react-native";
3
+ import { cn } from "../../utilities/cn";
4
+
5
+ interface RadioGroupContextValue {
6
+ value?: string;
7
+ onValueChange?: (value: string) => void;
8
+ disabled?: boolean;
9
+ }
10
+
11
+ const RadioGroupContext = React.createContext<RadioGroupContextValue>({});
12
+
13
+ export interface RadioGroupProps extends ViewProps {
14
+ value?: string;
15
+ defaultValue?: string;
16
+ onValueChange?: (value: string) => void;
17
+ disabled?: boolean;
18
+ className?: string;
19
+ }
20
+
21
+ export function RadioGroup({
22
+ value: controlledValue,
23
+ defaultValue,
24
+ onValueChange,
25
+ disabled = false,
26
+ className,
27
+ children,
28
+ ...props
29
+ }: RadioGroupProps) {
30
+ const [internalValue, setInternalValue] = React.useState(defaultValue);
31
+ const isControlled = controlledValue !== undefined;
32
+ const currentValue = isControlled ? controlledValue : internalValue;
33
+
34
+ const handleValueChange = (val: string) => {
35
+ if (!isControlled) setInternalValue(val);
36
+ onValueChange?.(val);
37
+ };
38
+
39
+ return (
40
+ <RadioGroupContext.Provider
41
+ value={{
42
+ value: currentValue,
43
+ onValueChange: handleValueChange,
44
+ disabled,
45
+ }}
46
+ >
47
+ <View className={cn("gap-3", className)} {...props}>
48
+ {children}
49
+ </View>
50
+ </RadioGroupContext.Provider>
51
+ );
52
+ }
53
+
54
+ export interface RadioProps {
55
+ value: string;
56
+ label?: string;
57
+ disabled?: boolean;
58
+ className?: string;
59
+ indicatorClassName?: string;
60
+ labelClassName?: string;
61
+ }
62
+
63
+ export function Radio({
64
+ value,
65
+ label,
66
+ disabled: itemDisabled,
67
+ className,
68
+ indicatorClassName,
69
+ labelClassName,
70
+ }: RadioProps) {
71
+ const group = React.useContext(RadioGroupContext);
72
+ const isSelected = group.value === value;
73
+ const isDisabled = group.disabled || itemDisabled;
74
+
75
+ const handlePress = () => {
76
+ if (!isDisabled) {
77
+ group.onValueChange?.(value);
78
+ }
79
+ };
80
+
81
+ return (
82
+ <Pressable
83
+ onPress={handlePress}
84
+ disabled={isDisabled}
85
+ accessibilityRole="radio"
86
+ accessibilityState={{ selected: isSelected, disabled: isDisabled }}
87
+ className={cn("flex-row items-center gap-2.5", isDisabled && "opacity-50")}
88
+ >
89
+ <View
90
+ className={cn(
91
+ "h-5 w-5 rounded-full border border-neutral-300 dark:border-neutral-700 items-center justify-center bg-white dark:bg-neutral-900",
92
+ isSelected && "border-primary-600 dark:border-primary-600",
93
+ className
94
+ )}
95
+ >
96
+ {isSelected ? (
97
+ <View
98
+ className={cn(
99
+ "h-2.5 w-2.5 rounded-full bg-primary-600 dark:bg-primary-600",
100
+ indicatorClassName
101
+ )}
102
+ />
103
+ ) : null}
104
+ </View>
105
+ {label ? (
106
+ <Text
107
+ className={cn(
108
+ "text-sm font-medium text-neutral-800 dark:text-neutral-200",
109
+ labelClassName
110
+ )}
111
+ >
112
+ {label}
113
+ </Text>
114
+ ) : null}
115
+ </Pressable>
116
+ );
117
+ }
@@ -0,0 +1 @@
1
+ export * from "./select";