@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.
- package/LICENSE +21 -0
- package/dist/index.d.ts +1113 -83
- package/dist/index.js +4936 -353
- package/package.json +27 -5
- package/src/cart/cart-line-actions.tsx +40 -0
- package/src/cart/cart-line.tsx +18 -32
- package/src/cart/cart-note-input.tsx +46 -0
- package/src/cart/cart-panel.tsx +39 -26
- package/src/cart/cart-total.tsx +43 -47
- package/src/cart/discount-badge.tsx +19 -0
- package/src/cart/index.ts +4 -1
- package/src/checkout/cash-tendered.tsx +101 -0
- package/src/checkout/change-display.tsx +19 -0
- package/src/checkout/index.ts +3 -0
- package/src/checkout/order-summary-line.tsx +7 -8
- package/src/checkout/order-summary.tsx +8 -7
- package/src/checkout/payment-method-card.tsx +10 -9
- package/src/checkout/payment-selector.tsx +5 -5
- package/src/checkout/receipt-preview.tsx +78 -0
- package/src/customer/customer-card.tsx +16 -12
- package/src/customer/customer-form.tsx +72 -0
- package/src/customer/customer-order-history.tsx +34 -0
- package/src/customer/customer-picker.tsx +124 -0
- package/src/customer/customer-select.tsx +80 -31
- package/src/customer/index.ts +3 -0
- package/src/index.ts +114 -1
- package/src/input/filter-chip.tsx +85 -27
- package/src/input/index.ts +1 -0
- package/src/input/quantity-stepper.tsx +64 -0
- package/src/input/search-input.tsx +30 -7
- package/src/layout/checkout-layout.tsx +46 -0
- package/src/layout/index.ts +5 -0
- package/src/layout/live-tab-screen.tsx +54 -0
- package/src/layout/pos-layout.tsx +64 -0
- package/src/layout/settings-layout.tsx +58 -0
- package/src/layout/store-settings-choice-screen.tsx +142 -0
- package/src/order/index.ts +4 -0
- package/src/order/order-card.tsx +48 -0
- package/src/order/order-detail.tsx +82 -0
- package/src/order/order-list.tsx +39 -0
- package/src/order/order-status-badge.tsx +32 -0
- package/src/product/category-nav.tsx +70 -0
- package/src/product/index.ts +3 -0
- package/src/product/product-card.tsx +36 -8
- package/src/product/product-grid.tsx +46 -13
- package/src/product/product-image.tsx +28 -7
- package/src/product/product-list.tsx +44 -0
- package/src/product/product-price.tsx +77 -22
- package/src/product/product-sku.tsx +5 -5
- package/src/product/product-stock-badge.tsx +41 -28
- package/src/product/product-title.tsx +2 -3
- package/src/product/product-variant-picker.tsx +61 -0
- package/src/register/cash-count-input.tsx +85 -0
- package/src/register/closure-sheet.tsx +161 -0
- package/src/register/index.ts +12 -0
- package/src/register/movement-sheet.tsx +118 -0
- package/src/register/open-register-card.tsx +109 -0
- package/src/register/register-bar.helpers.ts +57 -0
- package/src/register/register-bar.tsx +85 -0
- package/src/register/register-column.tsx +117 -0
- package/src/register/register-count.tsx +330 -0
- package/src/register/register-open-close.tsx +52 -0
- package/src/register/register-panel.tsx +151 -0
- package/src/register/register-picker.tsx +60 -0
- package/src/register/register-summary.tsx +72 -0
- package/src/sale/cart-bar.tsx +18 -0
- package/src/sale/cart.tsx +66 -0
- package/src/sale/catalogue.tsx +139 -0
- package/src/sale/discount-form.tsx +85 -0
- package/src/sale/index.ts +9 -0
- package/src/sale/orders-list.tsx +108 -0
- package/src/sale/print-style.ts +11 -0
- package/src/sale/receipt.tsx +62 -0
- package/src/sale/sync-status.tsx +141 -0
- package/src/sale/tender.tsx +38 -0
- package/src/settings/connector-status.tsx +65 -0
- package/src/settings/index.ts +3 -0
- package/src/settings/settings-group.tsx +23 -0
- package/src/settings/settings-row.tsx +23 -0
- package/src/ui/accordion/index.tsx +59 -0
- package/src/ui/alert-dialog/index.tsx +91 -0
- package/src/ui/avatar/index.tsx +50 -0
- package/src/ui/badge/index.tsx +60 -0
- package/src/ui/button/index.tsx +90 -0
- package/src/ui/card/index.tsx +60 -0
- package/src/ui/checkbox/index.tsx +29 -0
- package/src/ui/collapsible/index.tsx +24 -0
- package/src/ui/combobox/index.tsx +98 -0
- package/src/ui/context-menu/index.tsx +159 -0
- package/src/ui/dialog/index.tsx +92 -0
- package/src/ui/dropdown-menu/index.tsx +161 -0
- package/src/ui/hover-card/index.tsx +31 -0
- package/src/ui/hstack/index.tsx +43 -0
- package/src/ui/icon/index.tsx +44 -0
- package/src/ui/icon/search-icon.tsx +9 -0
- package/src/ui/icon/svg-icon.tsx +36 -0
- package/src/ui/icon-button/index.tsx +58 -0
- package/src/ui/index.ts +99 -0
- package/src/ui/input/index.tsx +100 -0
- package/src/ui/label/index.tsx +26 -0
- package/src/ui/loader/index.tsx +37 -0
- package/src/ui/popover/index.tsx +31 -0
- package/src/ui/progress/index.tsx +28 -0
- package/src/ui/radio-group/index.tsx +38 -0
- package/src/ui/select/index.tsx +96 -0
- package/src/ui/separator/index.tsx +29 -0
- package/src/ui/slider/index.tsx +28 -0
- package/src/ui/switch/index.tsx +31 -0
- package/src/ui/table/index.tsx +59 -0
- package/src/ui/tabs/index.tsx +53 -0
- package/src/ui/text/index.tsx +36 -0
- package/src/ui/textarea/index.tsx +29 -0
- package/src/ui/toast/index.tsx +52 -0
- package/src/ui/toggle/index.tsx +69 -0
- package/src/ui/toggle-group/index.tsx +66 -0
- package/src/ui/tooltip/index.tsx +30 -0
- package/src/ui/vstack/index.tsx +43 -0
- package/src/uniwind-env.d.ts +9 -1
- package/src/__tests__/cart-line.test.tsx +0 -53
- package/src/__tests__/cart-panel.test.tsx +0 -55
- package/src/__tests__/cart-total.test.tsx +0 -60
- package/src/__tests__/customer-card.test.tsx +0 -47
- package/src/__tests__/customer-select.test.tsx +0 -33
- package/src/__tests__/filter-chip.test.tsx +0 -40
- package/src/__tests__/helpers.ts +0 -111
- package/src/__tests__/order-summary-line.test.tsx +0 -18
- package/src/__tests__/order-summary.test.tsx +0 -32
- package/src/__tests__/payment-method-card.test.tsx +0 -24
- package/src/__tests__/payment-selector.test.tsx +0 -23
- package/src/__tests__/product-card.test.tsx +0 -31
- package/src/__tests__/product-grid.test.tsx +0 -37
- package/src/__tests__/product-image.test.tsx +0 -54
- package/src/__tests__/product-price.test.tsx +0 -68
- package/src/__tests__/product-sku.test.tsx +0 -47
- package/src/__tests__/product-stock-badge.test.tsx +0 -58
- package/src/__tests__/product-title.test.tsx +0 -38
- 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,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 };
|
package/src/ui/index.ts
ADDED
|
@@ -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 };
|