@gv-tech/ui-native 2.6.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 (55) hide show
  1. package/package.json +80 -0
  2. package/src/accordion.tsx +93 -0
  3. package/src/alert-dialog.tsx +123 -0
  4. package/src/alert.tsx +50 -0
  5. package/src/aspect-ratio.tsx +9 -0
  6. package/src/avatar.tsx +38 -0
  7. package/src/badge.tsx +51 -0
  8. package/src/breadcrumb.tsx +9 -0
  9. package/src/button.tsx +75 -0
  10. package/src/calendar.tsx +9 -0
  11. package/src/card.tsx +56 -0
  12. package/src/carousel.tsx +9 -0
  13. package/src/chart.tsx +9 -0
  14. package/src/checkbox.tsx +31 -0
  15. package/src/collapsible.tsx +15 -0
  16. package/src/command.tsx +9 -0
  17. package/src/context-menu.tsx +9 -0
  18. package/src/dialog.tsx +121 -0
  19. package/src/drawer.tsx +9 -0
  20. package/src/dropdown-menu.tsx +9 -0
  21. package/src/form.tsx +9 -0
  22. package/src/hover-card.tsx +9 -0
  23. package/src/index.ts +209 -0
  24. package/src/input.tsx +27 -0
  25. package/src/label.tsx +29 -0
  26. package/src/lib/render-native.tsx +17 -0
  27. package/src/lib/utils.ts +6 -0
  28. package/src/menubar.tsx +9 -0
  29. package/src/nativewind-env.d.ts +1 -0
  30. package/src/navigation-menu.tsx +9 -0
  31. package/src/pagination.tsx +9 -0
  32. package/src/popover.tsx +9 -0
  33. package/src/progress.tsx +9 -0
  34. package/src/radio-group.tsx +42 -0
  35. package/src/resizable.tsx +25 -0
  36. package/src/scroll-area.tsx +9 -0
  37. package/src/search.tsx +17 -0
  38. package/src/select.tsx +229 -0
  39. package/src/separator.tsx +20 -0
  40. package/src/sheet.tsx +127 -0
  41. package/src/skeleton.tsx +31 -0
  42. package/src/slider.tsx +9 -0
  43. package/src/sonner.tsx +9 -0
  44. package/src/switch.tsx +34 -0
  45. package/src/table.tsx +73 -0
  46. package/src/tabs.tsx +74 -0
  47. package/src/text.tsx +43 -0
  48. package/src/textarea.tsx +29 -0
  49. package/src/theme-provider.tsx +6 -0
  50. package/src/theme-toggle.tsx +11 -0
  51. package/src/toast.tsx +88 -0
  52. package/src/toaster.tsx +9 -0
  53. package/src/toggle-group.tsx +78 -0
  54. package/src/toggle.tsx +35 -0
  55. package/src/tooltip.tsx +44 -0
