@munchi_oy/native-ui 0.1.0

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/index.d.mts +568 -0
  2. package/dist/index.d.ts +568 -0
  3. package/dist/index.js +1 -0
  4. package/dist/index.mjs +1 -0
  5. package/global.css +53 -0
  6. package/nativewind-env.d.ts +2 -0
  7. package/package.json +88 -0
  8. package/src/MAlert.tsx +38 -0
  9. package/src/MAnimation.tsx +55 -0
  10. package/src/MAvatar.tsx +111 -0
  11. package/src/MBadge.tsx +72 -0
  12. package/src/MButton.tsx +90 -0
  13. package/src/MCard.tsx +15 -0
  14. package/src/MChevron.tsx +47 -0
  15. package/src/MConfirmation.tsx +68 -0
  16. package/src/MCountDown.tsx +120 -0
  17. package/src/MDateTimePicker.tsx +124 -0
  18. package/src/MDivider.tsx +69 -0
  19. package/src/MDrawerRightPanel.tsx +187 -0
  20. package/src/MDropdown.tsx +277 -0
  21. package/src/MInput.tsx +162 -0
  22. package/src/MLabel.tsx +3 -0
  23. package/src/MLucideIcon.tsx +21 -0
  24. package/src/MModal.tsx +287 -0
  25. package/src/MNativeAlert.tsx +33 -0
  26. package/src/MNumpad.tsx +520 -0
  27. package/src/MPicker.tsx +150 -0
  28. package/src/MPinPadKeys.tsx +104 -0
  29. package/src/MPortal.tsx +4 -0
  30. package/src/MProgressBar.tsx +74 -0
  31. package/src/MRadioGroup.tsx +4 -0
  32. package/src/MRequiredLabel.tsx +21 -0
  33. package/src/MResponsiveContainer.tsx +74 -0
  34. package/src/MSearch.tsx +138 -0
  35. package/src/MSelector.tsx +48 -0
  36. package/src/MSkeleton.tsx +3 -0
  37. package/src/MSwitch.tsx +13 -0
  38. package/src/MTable.tsx +17 -0
  39. package/src/MTabs.tsx +198 -0
  40. package/src/MText.tsx +51 -0
  41. package/src/MTimerUp.tsx +88 -0
  42. package/src/MToggle.tsx +51 -0
  43. package/src/constants.ts +19 -0
  44. package/src/hooks/useColorScheme.tsx +12 -0
  45. package/src/hooks/useIconColors.ts +19 -0
  46. package/src/index.ts +124 -0
  47. package/src/primitives/accordion.tsx +143 -0
  48. package/src/primitives/alert-dialog.tsx +181 -0
  49. package/src/primitives/alert.tsx +94 -0
  50. package/src/primitives/aspect-ratio.tsx +5 -0
  51. package/src/primitives/avatar.tsx +47 -0
  52. package/src/primitives/badge.tsx +57 -0
  53. package/src/primitives/button.tsx +92 -0
  54. package/src/primitives/card.tsx +86 -0
  55. package/src/primitives/checkbox.tsx +35 -0
  56. package/src/primitives/collapsible.tsx +9 -0
  57. package/src/primitives/context-menu.tsx +255 -0
  58. package/src/primitives/dialog.tsx +166 -0
  59. package/src/primitives/dropdown-menu.tsx +264 -0
  60. package/src/primitives/hover-card.tsx +45 -0
  61. package/src/primitives/input.tsx +25 -0
  62. package/src/primitives/label.tsx +33 -0
  63. package/src/primitives/menubar.tsx +266 -0
  64. package/src/primitives/navigation-menu.tsx +192 -0
  65. package/src/primitives/popover.tsx +46 -0
  66. package/src/primitives/progress.tsx +82 -0
  67. package/src/primitives/radio-group.tsx +42 -0
  68. package/src/primitives/select.tsx +192 -0
  69. package/src/primitives/separator.tsx +28 -0
  70. package/src/primitives/skeleton.tsx +39 -0
  71. package/src/primitives/switch.tsx +102 -0
  72. package/src/primitives/table.tsx +107 -0
  73. package/src/primitives/tabs.tsx +66 -0
  74. package/src/primitives/text.tsx +28 -0
  75. package/src/primitives/textarea.tsx +39 -0
  76. package/src/primitives/toggle-group.tsx +89 -0
  77. package/src/primitives/toggle.tsx +91 -0
  78. package/src/primitives/tooltip.tsx +40 -0
  79. package/src/primitives/typography.tsx +214 -0
  80. package/src/theme.ts +43 -0
  81. package/src/tokens.ts +7 -0
  82. package/src/utils.ts +14 -0
  83. package/tailwind.config.ts +112 -0
