@tallyui/components 1.0.0 → 3.0.0-next.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 (137) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.ts +1113 -83
  3. package/dist/index.js +4936 -353
  4. package/package.json +27 -5
  5. package/src/cart/cart-line-actions.tsx +40 -0
  6. package/src/cart/cart-line.tsx +18 -32
  7. package/src/cart/cart-note-input.tsx +46 -0
  8. package/src/cart/cart-panel.tsx +39 -26
  9. package/src/cart/cart-total.tsx +43 -47
  10. package/src/cart/discount-badge.tsx +19 -0
  11. package/src/cart/index.ts +4 -1
  12. package/src/checkout/cash-tendered.tsx +101 -0
  13. package/src/checkout/change-display.tsx +19 -0
  14. package/src/checkout/index.ts +3 -0
  15. package/src/checkout/order-summary-line.tsx +7 -8
  16. package/src/checkout/order-summary.tsx +8 -7
  17. package/src/checkout/payment-method-card.tsx +10 -9
  18. package/src/checkout/payment-selector.tsx +5 -5
  19. package/src/checkout/receipt-preview.tsx +78 -0
  20. package/src/customer/customer-card.tsx +16 -12
  21. package/src/customer/customer-form.tsx +72 -0
  22. package/src/customer/customer-order-history.tsx +34 -0
  23. package/src/customer/customer-picker.tsx +124 -0
  24. package/src/customer/customer-select.tsx +80 -31
  25. package/src/customer/index.ts +3 -0
  26. package/src/index.ts +114 -1
  27. package/src/input/filter-chip.tsx +85 -27
  28. package/src/input/index.ts +1 -0
  29. package/src/input/quantity-stepper.tsx +64 -0
  30. package/src/input/search-input.tsx +30 -7
  31. package/src/layout/checkout-layout.tsx +46 -0
  32. package/src/layout/index.ts +5 -0
  33. package/src/layout/live-tab-screen.tsx +54 -0
  34. package/src/layout/pos-layout.tsx +64 -0
  35. package/src/layout/settings-layout.tsx +58 -0
  36. package/src/layout/store-settings-choice-screen.tsx +142 -0
  37. package/src/order/index.ts +4 -0
  38. package/src/order/order-card.tsx +48 -0
  39. package/src/order/order-detail.tsx +82 -0
  40. package/src/order/order-list.tsx +39 -0
  41. package/src/order/order-status-badge.tsx +32 -0
  42. package/src/product/category-nav.tsx +70 -0
  43. package/src/product/index.ts +3 -0
  44. package/src/product/product-card.tsx +36 -8
  45. package/src/product/product-grid.tsx +46 -13
  46. package/src/product/product-image.tsx +28 -7
  47. package/src/product/product-list.tsx +44 -0
  48. package/src/product/product-price.tsx +77 -22
  49. package/src/product/product-sku.tsx +5 -5
  50. package/src/product/product-stock-badge.tsx +41 -28
  51. package/src/product/product-title.tsx +2 -3
  52. package/src/product/product-variant-picker.tsx +61 -0
  53. package/src/register/cash-count-input.tsx +85 -0
  54. package/src/register/closure-sheet.tsx +161 -0
  55. package/src/register/index.ts +12 -0
  56. package/src/register/movement-sheet.tsx +118 -0
  57. package/src/register/open-register-card.tsx +109 -0
  58. package/src/register/register-bar.helpers.ts +57 -0
  59. package/src/register/register-bar.tsx +85 -0
  60. package/src/register/register-column.tsx +117 -0
  61. package/src/register/register-count.tsx +330 -0
  62. package/src/register/register-open-close.tsx +52 -0
  63. package/src/register/register-panel.tsx +151 -0
  64. package/src/register/register-picker.tsx +60 -0
  65. package/src/register/register-summary.tsx +72 -0
  66. package/src/sale/cart-bar.tsx +18 -0
  67. package/src/sale/cart.tsx +66 -0
  68. package/src/sale/catalogue.tsx +139 -0
  69. package/src/sale/discount-form.tsx +85 -0
  70. package/src/sale/index.ts +9 -0
  71. package/src/sale/orders-list.tsx +108 -0
  72. package/src/sale/print-style.ts +11 -0
  73. package/src/sale/receipt.tsx +62 -0
  74. package/src/sale/sync-status.tsx +141 -0
  75. package/src/sale/tender.tsx +38 -0
  76. package/src/settings/connector-status.tsx +65 -0
  77. package/src/settings/index.ts +3 -0
  78. package/src/settings/settings-group.tsx +23 -0
  79. package/src/settings/settings-row.tsx +23 -0
  80. package/src/ui/accordion/index.tsx +59 -0
  81. package/src/ui/alert-dialog/index.tsx +91 -0
  82. package/src/ui/avatar/index.tsx +50 -0
  83. package/src/ui/badge/index.tsx +60 -0
  84. package/src/ui/button/index.tsx +90 -0
  85. package/src/ui/card/index.tsx +60 -0
  86. package/src/ui/checkbox/index.tsx +29 -0
  87. package/src/ui/collapsible/index.tsx +24 -0
  88. package/src/ui/combobox/index.tsx +98 -0
  89. package/src/ui/context-menu/index.tsx +159 -0
  90. package/src/ui/dialog/index.tsx +92 -0
  91. package/src/ui/dropdown-menu/index.tsx +161 -0
  92. package/src/ui/hover-card/index.tsx +31 -0
  93. package/src/ui/hstack/index.tsx +43 -0
  94. package/src/ui/icon/index.tsx +44 -0
  95. package/src/ui/icon/search-icon.tsx +9 -0
  96. package/src/ui/icon/svg-icon.tsx +36 -0
  97. package/src/ui/icon-button/index.tsx +58 -0
  98. package/src/ui/index.ts +99 -0
  99. package/src/ui/input/index.tsx +100 -0
  100. package/src/ui/label/index.tsx +26 -0
  101. package/src/ui/loader/index.tsx +37 -0
  102. package/src/ui/popover/index.tsx +31 -0
  103. package/src/ui/progress/index.tsx +28 -0
  104. package/src/ui/radio-group/index.tsx +38 -0
  105. package/src/ui/select/index.tsx +96 -0
  106. package/src/ui/separator/index.tsx +29 -0
  107. package/src/ui/slider/index.tsx +28 -0
  108. package/src/ui/switch/index.tsx +31 -0
  109. package/src/ui/table/index.tsx +59 -0
  110. package/src/ui/tabs/index.tsx +53 -0
  111. package/src/ui/text/index.tsx +36 -0
  112. package/src/ui/textarea/index.tsx +29 -0
  113. package/src/ui/toast/index.tsx +52 -0
  114. package/src/ui/toggle/index.tsx +69 -0
  115. package/src/ui/toggle-group/index.tsx +66 -0
  116. package/src/ui/tooltip/index.tsx +30 -0
  117. package/src/ui/vstack/index.tsx +43 -0
  118. package/src/uniwind-env.d.ts +9 -1
  119. package/src/__tests__/cart-line.test.tsx +0 -53
  120. package/src/__tests__/cart-panel.test.tsx +0 -55
  121. package/src/__tests__/cart-total.test.tsx +0 -60
  122. package/src/__tests__/customer-card.test.tsx +0 -47
  123. package/src/__tests__/customer-select.test.tsx +0 -33
  124. package/src/__tests__/filter-chip.test.tsx +0 -40
  125. package/src/__tests__/helpers.ts +0 -111
  126. package/src/__tests__/order-summary-line.test.tsx +0 -18
  127. package/src/__tests__/order-summary.test.tsx +0 -32
  128. package/src/__tests__/payment-method-card.test.tsx +0 -24
  129. package/src/__tests__/payment-selector.test.tsx +0 -23
  130. package/src/__tests__/product-card.test.tsx +0 -31
  131. package/src/__tests__/product-grid.test.tsx +0 -37
  132. package/src/__tests__/product-image.test.tsx +0 -54
  133. package/src/__tests__/product-price.test.tsx +0 -68
  134. package/src/__tests__/product-sku.test.tsx +0 -47
  135. package/src/__tests__/product-stock-badge.test.tsx +0 -58
  136. package/src/__tests__/product-title.test.tsx +0 -38
  137. package/src/__tests__/search-input.test.tsx +0 -22