package/src/select.tsx ADDED
@@ -0,0 +1,229 @@
1
+ import {
2
+ SelectBaseProps,
3
+ SelectContentBaseProps,
4
+ SelectGroupBaseProps,
5
+ SelectItemBaseProps,
6
+ SelectLabelBaseProps,
7
+ SelectScrollDownButtonBaseProps,
8
+ SelectScrollUpButtonBaseProps,
9
+ SelectSeparatorBaseProps,
10
+ SelectTriggerBaseProps,
11
+ SelectValueBaseProps,
12
+ } from '@gv-tech/ui-core';
13
+ import * as SelectPrimitive from '@rn-primitives/select';
14
+ import { Check, ChevronDown, ChevronUp } from 'lucide-react-native';
15
+ import * as React from 'react';
16
+ import { Platform, StyleSheet, View, type ViewStyle } from 'react-native';
17
+ import Animated from 'react-native-reanimated';
18
+
19
+ import { cn } from './lib/utils';
20
+
21
+ export interface SelectProps
22
+ extends
23
+ Omit<
24
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root>,
25
+ 'value' | 'defaultValue' | 'onValueChange' | 'disabled'
26
+ >,
27
+ SelectBaseProps {}
28
+
29
+ const Select = SelectPrimitive.Root;
30
+
31
+ export interface SelectGroupProps
32
+ extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Group>, SelectGroupBaseProps {}
33
+
34
+ const SelectGroup = SelectPrimitive.Group;
35
+
36
+ export interface SelectValueProps
37
+ extends Omit<React.ComponentPropsWithoutRef<typeof SelectPrimitive.Value>, 'placeholder'>, SelectValueBaseProps {}
38
+
39
+ const SelectValue = SelectPrimitive.Value;
40
+
41
+ export interface SelectTriggerProps
42
+ extends
43
+ Omit<React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>, 'children' | 'disabled'>,
44
+ SelectTriggerBaseProps {}
45
+
46
+ const SelectTrigger = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Trigger>, SelectTriggerProps>(
47
+ ({ className, children, ...props }, ref) => (
48
+ <SelectPrimitive.Trigger
49
+ ref={ref}
50
+ className={cn(
51
+ 'flex flex-row h-10 native:h-12 items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm text-muted-foreground web:ring-offset-background web:focus:outline-none web:focus:ring-2 web:focus:ring-ring web:focus:ring-offset-2 [&>span]:line-clamp-1',
52
+ props.disabled && 'web:cursor-not-allowed opacity-50',
53
+ className,
54
+ )}
55
+ {...props}
56
+ >
57
+ <>{children}</>
58
+ <ChevronDown size={16} aria-hidden={true} className="text-foreground opacity-50" />
59
+ </SelectPrimitive.Trigger>
60
+ ),
61
+ );
62
+ SelectTrigger.displayName = SelectPrimitive.Trigger?.displayName || 'SelectTrigger';
63
+
64
+ export interface SelectScrollUpButtonProps
65
+ extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>, SelectScrollUpButtonBaseProps {}
66
+
67
+ const SelectScrollUpButton = React.forwardRef<
68
+ React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
69
+ SelectScrollUpButtonProps
70
+ >(({ className, ...props }, ref) => (
71
+ <SelectPrimitive.ScrollUpButton
72
+ // @ts-expect-error TODO: fix type
73
+ ref={ref}
74
+ className={cn('flex cursor-default items-center justify-center py-1', className)}
75
+ {...props}
76
+ >
77
+ <ChevronUp size={14} className="text-foreground" />
78
+ </SelectPrimitive.ScrollUpButton>
79
+ ));
80
+ SelectScrollUpButton.displayName =
81
+ ((SelectPrimitive.ScrollUpButton as unknown as Record<string, unknown>)?.displayName as string | undefined) ||
82
+ 'SelectScrollUpButton';
83
+
84
+ export interface SelectScrollDownButtonProps
85
+ extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>, SelectScrollDownButtonBaseProps {}
86
+
87
+ const SelectScrollDownButton = React.forwardRef<
88
+ React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
89
+ SelectScrollDownButtonProps
90
+ >(({ className, ...props }, ref) => (
91
+ <SelectPrimitive.ScrollDownButton
92
+ // @ts-expect-error TODO: fix type
93
+ ref={ref}
94
+ className={cn('flex cursor-default items-center justify-center py-1', className)}
95
+ {...props}
96
+ >
97
+ <ChevronDown size={14} className="text-foreground" />
98
+ </SelectPrimitive.ScrollDownButton>
99
+ ));
100
+
101
+ SelectScrollDownButton.displayName =
102
+ ((SelectPrimitive.ScrollDownButton as unknown as Record<string, unknown>)?.displayName as string | undefined) ||
103
+ 'SelectScrollDownButton';
104
+
105
+ export interface SelectContentProps
106
+ extends Omit<React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>, 'position'>, SelectContentBaseProps {
107
+ portalHost?: string;
108
+ overlayClassName?: string;
109
+ overlayStyle?: ViewStyle;
110
+ }
111
+
112
+ const SelectContent = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Content>, SelectContentProps>(
113
+ ({ className, children, position = 'popper', portalHost, overlayClassName, overlayStyle, ...props }, ref) => {
114
+ const { open } = SelectPrimitive.useRootContext();
115
+
116
+ return (
117
+ <SelectPrimitive.Portal hostName={portalHost}>
118
+ <SelectPrimitive.Overlay style={Platform.OS !== 'web' ? StyleSheet.absoluteFill : undefined} asChild>
119
+ <Animated.View className={overlayClassName} style={overlayStyle} />
120
+ </SelectPrimitive.Overlay>
121
+ <SelectPrimitive.Content
122
+ ref={ref}
123
+ className={cn(
124
+ 'relative z-50 max-h-96 min-w-[8rem] rounded-md border border-border bg-popover shadow-md 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',
125
+ position === 'popper' &&
126
+ 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
127
+ open ? 'web:zoom-in-95 web:animate-in web:fade-in-0' : 'web:zoom-out-95 web:animate-out web:fade-out-0',
128
+ className,
129
+ )}
130
+ position={position}
131
+ {...props}
132
+ >
133
+ <SelectScrollUpButton />
134
+ <SelectPrimitive.Viewport
135
+ className={cn(
136
+ 'p-1',
137
+ position === 'popper' &&
138
+ 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]',
139
+ )}
140
+ >
141
+ {children}
142
+ </SelectPrimitive.Viewport>
143
+ <SelectScrollDownButton />
144
+ </SelectPrimitive.Content>
145
+ </SelectPrimitive.Portal>
146
+ );
147
+ },
148
+ );
149
+ SelectContent.displayName = SelectPrimitive.Content?.displayName || 'SelectContent';
150
+
151
+ export interface SelectLabelProps
152
+ extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>, SelectLabelBaseProps {}
153
+
154
+ const SelectLabel = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Label>, SelectLabelProps>(
155
+ ({ className, ...props }, ref) => (
156
+ <SelectPrimitive.Label
157
+ ref={ref}
158
+ className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold text-popover-foreground', className)}
159
+ {...props}
160
+ />
161
+ ),
162
+ );
163
+ SelectLabel.displayName = SelectPrimitive.Label?.displayName || 'SelectLabel';
164
+
165
+ export interface SelectItemProps
166
+ extends
167
+ Omit<React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>, 'children' | 'disabled' | 'label'>,
168
+ SelectItemBaseProps {
169
+ label?: string;
170
+ }
171
+
172
+ const SelectItem = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Item>, SelectItemProps>(
173
+ ({ className, children, label, ...props }, ref) => {
174
+ const itemLabel = label || (typeof children === 'string' ? children : '');
175
+ return (
176
+ <SelectPrimitive.Item
177
+ ref={ref}
178
+ label={itemLabel}
179
+ className={cn(
180
+ 'relative flex w-full cursor-default select-none flex-row items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none web:hover:bg-accent/50 web:focus:bg-accent web:focus:text-accent-foreground web:hover:text-accent-foreground data-[disabled]:opacity-50',
181
+ props.disabled && 'web:pointer-events-none',
182
+ className,
183
+ )}
184
+ {...props}
185
+ >
186
+ <View
187
+ className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"
188
+ {...({} as Record<string, unknown>)}
189
+ >
190
+ <SelectPrimitive.ItemIndicator>
191
+ <Check size={14} strokeWidth={3} className="text-popover-foreground" {...({} as Record<string, unknown>)} />
192
+ </SelectPrimitive.ItemIndicator>
193
+ </View>
194
+ {/* @ts-expect-error TODO: fix type */}
195
+ <SelectPrimitive.ItemText className="text-sm text-popover-foreground native:text-base">
196
+ {children}
197
+ </SelectPrimitive.ItemText>
198
+ </SelectPrimitive.Item>
199
+ );
200
+ },
201
+ );
202
+ SelectItem.displayName = SelectPrimitive.Item?.displayName || 'SelectItem';
203
+
204
+ export interface SelectSeparatorProps
205
+ extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>, SelectSeparatorBaseProps {}
206
+
207
+ const SelectSeparator = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Separator>, SelectSeparatorProps>(
208
+ ({ className, ...props }, ref) => (
209
+ <SelectPrimitive.Separator
210
+ ref={ref}
211
+ className={cn('-mx-1 my-1 h-px bg-muted', className)}
212
+ {...(props as Record<string, unknown>)}
213
+ />
214
+ ),
215
+ );
216
+ SelectSeparator.displayName = SelectPrimitive.Separator?.displayName || 'SelectSeparator';
217
+
218
+ export {
219
+ Select,
220
+ SelectContent,
221
+ SelectGroup,
222
+ SelectItem,
223
+ SelectLabel,
224
+ SelectScrollDownButton,
225
+ SelectScrollUpButton,
226
+ SelectSeparator,
227
+ SelectTrigger,
228
+ SelectValue,
229
+ };
@@ -0,0 +1,20 @@
1
+ import * as SeparatorPrimitive from '@rn-primitives/separator';
2
+ import * as React from 'react';
3
+
4
+ import { cn } from './lib/utils';
5
+
6
+ const Separator = React.forwardRef<
7
+ React.ElementRef<typeof SeparatorPrimitive.Root>,
8
+ React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
9
+ >(({ className, orientation = 'horizontal', decorative = true, ...props }, ref) => (
10
+ <SeparatorPrimitive.Root
11
+ ref={ref}
12
+ decorative={decorative}
13
+ orientation={orientation}
14
+ className={cn('shrink-0 bg-border', orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]', className)}
15
+ {...props}
16
+ />
17
+ ));
18
+ Separator.displayName = SeparatorPrimitive.Root?.displayName || 'Separator';
19
+
20
+ export { Separator };
package/src/sheet.tsx ADDED
@@ -0,0 +1,127 @@
1
+ import * as DialogPrimitive from '@rn-primitives/dialog';
2
+ import { X } from 'lucide-react-native';
3
+ import * as React from 'react';
4
+ import { Platform, StyleSheet, View, type ViewStyle } from 'react-native';
5
+ import Animated, { FadeIn, FadeOut, SlideInRight, SlideOutRight } from 'react-native-reanimated';
6
+
7
+ import { type DialogContentProps } from './dialog';
8
+ import { cn } from './lib/utils';
9
+ import { Text } from './text';
10
+
11
+ const Sheet = DialogPrimitive.Root;
12
+
13
+ const SheetTrigger = DialogPrimitive.Trigger;
14
+
15
+ const SheetClose = DialogPrimitive.Close;
16
+
17
+ const SheetPortal = DialogPrimitive.Portal;
18
+
19
+ const SheetOverlay = React.forwardRef<
20
+ React.ElementRef<typeof DialogPrimitive.Overlay>,
21
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
22
+ >(({ className, ...props }, ref) => {
23
+ return (
24
+ <DialogPrimitive.Overlay
25
+ style={Platform.OS !== 'web' ? StyleSheet.absoluteFill : undefined}
26
+ asChild
27
+ ref={ref}
28
+ {...props}
29
+ >
30
+ <Animated.View
31
+ entering={FadeIn.duration(150)}
32
+ exiting={FadeOut.duration(150)}
33
+ className={cn('absolute inset-0 z-50 bg-black/80 web:cursor-default', className)}
34
+ />
35
+ </DialogPrimitive.Overlay>
36
+ );
37
+ });
38
+ SheetOverlay.displayName = DialogPrimitive.Overlay?.displayName || 'SheetOverlay';
39
+
40
+ const SheetContent = React.forwardRef<
41
+ React.ElementRef<typeof DialogPrimitive.Content>,
42
+ DialogContentProps & {
43
+ side?: 'top' | 'right' | 'bottom' | 'left';
44
+ overlayClassName?: string;
45
+ overlayStyle?: ViewStyle;
46
+ }
47
+ >(({ className, children, side = 'right', overlayClassName, overlayStyle, ...props }, ref) => {
48
+ const isWeb = Platform.OS === 'web';
49
+ // TODO: Add support for other sides
50
+ const entering = isWeb ? undefined : SlideInRight;
51
+ const exiting = isWeb ? undefined : SlideOutRight;
52
+
53
+ return (
54
+ <SheetPortal>
55
+ <SheetOverlay className={overlayClassName} style={overlayStyle} />
56
+ <DialogPrimitive.Content ref={ref} asChild {...props}>
57
+ <Animated.View
58
+ entering={entering}
59
+ exiting={exiting}
60
+ className={cn(
61
+ 'absolute z-50 h-full w-3/4 gap-4 bg-background p-6 shadow-lg web:cursor-default web:duration-200 web:ease-in-out',
62
+ side === 'right' &&
63
+ 'right-0 top-0 border-l border-border data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right',
64
+ side === 'left' &&
65
+ 'left-0 top-0 border-r border-border data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left',
66
+ side === 'top' &&
67
+ 'top-0 w-full border-b border-border data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
68
+ side === 'bottom' &&
69
+ 'bottom-0 w-full border-t border-border data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',
70
+ className,
71
+ )}
72
+ >
73
+ {children}
74
+ <DialogPrimitive.Close
75
+ className={cn(
76
+ 'absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary',
77
+ 'web:absolute web:right-4 web:top-4',
78
+ )}
79
+ >
80
+ <X size={24} className="text-muted-foreground" />
81
+ <Text className="sr-only">Close</Text>
82
+ </DialogPrimitive.Close>
83
+ </Animated.View>
84
+ </DialogPrimitive.Content>
85
+ </SheetPortal>
86
+ );
87
+ });
88
+ SheetContent.displayName = DialogPrimitive.Content?.displayName || 'SheetContent';
89
+
90
+ const SheetHeader = ({ className, ...props }: React.ComponentPropsWithoutRef<typeof View>) => (
91
+ <View className={cn('flex flex-col space-y-2 text-center sm:text-left', className)} {...props} />
92
+ );
93
+ SheetHeader.displayName = 'SheetHeader';
94
+
95
+ const SheetFooter = ({ className, ...props }: React.ComponentPropsWithoutRef<typeof View>) => (
96
+ <View className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)} {...props} />
97
+ );
98
+ SheetFooter.displayName = 'SheetFooter';
99
+
100
+ const SheetTitle = React.forwardRef<
101
+ React.ElementRef<typeof DialogPrimitive.Title>,
102
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
103
+ >(({ className, ...props }, ref) => (
104
+ <DialogPrimitive.Title ref={ref} className={cn('text-lg font-semibold text-foreground', className)} {...props} />
105
+ ));
106
+ SheetTitle.displayName = DialogPrimitive.Title?.displayName || 'SheetTitle';
107
+
108
+ const SheetDescription = React.forwardRef<
109
+ React.ElementRef<typeof DialogPrimitive.Description>,
110
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
111
+ >(({ className, ...props }, ref) => (
112
+ <DialogPrimitive.Description ref={ref} className={cn('text-sm text-muted-foreground', className)} {...props} />
113
+ ));
114
+ SheetDescription.displayName = DialogPrimitive.Description?.displayName || 'SheetDescription';
115
+
116
+ export {
117
+ Sheet,
118
+ SheetClose,
119
+ SheetContent,
120
+ SheetDescription,
121
+ SheetFooter,
122
+ SheetHeader,
123
+ SheetOverlay,
124
+ SheetPortal,
125
+ SheetTitle,
126
+ SheetTrigger,
127
+ };
@@ -0,0 +1,31 @@
1
+ import * as React from 'react';
2
+ import { View } from 'react-native';
3
+ import Animated, {
4
+ useAnimatedStyle,
5
+ useSharedValue,
6
+ withRepeat,
7
+ withSequence,
8
+ withTiming,
9
+ } from 'react-native-reanimated';
10
+
11
+ import { cn } from './lib/utils';
12
+
13
+ function Skeleton({ className, ...props }: React.ComponentPropsWithoutRef<typeof View>) {
14
+ const opacity = useSharedValue(0.5);
15
+
16
+ React.useEffect(() => {
17
+ opacity.value = withRepeat(
18
+ withSequence(withTiming(0.2, { duration: 500 }), withTiming(0.5, { duration: 500 })),
19
+ -1,
20
+ true,
21
+ );
22
+ }, []);
23
+
24
+ const animatedStyle = useAnimatedStyle(() => ({
25
+ opacity: opacity.value,
26
+ }));
27
+
28
+ return <Animated.View className={cn('rounded-md bg-muted', className)} style={animatedStyle} {...props} />;
29
+ }
30
+
31
+ export { Skeleton };
package/src/slider.tsx ADDED
@@ -0,0 +1,9 @@
1
+ import { Text, View } from 'react-native';
2
+
3
+ export const Slider = () => {
4
+ return (
5
+ <View>
6
+ <Text>slider is not yet implemented for React Native</Text>
7
+ </View>
8
+ );
9
+ };
package/src/sonner.tsx ADDED
@@ -0,0 +1,9 @@
1
+ import { Text, View } from 'react-native';
2
+
3
+ export const Toaster = () => {
4
+ return (
5
+ <View>
6
+ <Text>Toaster (Sonner) is not yet implemented for React Native</Text>
7
+ </View>
8
+ );
9
+ };
package/src/switch.tsx ADDED
@@ -0,0 +1,34 @@
1
+ import { SwitchBaseProps } from '@gv-tech/ui-core';
2
+ import * as SwitchPrimitive from '@rn-primitives/switch';
3
+ import * as React from 'react';
4
+
5
+ import { cn } from './lib/utils';
6
+
7
+ export interface SwitchProps
8
+ extends
9
+ Omit<React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root>, 'checked' | 'onCheckedChange'>,
10
+ SwitchBaseProps {}
11
+
12
+ const Switch = React.forwardRef<React.ElementRef<typeof SwitchPrimitive.Root>, SwitchProps>(
13
+ ({ className, checked, onCheckedChange, ...props }, ref) => (
14
+ <SwitchPrimitive.Root
15
+ className={cn(
16
+ 'peer inline-flex h-6 w-11 shrink-0 cursor-pointer flex-row 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 disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',
17
+ className,
18
+ )}
19
+ {...props}
20
+ checked={checked ?? false}
21
+ onCheckedChange={onCheckedChange || (() => {})}
22
+ ref={ref}
23
+ >
24
+ <SwitchPrimitive.Thumb
25
+ className={cn(
26
+ 'pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0',
27
+ )}
28
+ />
29
+ </SwitchPrimitive.Root>
30
+ ),
31
+ );
32
+ Switch.displayName = SwitchPrimitive.Root?.displayName || 'Switch';
33
+
34
+ export { Switch };
package/src/table.tsx ADDED
@@ -0,0 +1,73 @@
1
+ import * as React from 'react';
2
+ import { View } from 'react-native';
3
+
4
+ import { cn } from './lib/utils';
5
+ import { Text } from './text';
6
+
7
+ const Table = React.forwardRef<React.ElementRef<typeof View>, React.ComponentPropsWithoutRef<typeof View>>(
8
+ ({ className, ...props }, ref) => (
9
+ <View ref={ref} className={cn('w-full caption-bottom text-sm', className)} {...props} />
10
+ ),
11
+ );
12
+ Table.displayName = 'Table';
13
+
14
+ const TableHeader = React.forwardRef<React.ElementRef<typeof View>, React.ComponentPropsWithoutRef<typeof View>>(
15
+ ({ className, ...props }, ref) => <View ref={ref} className={cn('border-b border-border', className)} {...props} />,
16
+ );
17
+ TableHeader.displayName = 'TableHeader';
18
+
19
+ const TableBody = React.forwardRef<React.ElementRef<typeof View>, React.ComponentPropsWithoutRef<typeof View>>(
20
+ ({ className, ...props }, ref) => <View ref={ref} className={cn('flex-1', className)} {...props} />,
21
+ );
22
+ TableBody.displayName = 'TableBody';
23
+
24
+ const TableFooter = React.forwardRef<React.ElementRef<typeof View>, React.ComponentPropsWithoutRef<typeof View>>(
25
+ ({ className, ...props }, ref) => (
26
+ <View ref={ref} className={cn('bg-muted/50 font-medium [&>tr]:last:border-b-0', className)} {...props} />
27
+ ),
28
+ );
29
+ TableFooter.displayName = 'TableFooter';
30
+
31
+ const TableRow = React.forwardRef<React.ElementRef<typeof View>, React.ComponentPropsWithoutRef<typeof View>>(
32
+ ({ className, ...props }, ref) => (
33
+ <View
34
+ ref={ref}
35
+ className={cn(
36
+ 'flex-row border-b border-border transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
37
+ className,
38
+ )}
39
+ {...props}
40
+ />
41
+ ),
42
+ );
43
+ TableRow.displayName = 'TableRow';
44
+
45
+ const TableHead = React.forwardRef<React.ElementRef<typeof Text>, React.ComponentPropsWithoutRef<typeof Text>>(
46
+ ({ className, ...props }, ref) => (
47
+ <Text
48
+ ref={ref}
49
+ className={cn(
50
+ 'h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0',
51
+ className,
52
+ )}
53
+ {...props}
54
+ />
55
+ ),
56
+ );
57
+ TableHead.displayName = 'TableHead';
58
+
59
+ const TableCell = React.forwardRef<React.ElementRef<typeof Text>, React.ComponentPropsWithoutRef<typeof Text>>(
60
+ ({ className, ...props }, ref) => (
61
+ <Text ref={ref} className={cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', className)} {...props} />
62
+ ),
63
+ );
64
+ TableCell.displayName = 'TableCell';
65
+
66
+ const TableCaption = React.forwardRef<React.ElementRef<typeof Text>, React.ComponentPropsWithoutRef<typeof Text>>(
67
+ ({ className, ...props }, ref) => (
68
+ <Text ref={ref} className={cn('mt-4 text-sm text-muted-foreground', className)} {...props} />
69
+ ),
70
+ );
71
+ TableCaption.displayName = 'TableCaption';
72
+
73
+ export { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow };
package/src/tabs.tsx ADDED
@@ -0,0 +1,74 @@
1
+ import { TabsBaseProps, TabsContentBaseProps, TabsListBaseProps, TabsTriggerBaseProps } from '@gv-tech/ui-core';
2
+ import * as TabsPrimitive from '@rn-primitives/tabs';
3
+ import * as React from 'react';
4
+
5
+ import { cn } from './lib/utils';
6
+ import { TextClassContext } from './text';
7
+
8
+ const Tabs = TabsPrimitive.Root;
9
+
10
+ export interface TabsProps
11
+ extends Omit<React.ComponentPropsWithoutRef<typeof TabsPrimitive.Root>, 'onValueChange' | 'value'>, TabsBaseProps {}
12
+ export interface TabsListProps extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>, TabsListBaseProps {}
13
+ export interface TabsTriggerProps
14
+ extends
15
+ Omit<React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>, 'children' | 'disabled'>,
16
+ TabsTriggerBaseProps {}
17
+ export interface TabsContentProps
18
+ extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>, TabsContentBaseProps {}
19
+
20
+ const TabsList = React.forwardRef<React.ElementRef<typeof TabsPrimitive.List>, TabsListProps>(
21
+ ({ className, ...props }, ref) => (
22
+ <TabsPrimitive.List
23
+ ref={ref}
24
+ className={cn(
25
+ 'h-10 inline-flex flex-row items-center justify-center rounded-md bg-muted p-1 text-muted-foreground',
26
+ className,
27
+ )}
28
+ {...props}
29
+ />
30
+ ),
31
+ );
32
+ TabsList.displayName = TabsPrimitive.List?.displayName || 'TabsList';
33
+
34
+ const TabsTrigger = React.forwardRef<React.ElementRef<typeof TabsPrimitive.Trigger>, TabsTriggerProps>(
35
+ ({ className, ...props }, ref) => {
36
+ const { value } = TabsPrimitive.useRootContext();
37
+ return (
38
+ <TextClassContext.Provider
39
+ value={cn(
40
+ 'text-sm native:text-base font-medium text-muted-foreground web:transition-all',
41
+ value === props.value && 'text-foreground',
42
+ )}
43
+ >
44
+ <TabsPrimitive.Trigger
45
+ ref={ref}
46
+ className={cn(
47
+ 'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
48
+ props.disabled && 'opacity-50',
49
+ value === props.value && 'bg-background shadow-sm shadow-foreground/10',
50
+ className,
51
+ )}
52
+ {...props}
53
+ />
54
+ </TextClassContext.Provider>
55
+ );
56
+ },
57
+ );
58
+ TabsTrigger.displayName = TabsPrimitive.Trigger?.displayName || 'TabsTrigger';
59
+
60
+ const TabsContent = React.forwardRef<React.ElementRef<typeof TabsPrimitive.Content>, TabsContentProps>(
61
+ ({ className, ...props }, ref) => (
62
+ <TabsPrimitive.Content
63
+ ref={ref}
64
+ className={cn(
65
+ 'mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
66
+ className,
67
+ )}
68
+ {...props}
69
+ />
70
+ ),
71
+ );
72
+ TabsContent.displayName = TabsPrimitive.Content?.displayName || 'TabsContent';
73
+
74
+ export { Tabs, TabsContent, TabsList, TabsTrigger };
package/src/text.tsx ADDED
@@ -0,0 +1,43 @@
1
+ import { cva, type VariantProps } from 'class-variance-authority';
2
+ import * as React from 'react';
3
+ import { Text as RNText } from 'react-native';
4
+
5
+ import type { TextBaseProps } from '@gv-tech/ui-core';
6
+ import { cn } from './lib/utils';
7
+
8
+ const TextClassContext = React.createContext<string | undefined>(undefined);
9
+
10
+ const textVariants = cva('text-foreground', {
11
+ variants: {
12
+ variant: {
13
+ h1: 'text-4xl font-extrabold tracking-tight',
14
+ h2: 'text-3xl font-semibold tracking-tight',
15
+ h3: 'text-2xl font-semibold tracking-tight',
16
+ h4: 'text-xl font-semibold tracking-tight',
17
+ body: 'text-base leading-7',
18
+ bodySmall: 'text-sm leading-6',
19
+ caption: 'text-xs text-muted-foreground',
20
+ label: 'text-sm font-medium',
21
+ overline: 'text-xs font-semibold uppercase tracking-widest text-muted-foreground',
22
+ },
23
+ },
24
+ defaultVariants: {
25
+ variant: 'body',
26
+ },
27
+ });
28
+
29
+ export interface TextProps
30
+ extends React.ComponentPropsWithoutRef<typeof RNText>, VariantProps<typeof textVariants>, TextBaseProps {}
31
+
32
+ const Text = React.forwardRef<React.ElementRef<typeof RNText>, TextProps>(
33
+ ({ className, variant = 'body', children, ...props }, ref) => {
34
+ return (
35
+ <RNText ref={ref} className={cn(textVariants({ variant, className }))} {...props}>
36
+ {children}
37
+ </RNText>
38
+ );
39
+ },
40
+ );
41
+ Text.displayName = 'Text';
42
+
43
+ export { Text, TextClassContext, textVariants };