@@ -0,0 +1,192 @@
1
+ import * as SelectPrimitive from "@rn-primitives/select";
2
+ import { Check, ChevronDown, ChevronUp } from "lucide-react-native";
3
+ import * as React from "react";
4
+ import { Platform, StyleSheet, View } from "react-native";
5
+ import Animated, { FadeIn, FadeOut } from "react-native-reanimated";
6
+ import { cn } from "../utils";
7
+
8
+ type Option = SelectPrimitive.Option;
9
+
10
+ const Select = SelectPrimitive.Root;
11
+
12
+ const SelectGroup = SelectPrimitive.Group;
13
+
14
+ const SelectValue = SelectPrimitive.Value;
15
+
16
+ const SelectTrigger = React.forwardRef<
17
+ SelectPrimitive.TriggerRef,
18
+ SelectPrimitive.TriggerProps
19
+ >(({ className, children, ...props }, ref) => (
20
+ <SelectPrimitive.Trigger
21
+ ref={ref}
22
+ className={cn(
23
+ "flex flex-row h-10 native:h-12 items-center text-sm justify-between rounded-md border border-input bg-background px-3 py-2 web:ring-offset-background text-muted-foreground web:focus:outline-none web:focus:ring-2 web:focus:ring-ring web:focus:ring-offset-2 [&>span]:line-clamp-1",
24
+ props.disabled && "web:cursor-not-allowed opacity-50",
25
+ className
26
+ )}
27
+ {...props}
28
+ >
29
+ <>{children}</>
30
+ <ChevronDown
31
+ size={16}
32
+ aria-hidden={true}
33
+ className="text-foreground opacity-50"
34
+ />
35
+ </SelectPrimitive.Trigger>
36
+ ));
37
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
38
+
39
+ /**
40
+ * Platform: WEB ONLY
41
+ */
42
+ const SelectScrollUpButton = ({
43
+ className,
44
+ ...props
45
+ }: SelectPrimitive.ScrollUpButtonProps) => {
46
+ if (Platform.OS !== "web") {
47
+ return null;
48
+ }
49
+ return (
50
+ <SelectPrimitive.ScrollUpButton
51
+ className={cn(
52
+ "flex web:cursor-default items-center justify-center py-1",
53
+ className
54
+ )}
55
+ {...props}
56
+ >
57
+ <ChevronUp size={14} className="text-foreground" />
58
+ </SelectPrimitive.ScrollUpButton>
59
+ );
60
+ };
61
+
62
+ /**
63
+ * Platform: WEB ONLY
64
+ */
65
+ const SelectScrollDownButton = ({
66
+ className,
67
+ ...props
68
+ }: SelectPrimitive.ScrollDownButtonProps) => {
69
+ if (Platform.OS !== "web") {
70
+ return null;
71
+ }
72
+ return (
73
+ <SelectPrimitive.ScrollDownButton
74
+ className={cn(
75
+ "flex web:cursor-default items-center justify-center py-1",
76
+ className
77
+ )}
78
+ {...props}
79
+ >
80
+ <ChevronDown size={14} className="text-foreground" />
81
+ </SelectPrimitive.ScrollDownButton>
82
+ );
83
+ };
84
+
85
+ const SelectContent = React.forwardRef<
86
+ SelectPrimitive.ContentRef,
87
+ SelectPrimitive.ContentProps & { portalHost?: string }
88
+ >(({ className, children, position = "popper", portalHost, ...props }, ref) => {
89
+ const { open } = SelectPrimitive.useRootContext();
90
+
91
+ return (
92
+ <SelectPrimitive.Portal hostName={portalHost}>
93
+ <SelectPrimitive.Overlay
94
+ style={Platform.OS !== "web" ? StyleSheet.absoluteFill : undefined}
95
+ >
96
+ <Animated.View className="z-50" entering={FadeIn} exiting={FadeOut}>
97
+ <SelectPrimitive.Content
98
+ ref={ref}
99
+ className={cn(
100
+ "relative z-50 max-h-96 min-w-[8rem] rounded-md border border-border bg-popover shadow-md shadow-foreground/10 py-2 px-1 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
101
+ position === "popper" &&
102
+ "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
103
+ open
104
+ ? "web:zoom-in-95 web:animate-in web:fade-in-0"
105
+ : "web:zoom-out-95 web:animate-out web:fade-out-0",
106
+ className
107
+ )}
108
+ position={position}
109
+ {...props}
110
+ >
111
+ <SelectScrollUpButton />
112
+ <SelectPrimitive.Viewport
113
+ className={cn(
114
+ "p-1",
115
+ position === "popper" &&
116
+ "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
117
+ )}
118
+ >
119
+ {children}
120
+ </SelectPrimitive.Viewport>
121
+ <SelectScrollDownButton />
122
+ </SelectPrimitive.Content>
123
+ </Animated.View>
124
+ </SelectPrimitive.Overlay>
125
+ </SelectPrimitive.Portal>
126
+ );
127
+ });
128
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
129
+
130
+ const SelectLabel = React.forwardRef<
131
+ SelectPrimitive.LabelRef,
132
+ SelectPrimitive.LabelProps
133
+ >(({ className, ...props }, ref) => (
134
+ <SelectPrimitive.Label
135
+ ref={ref}
136
+ className={cn(
137
+ "py-1.5 native:pb-2 pl-8 native:pl-10 pr-2 text-popover-foreground text-sm native:text-base font-semibold",
138
+ className
139
+ )}
140
+ {...props}
141
+ />
142
+ ));
143
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
144
+
145
+ const SelectItem = React.forwardRef<
146
+ SelectPrimitive.ItemRef,
147
+ SelectPrimitive.ItemProps
148
+ >(({ className, children, ...props }, ref) => (
149
+ <SelectPrimitive.Item
150
+ ref={ref}
151
+ className={cn(
152
+ "relative web:group flex flex-row w-full web:cursor-default web:select-none items-center rounded-sm py-1.5 native:py-2 pl-8 native:pl-10 pr-2 web:hover:bg-accent/50 active:bg-accent web:outline-none web:focus:bg-accent",
153
+ props.disabled && "web:pointer-events-none opacity-50",
154
+ className
155
+ )}
156
+ {...props}
157
+ >
158
+ <View className="absolute left-2 native:left-3.5 flex h-3.5 native:pt-px w-3.5 items-center justify-center">
159
+ <SelectPrimitive.ItemIndicator>
160
+ <Check size={16} strokeWidth={3} className="text-popover-foreground" />
161
+ </SelectPrimitive.ItemIndicator>
162
+ </View>
163
+ <SelectPrimitive.ItemText className="text-sm native:text-lg text-popover-foreground native:text-base web:group-focus:text-accent-foreground" />
164
+ </SelectPrimitive.Item>
165
+ ));
166
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
167
+
168
+ const SelectSeparator = React.forwardRef<
169
+ SelectPrimitive.SeparatorRef,
170
+ SelectPrimitive.SeparatorProps
171
+ >(({ className, ...props }, ref) => (
172
+ <SelectPrimitive.Separator
173
+ ref={ref}
174
+ className={cn("-mx-1 my-1 h-px bg-muted", className)}
175
+ {...props}
176
+ />
177
+ ));
178
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
179
+
180
+ export {
181
+ Select,
182
+ SelectContent,
183
+ SelectGroup,
184
+ SelectItem,
185
+ SelectLabel,
186
+ SelectScrollDownButton,
187
+ SelectScrollUpButton,
188
+ SelectSeparator,
189
+ SelectTrigger,
190
+ SelectValue,
191
+ type Option
192
+ };
@@ -0,0 +1,28 @@
1
+ import * as SeparatorPrimitive from "@rn-primitives/separator";
2
+ import * as React from "react";
3
+ import { cn } from "../utils";
4
+
5
+ const Separator = React.forwardRef<
6
+ SeparatorPrimitive.RootRef,
7
+ SeparatorPrimitive.RootProps
8
+ >(
9
+ (
10
+ { className, orientation = "horizontal", decorative = true, ...props },
11
+ ref
12
+ ) => (
13
+ <SeparatorPrimitive.Root
14
+ ref={ref}
15
+ decorative={decorative}
16
+ orientation={orientation}
17
+ className={cn(
18
+ "shrink-0 bg-border",
19
+ orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
20
+ className
21
+ )}
22
+ {...props}
23
+ />
24
+ )
25
+ );
26
+ Separator.displayName = SeparatorPrimitive.Root.displayName;
27
+
28
+ export { Separator };
@@ -0,0 +1,39 @@
1
+ import * as React from "react";
2
+ import Animated, {
3
+ useAnimatedStyle,
4
+ useSharedValue,
5
+ withRepeat,
6
+ withSequence,
7
+ withTiming
8
+ } from "react-native-reanimated";
9
+ import { cn } from "../utils";
10
+
11
+ const duration = 1000;
12
+
13
+ function Skeleton({
14
+ className,
15
+ ...props
16
+ }: Omit<React.ComponentPropsWithoutRef<typeof Animated.View>, "style">) {
17
+ const sv = useSharedValue(1);
18
+
19
+ React.useEffect(() => {
20
+ sv.value = withRepeat(
21
+ withSequence(withTiming(0.5, { duration }), withTiming(1, { duration })),
22
+ -1
23
+ );
24
+ }, []);
25
+
26
+ const style = useAnimatedStyle(() => ({
27
+ opacity: sv.value
28
+ }));
29
+
30
+ return (
31
+ <Animated.View
32
+ style={style}
33
+ className={cn("rounded-md bg-secondary dark:bg-muted", className)}
34
+ {...props}
35
+ />
36
+ );
37
+ }
38
+
39
+ export { Skeleton };
@@ -0,0 +1,102 @@
1
+ import * as SwitchPrimitives from "@rn-primitives/switch";
2
+ import * as React from "react";
3
+ import { Platform } from "react-native";
4
+ import Animated, {
5
+ interpolateColor,
6
+ useAnimatedStyle,
7
+ useDerivedValue,
8
+ withTiming
9
+ } from "react-native-reanimated";
10
+ import { useColorScheme } from "../hooks/useColorScheme";
11
+ import { cn } from "../utils";
12
+
13
+ const SwitchWeb = React.forwardRef<
14
+ SwitchPrimitives.RootRef,
15
+ SwitchPrimitives.RootProps
16
+ >(({ className, ...props }, ref) => (
17
+ <SwitchPrimitives.Root
18
+ className={cn(
19
+ "peer flex-row h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed",
20
+ props.checked ? "bg-primary" : "bg-input",
21
+ props.disabled && "opacity-50",
22
+ className
23
+ )}
24
+ {...props}
25
+ ref={ref}
26
+ >
27
+ <SwitchPrimitives.Thumb
28
+ className={cn(
29
+ "pointer-events-none block h-5 w-5 rounded-full bg-background shadow-md shadow-foreground/5 ring-0 transition-transform",
30
+ props.checked ? "translate-x-5" : "translate-x-0"
31
+ )}
32
+ />
33
+ </SwitchPrimitives.Root>
34
+ ));
35
+
36
+ SwitchWeb.displayName = "SwitchWeb";
37
+
38
+ const RGB_COLORS = {
39
+ light: {
40
+ primary: "rgb(24, 24, 27)",
41
+ input: "rgb(228, 228, 231)"
42
+ },
43
+ dark: {
44
+ primary: "rgb(250, 250, 250)",
45
+ input: "rgb(39, 39, 42)"
46
+ }
47
+ } as const;
48
+
49
+ const SwitchNative = React.forwardRef<
50
+ SwitchPrimitives.RootRef,
51
+ SwitchPrimitives.RootProps
52
+ >(({ className, ...props }, ref) => {
53
+ const { colorScheme } = useColorScheme();
54
+ const translateX = useDerivedValue(() => (props.checked ? 18 : 0));
55
+ const animatedRootStyle = useAnimatedStyle(() => {
56
+ return {
57
+ backgroundColor: interpolateColor(
58
+ translateX.value,
59
+ [0, 18],
60
+ [RGB_COLORS[colorScheme].input, RGB_COLORS[colorScheme].primary]
61
+ )
62
+ };
63
+ });
64
+ const animatedThumbStyle = useAnimatedStyle(() => ({
65
+ transform: [{ translateX: withTiming(translateX.value, { duration: 200 }) }]
66
+ }));
67
+ return (
68
+ <Animated.View
69
+ style={animatedRootStyle}
70
+ className={cn(
71
+ "h-8 w-[46px] rounded-full",
72
+ props.disabled && "opacity-50"
73
+ )}
74
+ >
75
+ <SwitchPrimitives.Root
76
+ className={cn(
77
+ "flex-row h-8 w-[46px] shrink-0 items-center rounded-full border-2 border-transparent",
78
+ props.checked ? "bg-primary" : "bg-input",
79
+ className
80
+ )}
81
+ {...props}
82
+ ref={ref}
83
+ >
84
+ <Animated.View style={animatedThumbStyle}>
85
+ <SwitchPrimitives.Thumb
86
+ className={
87
+ "h-7 w-7 rounded-full bg-background shadow-md shadow-foreground/25 ring-0"
88
+ }
89
+ />
90
+ </Animated.View>
91
+ </SwitchPrimitives.Root>
92
+ </Animated.View>
93
+ );
94
+ });
95
+ SwitchNative.displayName = "SwitchNative";
96
+
97
+ const Switch = Platform.select({
98
+ web: SwitchWeb,
99
+ default: SwitchNative
100
+ });
101
+
102
+ export { Switch };
@@ -0,0 +1,107 @@
1
+ import * as TablePrimitive from "@rn-primitives/table";
2
+ import * as React from "react";
3
+ import { cn } from "../utils";
4
+ import { TextClassContext } from "./text";
5
+
6
+ const Table = React.forwardRef<
7
+ TablePrimitive.RootRef,
8
+ TablePrimitive.RootProps
9
+ >(({ className, ...props }, ref) => (
10
+ <TablePrimitive.Root
11
+ ref={ref}
12
+ className={cn("w-full caption-bottom text-sm", className)}
13
+ {...props}
14
+ />
15
+ ));
16
+ Table.displayName = "Table";
17
+
18
+ const TableHeader = React.forwardRef<
19
+ TablePrimitive.HeaderRef,
20
+ TablePrimitive.HeaderProps
21
+ >(({ className, ...props }, ref) => (
22
+ <TablePrimitive.Header
23
+ ref={ref}
24
+ className={cn("border-border [&_tr]:border-b", className)}
25
+ {...props}
26
+ />
27
+ ));
28
+ TableHeader.displayName = "TableHeader";
29
+
30
+ const TableBody = React.forwardRef<
31
+ TablePrimitive.BodyRef,
32
+ TablePrimitive.BodyProps
33
+ >(({ className, style, ...props }, ref) => (
34
+ <TablePrimitive.Body
35
+ ref={ref}
36
+ className={cn("flex-1 border-border [&_tr:last-child]:border-0", className)}
37
+ style={[{ minHeight: 2 }, style]}
38
+ {...props}
39
+ />
40
+ ));
41
+ TableBody.displayName = "TableBody";
42
+
43
+ const TableFooter = React.forwardRef<
44
+ TablePrimitive.FooterRef,
45
+ TablePrimitive.FooterProps
46
+ >(({ className, ...props }, ref) => (
47
+ <TablePrimitive.Footer
48
+ ref={ref}
49
+ className={cn("bg-muted/50 font-medium [&>tr]:last:border-b-0", className)}
50
+ {...props}
51
+ />
52
+ ));
53
+ TableFooter.displayName = "TableFooter";
54
+
55
+ const TableRow = React.forwardRef<
56
+ TablePrimitive.RowRef,
57
+ TablePrimitive.RowProps
58
+ >(({ className, ...props }, ref) => (
59
+ <TablePrimitive.Row
60
+ ref={ref}
61
+ className={cn(
62
+ "flex-row border-border border-b web:transition-colors web:hover:bg-muted/50 web:data-[state=selected]:bg-muted",
63
+ className
64
+ )}
65
+ {...props}
66
+ />
67
+ ));
68
+ TableRow.displayName = "TableRow";
69
+
70
+ const TableHead = React.forwardRef<
71
+ TablePrimitive.HeadRef,
72
+ TablePrimitive.HeadProps
73
+ >(({ className, ...props }, ref) => (
74
+ <TextClassContext.Provider value="text-muted-foreground">
75
+ <TablePrimitive.Head
76
+ ref={ref}
77
+ className={cn(
78
+ "h-12 px-4 text-left justify-center font-medium [&:has([role=checkbox])]:pr-0",
79
+ className
80
+ )}
81
+ {...props}
82
+ />
83
+ </TextClassContext.Provider>
84
+ ));
85
+ TableHead.displayName = "TableHead";
86
+
87
+ const TableCell = React.forwardRef<
88
+ TablePrimitive.CellRef,
89
+ TablePrimitive.CellProps
90
+ >(({ className, ...props }, ref) => (
91
+ <TablePrimitive.Cell
92
+ ref={ref}
93
+ className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
94
+ {...props}
95
+ />
96
+ ));
97
+ TableCell.displayName = "TableCell";
98
+
99
+ export {
100
+ Table,
101
+ TableBody,
102
+ TableCell,
103
+ TableFooter,
104
+ TableHead,
105
+ TableHeader,
106
+ TableRow
107
+ };
@@ -0,0 +1,66 @@
1
+ import * as TabsPrimitive from "@rn-primitives/tabs";
2
+ import * as React from "react";
3
+ import { cn } from "../utils";
4
+ import { TextClassContext } from "./text";
5
+
6
+ const Tabs = TabsPrimitive.Root;
7
+
8
+ const TabsList = React.forwardRef<
9
+ TabsPrimitive.ListRef,
10
+ TabsPrimitive.ListProps
11
+ >(({ className, ...props }, ref) => (
12
+ <TabsPrimitive.List
13
+ ref={ref}
14
+ className={cn(
15
+ "web:inline-flex h-10 native:h-12 items-center justify-center rounded-md bg-muted p-1 native:px-1.5",
16
+ className
17
+ )}
18
+ {...props}
19
+ />
20
+ ));
21
+ TabsList.displayName = TabsPrimitive.List.displayName;
22
+
23
+ const TabsTrigger = React.forwardRef<
24
+ TabsPrimitive.TriggerRef,
25
+ TabsPrimitive.TriggerProps
26
+ >(({ className, ...props }, ref) => {
27
+ const { value } = TabsPrimitive.useRootContext();
28
+ return (
29
+ <TextClassContext.Provider
30
+ value={cn(
31
+ "text-sm native:text-base font-medium text-muted-foreground web:transition-all",
32
+ value === props.value && "text-foreground"
33
+ )}
34
+ >
35
+ <TabsPrimitive.Trigger
36
+ ref={ref}
37
+ className={cn(
38
+ "inline-flex items-center justify-center shadow-none web:whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium web:ring-offset-background web:transition-all web:focus-visible:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring web:focus-visible:ring-offset-2",
39
+ props.disabled && "web:pointer-events-none opacity-50",
40
+ props.value === value &&
41
+ "bg-background shadow-lg shadow-foreground/10",
42
+ className
43
+ )}
44
+ {...props}
45
+ />
46
+ </TextClassContext.Provider>
47
+ );
48
+ });
49
+ TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
50
+
51
+ const TabsContent = React.forwardRef<
52
+ TabsPrimitive.ContentRef,
53
+ TabsPrimitive.ContentProps
54
+ >(({ className, ...props }, ref) => (
55
+ <TabsPrimitive.Content
56
+ ref={ref}
57
+ className={cn(
58
+ "web:ring-offset-background web:focus-visible:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring web:focus-visible:ring-offset-2",
59
+ className
60
+ )}
61
+ {...props}
62
+ />
63
+ ));
64
+ TabsContent.displayName = TabsPrimitive.Content.displayName;
65
+
66
+ export { Tabs, TabsContent, TabsList, TabsTrigger };
@@ -0,0 +1,28 @@
1
+ import * as Slot from "@rn-primitives/slot";
2
+ import type { SlottableTextProps, TextRef } from "@rn-primitives/types";
3
+ import * as React from "react";
4
+ import { Text as RNText } from "react-native";
5
+ import { cn } from "../utils";
6
+
7
+ const TextClassContext = React.createContext<string | undefined>(undefined);
8
+
9
+ const Text = React.forwardRef<TextRef, SlottableTextProps>(
10
+ ({ className, asChild = false, ...props }, ref) => {
11
+ const textClass = React.useContext(TextClassContext);
12
+ const Component = asChild ? Slot.Text : RNText;
13
+ return (
14
+ <Component
15
+ className={cn(
16
+ "text-base text-foreground web:select-text",
17
+ textClass,
18
+ className
19
+ )}
20
+ ref={ref}
21
+ {...props}
22
+ />
23
+ );
24
+ }
25
+ );
26
+ Text.displayName = "Text";
27
+
28
+ export { Text, TextClassContext };
@@ -0,0 +1,39 @@
1
+ import * as React from "react";
2
+ import { TextInput, type TextInputProps } from "react-native";
3
+ import { cn } from "../utils";
4
+
5
+ const Textarea = React.forwardRef<
6
+ React.ElementRef<typeof TextInput>,
7
+ TextInputProps
8
+ >(
9
+ (
10
+ {
11
+ className,
12
+ multiline = true,
13
+ numberOfLines = 4,
14
+ placeholderClassName,
15
+ ...props
16
+ },
17
+ ref
18
+ ) => {
19
+ return (
20
+ <TextInput
21
+ ref={ref}
22
+ className={cn(
23
+ "web:flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-base lg:text-sm native:text-lg native:leading-[1.25] text-foreground web:ring-offset-background placeholder:text-muted-foreground web:focus-visible:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring web:focus-visible:ring-offset-2",
24
+ props.editable === false && "opacity-50 web:cursor-not-allowed",
25
+ className
26
+ )}
27
+ placeholderClassName={cn("text-muted-foreground", placeholderClassName)}
28
+ multiline={multiline}
29
+ numberOfLines={numberOfLines}
30
+ textAlignVertical="top"
31
+ {...props}
32
+ />
33
+ );
34
+ }
35
+ );
36
+
37
+ Textarea.displayName = "Textarea";
38
+
39
+ export { Textarea };
@@ -0,0 +1,89 @@
1
+ import * as ToggleGroupPrimitive from "@rn-primitives/toggle-group";
2
+ import type { VariantProps } from "class-variance-authority";
3
+ import type { LucideIcon } from "lucide-react-native";
4
+ import * as React from "react";
5
+ import { cn } from "../utils";
6
+ import { TextClassContext } from "./text";
7
+ import { toggleTextVariants, toggleVariants } from "./toggle";
8
+
9
+ const ToggleGroupContext = React.createContext<VariantProps<
10
+ typeof toggleVariants
11
+ > | null>(null);
12
+
13
+ const ToggleGroup = React.forwardRef<
14
+ ToggleGroupPrimitive.RootRef,
15
+ ToggleGroupPrimitive.RootProps & VariantProps<typeof toggleVariants>
16
+ >(({ className, variant, size, children, ...props }, ref) => (
17
+ <ToggleGroupPrimitive.Root
18
+ ref={ref}
19
+ className={cn("flex flex-row items-center justify-center gap-1", className)}
20
+ {...props}
21
+ >
22
+ <ToggleGroupContext.Provider value={{ variant, size }}>
23
+ {children}
24
+ </ToggleGroupContext.Provider>
25
+ </ToggleGroupPrimitive.Root>
26
+ ));
27
+
28
+ ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
29
+
30
+ function useToggleGroupContext() {
31
+ const context = React.useContext(ToggleGroupContext);
32
+ if (context === null) {
33
+ throw new Error(
34
+ "ToggleGroup compound components cannot be rendered outside the ToggleGroup component"
35
+ );
36
+ }
37
+ return context;
38
+ }
39
+
40
+ const ToggleGroupItem = React.forwardRef<
41
+ ToggleGroupPrimitive.ItemRef,
42
+ ToggleGroupPrimitive.ItemProps & VariantProps<typeof toggleVariants>
43
+ >(({ className, children, variant, size, ...props }, ref) => {
44
+ const context = useToggleGroupContext();
45
+ const { value } = ToggleGroupPrimitive.useRootContext();
46
+
47
+ return (
48
+ <TextClassContext.Provider
49
+ value={cn(
50
+ toggleTextVariants({ variant, size }),
51
+ ToggleGroupPrimitive.utils.getIsSelected(value, props.value)
52
+ ? "text-accent-foreground"
53
+ : "web:group-hover:text-muted-foreground"
54
+ )}
55
+ >
56
+ <ToggleGroupPrimitive.Item
57
+ ref={ref}
58
+ className={cn(
59
+ toggleVariants({
60
+ variant: context.variant || variant,
61
+ size: context.size || size
62
+ }),
63
+ props.disabled && "web:pointer-events-none opacity-50",
64
+ ToggleGroupPrimitive.utils.getIsSelected(value, props.value) &&
65
+ "bg-accent",
66
+ className
67
+ )}
68
+ {...props}
69
+ >
70
+ {children}
71
+ </ToggleGroupPrimitive.Item>
72
+ </TextClassContext.Provider>
73
+ );
74
+ });
75
+
76
+ ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
77
+
78
+ function ToggleGroupIcon({
79
+ className,
80
+ icon: Icon,
81
+ ...props
82
+ }: React.ComponentPropsWithoutRef<LucideIcon> & {
83
+ icon: LucideIcon;
84
+ }) {
85
+ const textClass = React.useContext(TextClassContext);
86
+ return <Icon className={cn(textClass, className)} {...props} />;
87
+ }
88
+
89
+ export { ToggleGroup, ToggleGroupIcon, ToggleGroupItem };