@@ -0,0 +1,43 @@
1
+ import * as React from 'react';
2
+ import { View, type ViewProps } from 'react-native';
3
+ import { cn } from '@tallyui/theme';
4
+ import { cva, type VariantProps } from 'class-variance-authority';
5
+
6
+ const hstackVariants = cva('flex-row items-center', {
7
+ variants: {
8
+ space: {
9
+ none: 'gap-0',
10
+ xs: 'gap-1',
11
+ sm: 'gap-2',
12
+ md: 'gap-3',
13
+ lg: 'gap-4',
14
+ xl: 'gap-6',
15
+ },
16
+ reversed: {
17
+ true: 'flex-row-reverse',
18
+ },
19
+ },
20
+ defaultVariants: {
21
+ space: 'md',
22
+ },
23
+ });
24
+
25
+ type HStackProps = ViewProps & VariantProps<typeof hstackVariants>;
26
+
27
+ const HStack = React.forwardRef<View, HStackProps>(function HStack(
28
+ { className, space, reversed, ...props },
29
+ ref
30
+ ) {
31
+ return (
32
+ <View
33
+ ref={ref}
34
+ className={cn(hstackVariants({ space, reversed }), className)}
35
+ {...props}
36
+ />
37
+ );
38
+ });
39
+
40
+ HStack.displayName = 'HStack';
41
+
42
+ export { HStack, hstackVariants };
43
+ export type { HStackProps };
@@ -0,0 +1,44 @@
1
+ import * as React from 'react';
2
+ import { View, type ViewProps } from 'react-native';
3
+ import { TextClassContext } from '@tallyui/primitives';
4
+ import { cn } from '@tallyui/theme';
5
+ import { cva, type VariantProps } from 'class-variance-authority';
6
+
7
+ const iconVariants = cva('items-center justify-center', {
8
+ variants: {
9
+ size: {
10
+ xs: 'h-3 w-3',
11
+ sm: 'h-4 w-4',
12
+ md: 'h-5 w-5',
13
+ lg: 'h-6 w-6',
14
+ xl: 'h-8 w-8',
15
+ },
16
+ },
17
+ defaultVariants: {
18
+ size: 'md',
19
+ },
20
+ });
21
+
22
+ type IconProps = ViewProps & VariantProps<typeof iconVariants>;
23
+
24
+ const Icon = React.forwardRef<View, IconProps>(function Icon(
25
+ { className, size, children, ...props },
26
+ ref
27
+ ) {
28
+ const textClass = React.useContext(TextClassContext);
29
+
30
+ return (
31
+ <View
32
+ ref={ref}
33
+ className={cn(iconVariants({ size }), textClass, className)}
34
+ {...props}
35
+ >
36
+ {children}
37
+ </View>
38
+ );
39
+ });
40
+
41
+ Icon.displayName = 'Icon';
42
+
43
+ export { Icon, iconVariants };
44
+ export type { IconProps };
@@ -0,0 +1,9 @@
1
+ import { Circle, Line } from 'react-native-svg';
2
+ import { createSvgIcon } from './svg-icon';
3
+
4
+ export const SearchIcon = createSvgIcon('SearchIcon', () => (
5
+ <>
6
+ <Circle cx={11} cy={11} r={7} />
7
+ <Line x1={16.5} y1={16.5} x2={21} y2={21} />
8
+ </>
9
+ ));
@@ -0,0 +1,36 @@
1
+ import * as React from 'react';
2
+ import Svg, { type SvgProps } from 'react-native-svg';
3
+
4
+ export type SvgIconProps = {
5
+ size?: number;
6
+ color?: string;
7
+ strokeWidth?: number;
8
+ accessibilityLabel?: string;
9
+ } & Omit<SvgProps, 'width' | 'height' | 'color'>;
10
+
11
+ export function createSvgIcon(name: string, render: (props: { strokeWidth: number }) => React.ReactNode) {
12
+ function SvgIcon({ size = 16, color, strokeWidth = 2, accessibilityLabel, ...props }: SvgIconProps) {
13
+ return (
14
+ <Svg
15
+ {...props}
16
+ viewBox="0 0 24 24"
17
+ width={size}
18
+ height={size}
19
+ fill="none"
20
+ stroke={color ?? 'currentColor'}
21
+ strokeWidth={strokeWidth}
22
+ strokeLinecap="round"
23
+ strokeLinejoin="round"
24
+ color={color}
25
+ aria-hidden={accessibilityLabel === undefined}
26
+ role={accessibilityLabel === undefined ? undefined : 'img'}
27
+ aria-label={accessibilityLabel}
28
+ >
29
+ {render({ strokeWidth })}
30
+ </Svg>
31
+ );
32
+ }
33
+
34
+ SvgIcon.displayName = name;
35
+ return SvgIcon;
36
+ }
@@ -0,0 +1,58 @@
1
+ import * as React from 'react';
2
+ import { Pressable, type PressableProps } from 'react-native';
3
+ import { Slot } from '@tallyui/primitives';
4
+ import { cn } from '@tallyui/theme';
5
+ import { cva, type VariantProps } from 'class-variance-authority';
6
+
7
+ const iconButtonVariants = cva(
8
+ 'inline-flex items-center justify-center rounded-md web:transition-colors web:focus-visible:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring',
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: 'bg-primary active:opacity-90',
13
+ destructive: 'bg-destructive active:opacity-90',
14
+ outline: 'border border-input bg-background active:bg-accent',
15
+ secondary: 'bg-secondary active:opacity-80',
16
+ ghost: 'active:bg-accent',
17
+ },
18
+ size: {
19
+ sm: 'h-8 w-8',
20
+ md: 'h-10 w-10',
21
+ lg: 'h-12 w-12',
22
+ },
23
+ },
24
+ defaultVariants: {
25
+ variant: 'ghost',
26
+ size: 'md',
27
+ },
28
+ }
29
+ );
30
+
31
+ type IconButtonProps = PressableProps & VariantProps<typeof iconButtonVariants> & {
32
+ asChild?: boolean;
33
+ };
34
+
35
+ const IconButton = React.forwardRef<React.ComponentRef<typeof Pressable>, IconButtonProps>(
36
+ function IconButton({ className, variant, size, asChild = false, disabled, ...props }, ref) {
37
+ const Component = asChild ? Slot : Pressable;
38
+
39
+ return (
40
+ <Component
41
+ ref={ref}
42
+ role="button"
43
+ disabled={disabled}
44
+ className={cn(
45
+ iconButtonVariants({ variant, size }),
46
+ disabled && 'opacity-50 web:pointer-events-none',
47
+ className,
48
+ )}
49
+ {...props}
50
+ />
51
+ );
52
+ }
53
+ );
54
+
55
+ IconButton.displayName = 'IconButton';
56
+
57
+ export { IconButton, iconButtonVariants };
58
+ export type { IconButtonProps };
@@ -0,0 +1,99 @@
1
+ // Core
2
+ export { Text, TextClassContext, textVariants, type TextProps } from './text';
3
+ export { HStack, hstackVariants, type HStackProps } from './hstack';
4
+ export { VStack, vstackVariants, type VStackProps } from './vstack';
5
+
6
+ // Visual
7
+ export { Icon, iconVariants, type IconProps } from './icon';
8
+ export { createSvgIcon, type SvgIconProps } from './icon/svg-icon';
9
+ export { SearchIcon } from './icon/search-icon';
10
+ export { Loader, loaderVariants, type LoaderProps } from './loader';
11
+ export { Badge, badgeVariants, badgeTextVariants, type BadgeProps } from './badge';
12
+ export { Avatar, avatarVariants, type AvatarProps } from './avatar';
13
+
14
+ // Interactive
15
+ export { Button, buttonVariants, buttonTextVariants, type ButtonProps } from './button';
16
+ export { IconButton, iconButtonVariants, type IconButtonProps } from './icon-button';
17
+
18
+ // Containers & Form
19
+ export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from './card';
20
+ export { Separator, type SeparatorProps } from './separator';
21
+ export { Label, type LabelProps } from './label';
22
+ export { Input, InputRoot, InputField, InputSlot, useInputContext, type InputRootProps } from './input';
23
+ export { Textarea, type TextareaProps } from './textarea';
24
+
25
+ // Tabs
26
+ export { Tabs, TabsList, TabsTrigger, TabsContent } from './tabs';
27
+
28
+ // Dialog
29
+ export {
30
+ Dialog, DialogTrigger, DialogPortal, DialogOverlay, DialogContent,
31
+ DialogHeader, DialogFooter, DialogTitle, DialogDescription, DialogClose,
32
+ } from './dialog';
33
+
34
+ // Alert Dialog
35
+ export {
36
+ AlertDialog, AlertDialogTrigger, AlertDialogPortal, AlertDialogOverlay,
37
+ AlertDialogContent, AlertDialogHeader, AlertDialogFooter, AlertDialogTitle,
38
+ AlertDialogDescription, AlertDialogAction, AlertDialogCancel,
39
+ } from './alert-dialog';
40
+
41
+ // Select
42
+ export {
43
+ Select, SelectGroup, SelectValue, SelectTrigger, SelectContent,
44
+ SelectLabel, SelectItem, SelectSeparator,
45
+ } from './select';
46
+
47
+ // Combobox
48
+ export {
49
+ Combobox, ComboboxTrigger, ComboboxInput, ComboboxContent,
50
+ ComboboxItem, ComboboxEmpty,
51
+ } from './combobox';
52
+
53
+ // Dropdown Menu
54
+ export {
55
+ DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem,
56
+ DropdownMenuCheckboxItem, DropdownMenuRadioItem, DropdownMenuLabel,
57
+ DropdownMenuSeparator, DropdownMenuGroup, DropdownMenuPortal,
58
+ DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger,
59
+ DropdownMenuRadioGroup,
60
+ } from './dropdown-menu';
61
+
62
+ // Context Menu
63
+ export {
64
+ ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuItem,
65
+ ContextMenuCheckboxItem, ContextMenuRadioItem, ContextMenuLabel,
66
+ ContextMenuSeparator, ContextMenuGroup, ContextMenuPortal,
67
+ ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger,
68
+ ContextMenuRadioGroup,
69
+ } from './context-menu';
70
+
71
+ // Popover
72
+ export { Popover, PopoverTrigger, PopoverContent } from './popover';
73
+
74
+ // Tooltip
75
+ export { Tooltip, TooltipTrigger, TooltipContent } from './tooltip';
76
+
77
+ // Hover Card
78
+ export { HoverCard, HoverCardTrigger, HoverCardContent } from './hover-card';
79
+
80
+ // Accordion
81
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from './accordion';
82
+
83
+ // Collapsible
84
+ export { Collapsible, CollapsibleTrigger, CollapsibleContent } from './collapsible';
85
+
86
+ // Form Controls
87
+ export { Checkbox } from './checkbox';
88
+ export { Switch } from './switch';
89
+ export { RadioGroup, RadioGroupItem } from './radio-group';
90
+ export { Toggle, toggleVariants, toggleTextVariants, type ToggleProps } from './toggle';
91
+ export { ToggleGroup, ToggleGroupItem, type ToggleGroupProps, type ToggleGroupItemProps } from './toggle-group';
92
+ export { Progress, type ProgressProps } from './progress';
93
+ export { Slider, type SliderProps } from './slider';
94
+
95
+ // Toast
96
+ export { Toast, ToastTitle, ToastDescription, ToastClose, toastVariants, type ToastProps } from './toast';
97
+
98
+ // Table
99
+ export { Table, TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell } from './table';
@@ -0,0 +1,100 @@
1
+ import * as React from 'react';
2
+ import { TextInput, View, type TextInputProps, type ViewProps } from 'react-native';
3
+ import { cn } from '@tallyui/theme';
4
+
5
+ interface InputContextType {
6
+ focused: boolean;
7
+ disabled: boolean;
8
+ }
9
+
10
+ const InputContext = React.createContext<InputContextType>({
11
+ focused: false,
12
+ disabled: false,
13
+ });
14
+
15
+ function useInputContext() {
16
+ return React.useContext(InputContext);
17
+ }
18
+
19
+ // Root container
20
+ interface InputRootProps extends ViewProps {
21
+ disabled?: boolean;
22
+ }
23
+
24
+ const InputRoot = React.forwardRef<View, InputRootProps>(
25
+ function InputRoot({ className, disabled = false, children, ...props }, ref) {
26
+ const [focused, setFocused] = React.useState(false);
27
+
28
+ return (
29
+ <InputContext.Provider value={{ focused, disabled }}>
30
+ <View
31
+ ref={ref}
32
+ className={cn(
33
+ 'flex h-10 flex-row items-center rounded-md border border-input bg-background px-3',
34
+ focused && 'ring-2 ring-ring ring-offset-2',
35
+ disabled && 'opacity-50',
36
+ className,
37
+ )}
38
+ {...props}
39
+ >
40
+ {React.Children.map(children, (child) => {
41
+ if (React.isValidElement(child) && child.type === InputField) {
42
+ return React.cloneElement(child as React.ReactElement<any>, {
43
+ onFocus: (e: any) => {
44
+ setFocused(true);
45
+ (child.props as any).onFocus?.(e);
46
+ },
47
+ onBlur: (e: any) => {
48
+ setFocused(false);
49
+ (child.props as any).onBlur?.(e);
50
+ },
51
+ });
52
+ }
53
+ return child;
54
+ })}
55
+ </View>
56
+ </InputContext.Provider>
57
+ );
58
+ }
59
+ );
60
+ InputRoot.displayName = 'InputRoot';
61
+
62
+ // Left/Right slots
63
+ const InputSlot = React.forwardRef<View, ViewProps>(
64
+ function InputSlot({ className, ...props }, ref) {
65
+ return (
66
+ <View ref={ref} className={cn('justify-center', className)} {...props} />
67
+ );
68
+ }
69
+ );
70
+ InputSlot.displayName = 'InputSlot';
71
+
72
+ // The actual text input
73
+ const InputField = React.forwardRef<TextInput, TextInputProps>(
74
+ function InputField({ className, ...props }, ref) {
75
+ const { disabled } = useInputContext();
76
+
77
+ return (
78
+ <TextInput
79
+ ref={ref}
80
+ editable={!disabled}
81
+ className={cn(
82
+ 'flex-1 text-sm text-foreground web:outline-none placeholder:text-muted-foreground',
83
+ className,
84
+ )}
85
+ {...props}
86
+ />
87
+ );
88
+ }
89
+ );
90
+ InputField.displayName = 'InputField';
91
+
92
+ // Convenience compound component
93
+ const Input = Object.assign(InputRoot, {
94
+ Left: InputSlot,
95
+ Field: InputField,
96
+ Right: InputSlot,
97
+ });
98
+
99
+ export { Input, InputRoot, InputField, InputSlot, useInputContext };
100
+ export type { InputRootProps };
@@ -0,0 +1,26 @@
1
+ import * as React from 'react';
2
+ import { Text } from 'react-native';
3
+ import { Label as LabelPrimitive } from '@tallyui/primitives';
4
+ import { cn } from '@tallyui/theme';
5
+
6
+ type LabelProps = React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>;
7
+
8
+ const Label = React.forwardRef<React.ComponentRef<typeof Text>, LabelProps>(
9
+ function Label({ className, ...props }, ref) {
10
+ return (
11
+ <LabelPrimitive.Root
12
+ ref={ref}
13
+ className={cn(
14
+ 'text-sm font-medium leading-none text-foreground web:peer-disabled:cursor-not-allowed web:peer-disabled:opacity-70',
15
+ className,
16
+ )}
17
+ {...props}
18
+ />
19
+ );
20
+ }
21
+ );
22
+
23
+ Label.displayName = 'Label';
24
+
25
+ export { Label };
26
+ export type { LabelProps };
@@ -0,0 +1,37 @@
1
+ import * as React from 'react';
2
+ import { View, type ViewProps } from 'react-native';
3
+ import { TextClassContext } from '@tallyui/primitives';
4
+ import { cn } from '@tallyui/theme';
5
+ import { cva, type VariantProps } from 'class-variance-authority';
6
+
7
+ const loaderVariants = cva('animate-spin', {
8
+ variants: {
9
+ size: {
10
+ sm: 'h-4 w-4',
11
+ md: 'h-5 w-5',
12
+ lg: 'h-8 w-8',
13
+ },
14
+ },
15
+ defaultVariants: {
16
+ size: 'md',
17
+ },
18
+ });
19
+
20
+ type LoaderProps = Omit<ViewProps, 'children'> & VariantProps<typeof loaderVariants>;
21
+
22
+ function Loader({ className, size, ...props }: LoaderProps) {
23
+ const textClass = React.useContext(TextClassContext);
24
+
25
+ return (
26
+ <View
27
+ className={cn(loaderVariants({ size }), textClass, className)}
28
+ role="progressbar"
29
+ {...props}
30
+ >
31
+ <View className="h-full w-full rounded-full border-2 border-current border-t-transparent" />
32
+ </View>
33
+ );
34
+ }
35
+
36
+ export { Loader, loaderVariants };
37
+ export type { LoaderProps };
@@ -0,0 +1,31 @@
1
+ import * as React from 'react';
2
+ import { Popover as PopoverPrimitive, TextClassContext } from '@tallyui/primitives';
3
+ import { cn } from '@tallyui/theme';
4
+
5
+ const Popover = PopoverPrimitive.Root;
6
+ const PopoverTrigger = PopoverPrimitive.Trigger;
7
+
8
+ const PopoverContent = React.forwardRef<
9
+ React.ComponentRef<typeof PopoverPrimitive.Content>,
10
+ React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
11
+ >(function PopoverContent({ className, align = 'center', sideOffset = 4, ...props }, ref) {
12
+ return (
13
+ <PopoverPrimitive.Portal>
14
+ <TextClassContext.Provider value="text-popover-foreground">
15
+ <PopoverPrimitive.Content
16
+ ref={ref}
17
+ align={align}
18
+ sideOffset={sideOffset}
19
+ className={cn(
20
+ 'z-50 w-72 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none',
21
+ className,
22
+ )}
23
+ {...props}
24
+ />
25
+ </TextClassContext.Provider>
26
+ </PopoverPrimitive.Portal>
27
+ );
28
+ });
29
+ PopoverContent.displayName = 'PopoverContent';
30
+
31
+ export { Popover, PopoverTrigger, PopoverContent };
@@ -0,0 +1,28 @@
1
+ import * as React from 'react';
2
+ import { View } from 'react-native';
3
+ import { Progress as ProgressPrimitive } from '@tallyui/primitives';
4
+ import { cn } from '@tallyui/theme';
5
+
6
+ type ProgressProps = React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>;
7
+
8
+ const Progress = React.forwardRef<
9
+ React.ComponentRef<typeof ProgressPrimitive.Root>,
10
+ ProgressProps
11
+ >(function Progress({ className, value, ...props }, ref) {
12
+ return (
13
+ <ProgressPrimitive.Root
14
+ ref={ref}
15
+ className={cn('relative h-4 w-full overflow-hidden rounded-full bg-secondary', className)}
16
+ {...props}
17
+ >
18
+ <ProgressPrimitive.Indicator
19
+ className="h-full w-full flex-1 rounded-full bg-primary web:transition-all"
20
+ style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
21
+ />
22
+ </ProgressPrimitive.Root>
23
+ );
24
+ });
25
+ Progress.displayName = 'Progress';
26
+
27
+ export { Progress };
28
+ export type { ProgressProps };
@@ -0,0 +1,38 @@
1
+ import * as React from 'react';
2
+ import { View, Text } from 'react-native';
3
+ import { RadioGroup as RadioGroupPrimitive } from '@tallyui/primitives';
4
+ import { cn } from '@tallyui/theme';
5
+
6
+ const RadioGroup = React.forwardRef<
7
+ React.ComponentRef<typeof RadioGroupPrimitive.Root>,
8
+ React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
9
+ >(function RadioGroup({ className, ...props }, ref) {
10
+ return (
11
+ <RadioGroupPrimitive.Root ref={ref} className={cn('grid gap-2', className)} {...props} />
12
+ );
13
+ });
14
+ RadioGroup.displayName = 'RadioGroup';
15
+
16
+ const RadioGroupItem = React.forwardRef<
17
+ React.ComponentRef<typeof RadioGroupPrimitive.Item>,
18
+ React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
19
+ >(function RadioGroupItem({ className, ...props }, ref) {
20
+ return (
21
+ <RadioGroupPrimitive.Item
22
+ ref={ref}
23
+ className={cn(
24
+ 'aspect-square h-4 w-4 rounded-full border border-primary text-primary web:ring-offset-background web:focus:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring web:focus-visible:ring-offset-2',
25
+ props.disabled && 'web:cursor-not-allowed opacity-50',
26
+ className,
27
+ )}
28
+ {...props}
29
+ >
30
+ <RadioGroupPrimitive.Indicator className="flex items-center justify-center">
31
+ <View className="h-2.5 w-2.5 rounded-full bg-current" />
32
+ </RadioGroupPrimitive.Indicator>
33
+ </RadioGroupPrimitive.Item>
34
+ );
35
+ });
36
+ RadioGroupItem.displayName = 'RadioGroupItem';
37
+
38
+ export { RadioGroup, RadioGroupItem };
@@ -0,0 +1,96 @@
1
+ import * as React from 'react';
2
+ import { View } from 'react-native';
3
+ import { Select as SelectPrimitive } from '@tallyui/primitives';
4
+ import { cn } from '@tallyui/theme';
5
+
6
+ const Select = SelectPrimitive.Root;
7
+ const SelectGroup = SelectPrimitive.Group;
8
+ const SelectValue = SelectPrimitive.Value;
9
+
10
+ const SelectTrigger = React.forwardRef<
11
+ React.ComponentRef<typeof SelectPrimitive.Trigger>,
12
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
13
+ >(function SelectTrigger({ className, children, ...props }, ref) {
14
+ return (
15
+ <SelectPrimitive.Trigger
16
+ ref={ref}
17
+ className={cn(
18
+ 'flex h-10 w-full flex-row items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground web:ring-offset-background web:focus:outline-none web:focus:ring-2 web:focus:ring-ring web:focus:ring-offset-2',
19
+ className,
20
+ )}
21
+ {...props}
22
+ >
23
+ {children}
24
+ </SelectPrimitive.Trigger>
25
+ );
26
+ });
27
+ SelectTrigger.displayName = 'SelectTrigger';
28
+
29
+ const SelectContent = React.forwardRef<
30
+ React.ComponentRef<typeof SelectPrimitive.Content>,
31
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
32
+ >(function SelectContent({ className, children, ...props }, ref) {
33
+ return (
34
+ <SelectPrimitive.Portal>
35
+ <SelectPrimitive.Content
36
+ ref={ref}
37
+ className={cn(
38
+ 'relative z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md',
39
+ className,
40
+ )}
41
+ {...props}
42
+ >
43
+ {children}
44
+ </SelectPrimitive.Content>
45
+ </SelectPrimitive.Portal>
46
+ );
47
+ });
48
+ SelectContent.displayName = 'SelectContent';
49
+
50
+ const SelectLabel = React.forwardRef<
51
+ React.ComponentRef<typeof SelectPrimitive.Label>,
52
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
53
+ >(function SelectLabel({ className, ...props }, ref) {
54
+ return (
55
+ <SelectPrimitive.Label ref={ref} className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', className)} {...props} />
56
+ );
57
+ });
58
+ SelectLabel.displayName = 'SelectLabel';
59
+
60
+ const SelectItem = React.forwardRef<
61
+ React.ComponentRef<typeof SelectPrimitive.Item>,
62
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
63
+ >(function SelectItem({ className, ...props }, ref) {
64
+ return (
65
+ <SelectPrimitive.Item
66
+ ref={ref}
67
+ className={cn(
68
+ '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:focus:bg-accent web:focus:text-accent-foreground',
69
+ className,
70
+ )}
71
+ {...props}
72
+ />
73
+ );
74
+ });
75
+ SelectItem.displayName = 'SelectItem';
76
+
77
+ const SelectSeparator = React.forwardRef<
78
+ React.ComponentRef<typeof SelectPrimitive.Separator>,
79
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
80
+ >(function SelectSeparator({ className, ...props }, ref) {
81
+ return (
82
+ <SelectPrimitive.Separator ref={ref} className={cn('-mx-1 my-1 h-px bg-muted', className)} {...props} />
83
+ );
84
+ });
85
+ SelectSeparator.displayName = 'SelectSeparator';
86
+
87
+ export {
88
+ Select,
89
+ SelectGroup,
90
+ SelectValue,
91
+ SelectTrigger,
92
+ SelectContent,
93
+ SelectLabel,
94
+ SelectItem,
95
+ SelectSeparator,
96
+ };
@@ -0,0 +1,29 @@
1
+ import * as React from 'react';
2
+ import { View } from 'react-native';
3
+ import { Separator as SeparatorPrimitive } from '@tallyui/primitives';
4
+ import { cn } from '@tallyui/theme';
5
+
6
+ type SeparatorProps = React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>;
7
+
8
+ const Separator = React.forwardRef<React.ComponentRef<typeof View>, SeparatorProps>(
9
+ function Separator({ className, orientation = 'horizontal', decorative = true, ...props }, ref) {
10
+ return (
11
+ <SeparatorPrimitive.Root
12
+ ref={ref}
13
+ decorative={decorative}
14
+ orientation={orientation}
15
+ className={cn(
16
+ 'shrink-0 bg-border',
17
+ orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
18
+ className,
19
+ )}
20
+ {...props}
21
+ />
22
+ );
23
+ }
24
+ );
25
+
26
+ Separator.displayName = 'Separator';
27
+
28
+ export { Separator };
29
+ export type { SeparatorProps };