@tallyui/components 1.0.0 → 2.0.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 +1076 -76
- package/dist/index.js +4662 -355
- 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 +8 -9
- package/src/customer/customer-form.tsx +70 -0
- package/src/customer/customer-order-history.tsx +34 -0
- package/src/customer/customer-select.tsx +63 -24
- package/src/customer/index.ts +2 -0
- package/src/index.ts +112 -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 +25 -6
- 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 +155 -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 +131 -0
- package/src/sale/discount-form.tsx +85 -0
- package/src/sale/index.ts +9 -0
- package/src/sale/orders-list.tsx +66 -0
- package/src/sale/print-style.ts +11 -0
- package/src/sale/receipt.tsx +61 -0
- package/src/sale/sync-status.tsx +20 -0
- package/src/sale/tender.tsx +35 -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,23 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { Text, View, type ViewProps } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { cn } from '@tallyui/theme';
|
|
5
|
+
|
|
6
|
+
export interface SettingsRowProps extends Omit<ViewProps, 'children'> {
|
|
7
|
+
label: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
action?: ReactNode;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function SettingsRow({ label, description, action, className, ...viewProps }: SettingsRowProps) {
|
|
14
|
+
return (
|
|
15
|
+
<View className={cn('flex-row items-center gap-3 px-4 py-3', className)} {...viewProps}>
|
|
16
|
+
<View className="flex-1 gap-0.5">
|
|
17
|
+
<Text className="text-sm font-medium text-foreground">{label}</Text>
|
|
18
|
+
{description && <Text className="text-xs text-muted-foreground">{description}</Text>}
|
|
19
|
+
</View>
|
|
20
|
+
{action && <View>{action}</View>}
|
|
21
|
+
</View>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import { Accordion as AccordionPrimitive, TextClassContext } from '@tallyui/primitives';
|
|
4
|
+
import { cn } from '@tallyui/theme';
|
|
5
|
+
|
|
6
|
+
const Accordion = AccordionPrimitive.Root;
|
|
7
|
+
|
|
8
|
+
const AccordionItem = React.forwardRef<
|
|
9
|
+
React.ComponentRef<typeof AccordionPrimitive.Item>,
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
|
|
11
|
+
>(function AccordionItem({ className, ...props }, ref) {
|
|
12
|
+
return (
|
|
13
|
+
<AccordionPrimitive.Item ref={ref} className={cn('border-b border-border', className)} {...props} />
|
|
14
|
+
);
|
|
15
|
+
});
|
|
16
|
+
AccordionItem.displayName = 'AccordionItem';
|
|
17
|
+
|
|
18
|
+
const AccordionTrigger = React.forwardRef<
|
|
19
|
+
React.ComponentRef<typeof AccordionPrimitive.Trigger>,
|
|
20
|
+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
|
|
21
|
+
>(function AccordionTrigger({ className, children, ...props }, ref) {
|
|
22
|
+
return (
|
|
23
|
+
<AccordionPrimitive.Header className="flex">
|
|
24
|
+
<TextClassContext.Provider value="text-sm font-medium">
|
|
25
|
+
<AccordionPrimitive.Trigger
|
|
26
|
+
ref={ref}
|
|
27
|
+
className={cn(
|
|
28
|
+
'flex flex-1 flex-row items-center justify-between py-4 font-medium web:transition-all web:hover:underline',
|
|
29
|
+
className,
|
|
30
|
+
)}
|
|
31
|
+
{...props}
|
|
32
|
+
>
|
|
33
|
+
{children}
|
|
34
|
+
</AccordionPrimitive.Trigger>
|
|
35
|
+
</TextClassContext.Provider>
|
|
36
|
+
</AccordionPrimitive.Header>
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
AccordionTrigger.displayName = 'AccordionTrigger';
|
|
40
|
+
|
|
41
|
+
const AccordionContent = React.forwardRef<
|
|
42
|
+
React.ComponentRef<typeof AccordionPrimitive.Content>,
|
|
43
|
+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
|
|
44
|
+
>(function AccordionContent({ className, children, ...props }, ref) {
|
|
45
|
+
return (
|
|
46
|
+
<TextClassContext.Provider value="text-sm">
|
|
47
|
+
<AccordionPrimitive.Content
|
|
48
|
+
ref={ref}
|
|
49
|
+
className={cn('overflow-hidden text-sm web:transition-all', className)}
|
|
50
|
+
{...props}
|
|
51
|
+
>
|
|
52
|
+
<View className="pb-4 pt-0">{children}</View>
|
|
53
|
+
</AccordionPrimitive.Content>
|
|
54
|
+
</TextClassContext.Provider>
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
AccordionContent.displayName = 'AccordionContent';
|
|
58
|
+
|
|
59
|
+
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import { AlertDialog as AlertDialogPrimitive, TextClassContext } from '@tallyui/primitives';
|
|
4
|
+
import { cn } from '@tallyui/theme';
|
|
5
|
+
|
|
6
|
+
const AlertDialog = AlertDialogPrimitive.Root;
|
|
7
|
+
const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
|
|
8
|
+
const AlertDialogPortal = AlertDialogPrimitive.Portal;
|
|
9
|
+
|
|
10
|
+
const AlertDialogOverlay = React.forwardRef<
|
|
11
|
+
React.ComponentRef<typeof AlertDialogPrimitive.Overlay>,
|
|
12
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
|
|
13
|
+
>(function AlertDialogOverlay({ className, ...props }, ref) {
|
|
14
|
+
return (
|
|
15
|
+
<AlertDialogPrimitive.Overlay
|
|
16
|
+
ref={ref}
|
|
17
|
+
className={cn('fixed inset-0 z-50 bg-black/80', className)}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
AlertDialogOverlay.displayName = 'AlertDialogOverlay';
|
|
23
|
+
|
|
24
|
+
const AlertDialogContent = React.forwardRef<
|
|
25
|
+
React.ComponentRef<typeof AlertDialogPrimitive.Content>,
|
|
26
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
|
27
|
+
>(function AlertDialogContent({ className, children, ...props }, ref) {
|
|
28
|
+
return (
|
|
29
|
+
<AlertDialogPortal>
|
|
30
|
+
<AlertDialogOverlay />
|
|
31
|
+
<AlertDialogPrimitive.Content
|
|
32
|
+
ref={ref}
|
|
33
|
+
className={cn(
|
|
34
|
+
'fixed left-1/2 top-1/2 z-50 w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 rounded-lg border border-border bg-background p-6 shadow-lg',
|
|
35
|
+
className,
|
|
36
|
+
)}
|
|
37
|
+
{...props}
|
|
38
|
+
>
|
|
39
|
+
{children}
|
|
40
|
+
</AlertDialogPrimitive.Content>
|
|
41
|
+
</AlertDialogPortal>
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
AlertDialogContent.displayName = 'AlertDialogContent';
|
|
45
|
+
|
|
46
|
+
function AlertDialogHeader({ className, ...props }: React.ComponentPropsWithoutRef<typeof View>) {
|
|
47
|
+
return <View className={cn('flex flex-col gap-2', className)} {...props} />;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function AlertDialogFooter({ className, ...props }: React.ComponentPropsWithoutRef<typeof View>) {
|
|
51
|
+
return <View className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-2', className)} {...props} />;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const AlertDialogTitle = React.forwardRef<
|
|
55
|
+
React.ComponentRef<typeof AlertDialogPrimitive.Title>,
|
|
56
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
|
57
|
+
>(function AlertDialogTitle({ className, ...props }, ref) {
|
|
58
|
+
return (
|
|
59
|
+
<TextClassContext.Provider value="text-lg font-semibold text-foreground">
|
|
60
|
+
<AlertDialogPrimitive.Title ref={ref} className={cn('text-lg font-semibold text-foreground', className)} {...props} />
|
|
61
|
+
</TextClassContext.Provider>
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
AlertDialogTitle.displayName = 'AlertDialogTitle';
|
|
65
|
+
|
|
66
|
+
const AlertDialogDescription = React.forwardRef<
|
|
67
|
+
React.ComponentRef<typeof AlertDialogPrimitive.Description>,
|
|
68
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
|
69
|
+
>(function AlertDialogDescription({ className, ...props }, ref) {
|
|
70
|
+
return (
|
|
71
|
+
<AlertDialogPrimitive.Description ref={ref} className={cn('text-sm text-muted-foreground', className)} {...props} />
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
AlertDialogDescription.displayName = 'AlertDialogDescription';
|
|
75
|
+
|
|
76
|
+
const AlertDialogAction = AlertDialogPrimitive.Action;
|
|
77
|
+
const AlertDialogCancel = AlertDialogPrimitive.Cancel;
|
|
78
|
+
|
|
79
|
+
export {
|
|
80
|
+
AlertDialog,
|
|
81
|
+
AlertDialogTrigger,
|
|
82
|
+
AlertDialogPortal,
|
|
83
|
+
AlertDialogOverlay,
|
|
84
|
+
AlertDialogContent,
|
|
85
|
+
AlertDialogHeader,
|
|
86
|
+
AlertDialogFooter,
|
|
87
|
+
AlertDialogTitle,
|
|
88
|
+
AlertDialogDescription,
|
|
89
|
+
AlertDialogAction,
|
|
90
|
+
AlertDialogCancel,
|
|
91
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Image, View, Text, type ViewProps } from 'react-native';
|
|
3
|
+
import { cn } from '@tallyui/theme';
|
|
4
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
5
|
+
|
|
6
|
+
const avatarVariants = cva('relative overflow-hidden rounded-full', {
|
|
7
|
+
variants: {
|
|
8
|
+
size: {
|
|
9
|
+
sm: 'h-8 w-8',
|
|
10
|
+
md: 'h-10 w-10',
|
|
11
|
+
lg: 'h-12 w-12',
|
|
12
|
+
xl: 'h-16 w-16',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
defaultVariants: {
|
|
16
|
+
size: 'md',
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
type AvatarProps = ViewProps & VariantProps<typeof avatarVariants> & {
|
|
21
|
+
src?: string;
|
|
22
|
+
alt?: string;
|
|
23
|
+
fallback?: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function Avatar({ className, size, src, alt, fallback, ...props }: AvatarProps) {
|
|
27
|
+
const [hasError, setHasError] = React.useState(false);
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<View className={cn(avatarVariants({ size }), className)} {...props}>
|
|
31
|
+
{src && !hasError ? (
|
|
32
|
+
<Image
|
|
33
|
+
source={{ uri: src }}
|
|
34
|
+
accessibilityLabel={alt}
|
|
35
|
+
onError={() => setHasError(true)}
|
|
36
|
+
className="h-full w-full"
|
|
37
|
+
/>
|
|
38
|
+
) : (
|
|
39
|
+
<View className="flex h-full w-full items-center justify-center bg-muted">
|
|
40
|
+
<Text className="text-sm font-medium text-muted-foreground">
|
|
41
|
+
{fallback ?? alt?.charAt(0)?.toUpperCase() ?? '?'}
|
|
42
|
+
</Text>
|
|
43
|
+
</View>
|
|
44
|
+
)}
|
|
45
|
+
</View>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { Avatar, avatarVariants };
|
|
50
|
+
export type { AvatarProps };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Text, View, type ViewProps } from 'react-native';
|
|
3
|
+
import { cn } from '@tallyui/theme';
|
|
4
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
5
|
+
|
|
6
|
+
const badgeVariants = cva(
|
|
7
|
+
'inline-flex items-center rounded-full border px-2.5 py-0.5',
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: 'border-transparent bg-primary',
|
|
12
|
+
secondary: 'border-transparent bg-secondary',
|
|
13
|
+
destructive: 'border-transparent bg-destructive',
|
|
14
|
+
outline: 'border-border',
|
|
15
|
+
success: 'border-transparent bg-success',
|
|
16
|
+
warning: 'border-transparent bg-warning',
|
|
17
|
+
info: 'border-transparent bg-info',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
variant: 'default',
|
|
22
|
+
},
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const badgeTextVariants = cva('text-xs font-semibold', {
|
|
27
|
+
variants: {
|
|
28
|
+
variant: {
|
|
29
|
+
default: 'text-primary-foreground',
|
|
30
|
+
secondary: 'text-secondary-foreground',
|
|
31
|
+
destructive: 'text-destructive-foreground',
|
|
32
|
+
outline: 'text-foreground',
|
|
33
|
+
success: 'text-success-foreground',
|
|
34
|
+
warning: 'text-warning-foreground',
|
|
35
|
+
info: 'text-info-foreground',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
defaultVariants: {
|
|
39
|
+
variant: 'default',
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
type BadgeProps = ViewProps & VariantProps<typeof badgeVariants> & {
|
|
44
|
+
label?: string;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
function Badge({ className, variant, label, children, ...props }: BadgeProps) {
|
|
48
|
+
return (
|
|
49
|
+
<View className={cn(badgeVariants({ variant }), className)} {...props}>
|
|
50
|
+
{label ? (
|
|
51
|
+
<Text className={badgeTextVariants({ variant })}>{label}</Text>
|
|
52
|
+
) : (
|
|
53
|
+
children
|
|
54
|
+
)}
|
|
55
|
+
</View>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { Badge, badgeVariants, badgeTextVariants };
|
|
60
|
+
export type { BadgeProps };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Pressable, type PressableProps } from 'react-native';
|
|
3
|
+
import { TextClassContext, Slot } from '@tallyui/primitives';
|
|
4
|
+
import { cn } from '@tallyui/theme';
|
|
5
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
6
|
+
|
|
7
|
+
const buttonVariants = cva(
|
|
8
|
+
'inline-flex flex-row items-center justify-center gap-2 rounded-md web:ring-offset-background web:transition-colors web:focus-visible:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring web:focus-visible:ring-offset-2',
|
|
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
|
+
link: 'web:underline-offset-4 web:hover:underline',
|
|
18
|
+
},
|
|
19
|
+
size: {
|
|
20
|
+
default: 'h-10 px-4 py-2',
|
|
21
|
+
sm: 'h-9 rounded-md px-3',
|
|
22
|
+
lg: 'h-11 rounded-md px-8',
|
|
23
|
+
icon: 'h-10 w-10',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
defaultVariants: {
|
|
27
|
+
variant: 'default',
|
|
28
|
+
size: 'default',
|
|
29
|
+
},
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const buttonTextVariants = cva(
|
|
34
|
+
'web:whitespace-nowrap text-sm font-medium',
|
|
35
|
+
{
|
|
36
|
+
variants: {
|
|
37
|
+
variant: {
|
|
38
|
+
default: 'text-primary-foreground',
|
|
39
|
+
destructive: 'text-destructive-foreground',
|
|
40
|
+
outline: 'text-foreground',
|
|
41
|
+
secondary: 'text-secondary-foreground',
|
|
42
|
+
ghost: 'text-foreground',
|
|
43
|
+
link: 'text-primary',
|
|
44
|
+
},
|
|
45
|
+
size: {
|
|
46
|
+
default: '',
|
|
47
|
+
sm: '',
|
|
48
|
+
lg: 'text-base',
|
|
49
|
+
icon: '',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
defaultVariants: {
|
|
53
|
+
variant: 'default',
|
|
54
|
+
size: 'default',
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
type ButtonProps = PressableProps & VariantProps<typeof buttonVariants> & {
|
|
60
|
+
asChild?: boolean;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const Button = React.forwardRef<React.ComponentRef<typeof Pressable>, ButtonProps>(
|
|
64
|
+
function Button({ className, variant, size, asChild = false, disabled, ...props }, ref) {
|
|
65
|
+
const Component = asChild ? Slot : Pressable;
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<TextClassContext.Provider
|
|
69
|
+
value={buttonTextVariants({ variant, size })}
|
|
70
|
+
>
|
|
71
|
+
<Component
|
|
72
|
+
ref={ref}
|
|
73
|
+
role="button"
|
|
74
|
+
disabled={disabled}
|
|
75
|
+
className={cn(
|
|
76
|
+
buttonVariants({ variant, size }),
|
|
77
|
+
disabled && 'opacity-50 web:pointer-events-none',
|
|
78
|
+
className,
|
|
79
|
+
)}
|
|
80
|
+
{...props}
|
|
81
|
+
/>
|
|
82
|
+
</TextClassContext.Provider>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
Button.displayName = 'Button';
|
|
88
|
+
|
|
89
|
+
export { Button, buttonVariants, buttonTextVariants };
|
|
90
|
+
export type { ButtonProps };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Text, View, type TextProps, type ViewProps } from 'react-native';
|
|
3
|
+
import { TextClassContext } from '@tallyui/primitives';
|
|
4
|
+
import { cn } from '@tallyui/theme';
|
|
5
|
+
|
|
6
|
+
const Card = React.forwardRef<View, ViewProps>(function Card({ className, ...props }, ref) {
|
|
7
|
+
return (
|
|
8
|
+
<View
|
|
9
|
+
ref={ref}
|
|
10
|
+
className={cn('rounded-lg border border-border bg-card shadow-sm', className)}
|
|
11
|
+
{...props}
|
|
12
|
+
/>
|
|
13
|
+
);
|
|
14
|
+
});
|
|
15
|
+
Card.displayName = 'Card';
|
|
16
|
+
|
|
17
|
+
const CardHeader = React.forwardRef<View, ViewProps>(function CardHeader({ className, ...props }, ref) {
|
|
18
|
+
return (
|
|
19
|
+
<View ref={ref} className={cn('flex flex-col gap-1.5 p-6', className)} {...props} />
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
CardHeader.displayName = 'CardHeader';
|
|
23
|
+
|
|
24
|
+
const CardTitle = React.forwardRef<Text, TextProps>(function CardTitle({ className, ...props }, ref) {
|
|
25
|
+
return (
|
|
26
|
+
<Text
|
|
27
|
+
ref={ref}
|
|
28
|
+
role="heading"
|
|
29
|
+
aria-level={3}
|
|
30
|
+
className={cn('text-2xl font-semibold leading-none text-card-foreground', className)}
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
CardTitle.displayName = 'CardTitle';
|
|
36
|
+
|
|
37
|
+
const CardDescription = React.forwardRef<Text, TextProps>(function CardDescription({ className, ...props }, ref) {
|
|
38
|
+
return (
|
|
39
|
+
<Text ref={ref} className={cn('text-sm text-muted-foreground', className)} {...props} />
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
CardDescription.displayName = 'CardDescription';
|
|
43
|
+
|
|
44
|
+
const CardContent = React.forwardRef<View, ViewProps>(function CardContent({ className, ...props }, ref) {
|
|
45
|
+
return (
|
|
46
|
+
<TextClassContext.Provider value="text-card-foreground">
|
|
47
|
+
<View ref={ref} className={cn('p-6 pt-0', className)} {...props} />
|
|
48
|
+
</TextClassContext.Provider>
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
CardContent.displayName = 'CardContent';
|
|
52
|
+
|
|
53
|
+
const CardFooter = React.forwardRef<View, ViewProps>(function CardFooter({ className, ...props }, ref) {
|
|
54
|
+
return (
|
|
55
|
+
<View ref={ref} className={cn('flex flex-row items-center p-6 pt-0', className)} {...props} />
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
CardFooter.displayName = 'CardFooter';
|
|
59
|
+
|
|
60
|
+
export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { View, Text } from 'react-native';
|
|
3
|
+
import { Checkbox as CheckboxPrimitive } from '@tallyui/primitives';
|
|
4
|
+
import { cn } from '@tallyui/theme';
|
|
5
|
+
|
|
6
|
+
const Checkbox = React.forwardRef<
|
|
7
|
+
React.ComponentRef<typeof CheckboxPrimitive.Root>,
|
|
8
|
+
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
|
|
9
|
+
>(function Checkbox({ className, ...props }, ref) {
|
|
10
|
+
return (
|
|
11
|
+
<CheckboxPrimitive.Root
|
|
12
|
+
ref={ref}
|
|
13
|
+
className={cn(
|
|
14
|
+
'h-4 w-4 shrink-0 rounded-sm border border-primary 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',
|
|
15
|
+
props.checked && 'bg-primary',
|
|
16
|
+
props.disabled && 'web:cursor-not-allowed opacity-50',
|
|
17
|
+
className,
|
|
18
|
+
)}
|
|
19
|
+
{...props}
|
|
20
|
+
>
|
|
21
|
+
<CheckboxPrimitive.Indicator className="flex items-center justify-center text-current">
|
|
22
|
+
<Text className="text-xs text-primary-foreground">{'\u2713'}</Text>
|
|
23
|
+
</CheckboxPrimitive.Indicator>
|
|
24
|
+
</CheckboxPrimitive.Root>
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
Checkbox.displayName = 'Checkbox';
|
|
28
|
+
|
|
29
|
+
export { Checkbox };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Collapsible as CollapsiblePrimitive, TextClassContext } from '@tallyui/primitives';
|
|
3
|
+
import { cn } from '@tallyui/theme';
|
|
4
|
+
|
|
5
|
+
const Collapsible = CollapsiblePrimitive.Root;
|
|
6
|
+
const CollapsibleTrigger = CollapsiblePrimitive.Trigger;
|
|
7
|
+
|
|
8
|
+
const CollapsibleContent = React.forwardRef<
|
|
9
|
+
React.ComponentRef<typeof CollapsiblePrimitive.Content>,
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.Content>
|
|
11
|
+
>(function CollapsibleContent({ className, ...props }, ref) {
|
|
12
|
+
return (
|
|
13
|
+
<TextClassContext.Provider value="text-sm">
|
|
14
|
+
<CollapsiblePrimitive.Content
|
|
15
|
+
ref={ref}
|
|
16
|
+
className={cn('overflow-hidden web:transition-all', className)}
|
|
17
|
+
{...props}
|
|
18
|
+
/>
|
|
19
|
+
</TextClassContext.Provider>
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
CollapsibleContent.displayName = 'CollapsibleContent';
|
|
23
|
+
|
|
24
|
+
export { Collapsible, CollapsibleTrigger, CollapsibleContent };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { View, TextInput, Pressable, Text, ScrollView } from 'react-native';
|
|
3
|
+
import { Combobox as ComboboxPrimitive, TextClassContext } from '@tallyui/primitives';
|
|
4
|
+
import { cn } from '@tallyui/theme';
|
|
5
|
+
|
|
6
|
+
const Combobox = ComboboxPrimitive.Root;
|
|
7
|
+
|
|
8
|
+
const ComboboxTrigger = React.forwardRef<
|
|
9
|
+
React.ComponentRef<typeof ComboboxPrimitive.Trigger>,
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.Trigger>
|
|
11
|
+
>(function ComboboxTrigger({ className, children, ...props }, ref) {
|
|
12
|
+
return (
|
|
13
|
+
<ComboboxPrimitive.Trigger
|
|
14
|
+
ref={ref}
|
|
15
|
+
className={cn(
|
|
16
|
+
'flex h-10 w-full flex-row items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm web:ring-offset-background web:focus:outline-none web:focus:ring-2 web:focus:ring-ring web:focus:ring-offset-2',
|
|
17
|
+
className,
|
|
18
|
+
)}
|
|
19
|
+
{...props}
|
|
20
|
+
>
|
|
21
|
+
{children}
|
|
22
|
+
</ComboboxPrimitive.Trigger>
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
ComboboxTrigger.displayName = 'ComboboxTrigger';
|
|
26
|
+
|
|
27
|
+
const ComboboxInput = React.forwardRef<
|
|
28
|
+
React.ComponentRef<typeof ComboboxPrimitive.Input>,
|
|
29
|
+
React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.Input>
|
|
30
|
+
>(function ComboboxInput({ className, ...props }, ref) {
|
|
31
|
+
return (
|
|
32
|
+
<ComboboxPrimitive.Input
|
|
33
|
+
ref={ref}
|
|
34
|
+
className={cn(
|
|
35
|
+
'flex-1 text-sm text-foreground web:outline-none placeholder:text-muted-foreground',
|
|
36
|
+
className,
|
|
37
|
+
)}
|
|
38
|
+
{...props}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
ComboboxInput.displayName = 'ComboboxInput';
|
|
43
|
+
|
|
44
|
+
const ComboboxContent = React.forwardRef<
|
|
45
|
+
React.ComponentRef<typeof ComboboxPrimitive.Content>,
|
|
46
|
+
React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.Content>
|
|
47
|
+
>(function ComboboxContent({ className, children, ...props }, ref) {
|
|
48
|
+
return (
|
|
49
|
+
<ComboboxPrimitive.Portal>
|
|
50
|
+
<TextClassContext.Provider value="text-popover-foreground">
|
|
51
|
+
<ComboboxPrimitive.Content
|
|
52
|
+
ref={ref}
|
|
53
|
+
className={cn(
|
|
54
|
+
'z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md',
|
|
55
|
+
className,
|
|
56
|
+
)}
|
|
57
|
+
{...props}
|
|
58
|
+
>
|
|
59
|
+
{children}
|
|
60
|
+
</ComboboxPrimitive.Content>
|
|
61
|
+
</TextClassContext.Provider>
|
|
62
|
+
</ComboboxPrimitive.Portal>
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
ComboboxContent.displayName = 'ComboboxContent';
|
|
66
|
+
|
|
67
|
+
const ComboboxItem = React.forwardRef<
|
|
68
|
+
React.ComponentRef<typeof ComboboxPrimitive.Item>,
|
|
69
|
+
React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.Item>
|
|
70
|
+
>(function ComboboxItem({ className, ...props }, ref) {
|
|
71
|
+
return (
|
|
72
|
+
<ComboboxPrimitive.Item
|
|
73
|
+
ref={ref}
|
|
74
|
+
className={cn(
|
|
75
|
+
'relative flex cursor-default select-none flex-row items-center rounded-sm px-2 py-1.5 text-sm outline-none web:focus:bg-accent web:focus:text-accent-foreground',
|
|
76
|
+
className,
|
|
77
|
+
)}
|
|
78
|
+
{...props}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
ComboboxItem.displayName = 'ComboboxItem';
|
|
83
|
+
|
|
84
|
+
const ComboboxEmpty = React.forwardRef<
|
|
85
|
+
View,
|
|
86
|
+
React.ComponentPropsWithoutRef<typeof View>
|
|
87
|
+
>(function ComboboxEmpty({ className, ...props }, ref) {
|
|
88
|
+
return (
|
|
89
|
+
<View ref={ref} className={cn('py-6 text-center', className)} {...props}>
|
|
90
|
+
<Text className="text-sm text-muted-foreground">No results found.</Text>
|
|
91
|
+
</View>
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
ComboboxEmpty.displayName = 'ComboboxEmpty';
|
|
95
|
+
|
|
96
|
+
export {
|
|
97
|
+
Combobox, ComboboxTrigger, ComboboxInput, ComboboxContent, ComboboxItem, ComboboxEmpty,
|
|
98
|
+
};
|